OSDN Git Service

[RTT2] Add a generic Responder mode configuration
authorEtan Cohen <etancohen@google.com>
Mon, 20 Nov 2017 23:44:50 +0000 (15:44 -0800)
committerEtan Cohen <etancohen@google.com>
Thu, 30 Nov 2017 20:21:04 +0000 (20:21 +0000)
Add a generic Responder mode which is the common configuration for
any peer (which any peer configuration can be translated to).

Bug: 65014962
Test: unit tests and integration tests
Change-Id: If2f6abc217508792d319d7d5e54aa3f7385b0ec5

wifi/java/android/net/wifi/rtt/RangingRequest.java
wifi/java/android/net/wifi/rtt/ResponderConfig.aidl [new file with mode: 0644]
wifi/java/android/net/wifi/rtt/ResponderConfig.java [new file with mode: 0644]

index a396281..7d74a72 100644 (file)
@@ -16,6 +16,7 @@
 
 package android.net.wifi.rtt;
 
+import android.annotation.NonNull;
 import android.net.wifi.ScanResult;
 import android.net.wifi.aware.AttachCallback;
 import android.net.wifi.aware.DiscoverySessionCallback;
@@ -25,14 +26,9 @@ import android.net.wifi.aware.WifiAwareManager;
 import android.os.Handler;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.text.TextUtils;
-
-import libcore.util.HexEncoding;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
-import java.util.Objects;
 import java.util.StringJoiner;
 
 /**
@@ -63,10 +59,10 @@ public final class RangingRequest implements Parcelable {
     }
 
     /** @hide */
-    public final List<RttPeer> mRttPeers;
+    public final List<ResponderConfig> mRttPeers;
 
     /** @hide */
-    private RangingRequest(List<RttPeer> rttPeers) {
+    private RangingRequest(List<ResponderConfig> rttPeers) {
         mRttPeers = rttPeers;
     }
 
@@ -95,9 +91,9 @@ public final class RangingRequest implements Parcelable {
     /** @hide */
     @Override
     public String toString() {
-        StringJoiner sj = new StringJoiner(", ", "RangingRequest: mRttPeers=[", ",");
-        for (RttPeer rp : mRttPeers) {
-            sj.add(rp.toString());
+        StringJoiner sj = new StringJoiner(", ", "RangingRequest: mRttPeers=[", "]");
+        for (ResponderConfig rc : mRttPeers) {
+            sj.add(rc.toString());
         }
         return sj.toString();
     }
@@ -109,26 +105,9 @@ public final class RangingRequest implements Parcelable {
                     "Ranging to too many peers requested. Use getMaxPeers() API to get limit.");
         }
 
-        for (RttPeer peer: mRttPeers) {
-            if (peer instanceof RttPeerAp) {
-                RttPeerAp apPeer = (RttPeerAp) peer;
-                if (apPeer.scanResult == null || apPeer.scanResult.BSSID == null) {
-                    throw new IllegalArgumentException("Invalid AP peer specification");
-                }
-            } else if (peer instanceof RttPeerAware) {
-                if (!awareSupported) {
-                    throw new IllegalArgumentException(
-                            "Request contains Aware peers - but Aware isn't supported on this "
-                                    + "device");
-                }
-
-                RttPeerAware awarePeer = (RttPeerAware) peer;
-                if (awarePeer.peerMacAddress == null && awarePeer.peerHandle == null) {
-                    throw new IllegalArgumentException("Invalid Aware peer specification");
-                }
-            } else {
-                throw new IllegalArgumentException(
-                        "Request contains unknown peer specification types");
+        for (ResponderConfig peer: mRttPeers) {
+            if (!peer.isValid(awareSupported)) {
+                throw new IllegalArgumentException("Invalid Responder specification");
             }
         }
     }
@@ -137,35 +116,34 @@ public final class RangingRequest implements Parcelable {
      * Builder class used to construct {@link RangingRequest} objects.
      */
     public static final class Builder {
-        private List<RttPeer> mRttPeers = new ArrayList<>();
+        private List<ResponderConfig> mRttPeers = new ArrayList<>();
 
         /**
          * Add the device specified by the {@link ScanResult} to the list of devices with
-         * which to measure range. The total number of results added to a request cannot exceed the
+         * which to measure range. The total number of peers added to a request cannot exceed the
          * limit specified by {@link #getMaxPeers()}.
          *
          * @param apInfo Information of an Access Point (AP) obtained in a Scan Result.
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
-        public Builder addAccessPoint(ScanResult apInfo) {
+        public Builder addAccessPoint(@NonNull ScanResult apInfo) {
             if (apInfo == null) {
                 throw new IllegalArgumentException("Null ScanResult!");
             }
-            mRttPeers.add(new RttPeerAp(apInfo));
-            return this;
+            return addResponder(ResponderConfig.fromScanResult(apInfo));
         }
 
         /**
          * Add the devices specified by the {@link ScanResult}s to the list of devices with
-         * which to measure range. The total number of results added to a request cannot exceed the
+         * which to measure range. The total number of peers added to a request cannot exceed the
          * limit specified by {@link #getMaxPeers()}.
          *
          * @param apInfos Information of an Access Points (APs) obtained in a Scan Result.
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
-        public Builder addAccessPoints(List<ScanResult> apInfos) {
+        public Builder addAccessPoints(@NonNull List<ScanResult> apInfos) {
             if (apInfos == null) {
                 throw new IllegalArgumentException("Null list of ScanResults!");
             }
@@ -190,9 +168,12 @@ public final class RangingRequest implements Parcelable {
          * @param peerMacAddress The MAC address of the Wi-Fi Aware peer.
          * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
          */
-        public Builder addWifiAwarePeer(byte[] peerMacAddress) {
-            mRttPeers.add(new RttPeerAware(peerMacAddress));
-            return this;
+        public Builder addWifiAwarePeer(@NonNull byte[] peerMacAddress) {
+            if (peerMacAddress == null) {
+                throw new IllegalArgumentException("Null peer MAC address");
+            }
+            return addResponder(
+                    ResponderConfig.fromWifiAwarePeerMacAddressWithDefaults(peerMacAddress));
         }
 
         /**
@@ -208,8 +189,30 @@ public final class RangingRequest implements Parcelable {
          * @param peerHandle The peer handler of the peer Wi-Fi Aware device.
          * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
          */
-        public Builder addWifiAwarePeer(PeerHandle peerHandle) {
-            mRttPeers.add(new RttPeerAware(peerHandle));
+        public Builder addWifiAwarePeer(@NonNull PeerHandle peerHandle) {
+            if (peerHandle == null) {
+                throw new IllegalArgumentException("Null peer handler (identifier)");
+            }
+
+            return addResponder(ResponderConfig.fromWifiAwarePeerHandleWithDefaults(peerHandle));
+        }
+
+        /*
+         * Add the Responder device specified by the {@link ResponderConfig} to the list of devices
+         * with which to measure range. The total number of peers added to the request cannot exceed
+         * the limit specified by {@link #getMaxPeers()}.
+         *
+         * @param responder Information on the RTT Responder.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         *
+         * @hide (SystemApi)
+         */
+        public Builder addResponder(@NonNull ResponderConfig responder) {
+            if (responder == null) {
+                throw new IllegalArgumentException("Null Responder!");
+            }
+
+            mRttPeers.add(responder);
             return this;
         }
 
@@ -241,152 +244,4 @@ public final class RangingRequest implements Parcelable {
     public int hashCode() {
         return mRttPeers.hashCode();
     }
-
-    /** @hide */
-    public interface RttPeer {
-        // empty (marker interface)
-    }
-
-    /** @hide */
-    public static class RttPeerAp implements RttPeer, Parcelable {
-        public final ScanResult scanResult;
-
-        public RttPeerAp(ScanResult scanResult) {
-            this.scanResult = scanResult;
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            scanResult.writeToParcel(dest, flags);
-        }
-
-        public static final Creator<RttPeerAp> CREATOR = new Creator<RttPeerAp>() {
-            @Override
-            public RttPeerAp[] newArray(int size) {
-                return new RttPeerAp[size];
-            }
-
-            @Override
-            public RttPeerAp createFromParcel(Parcel in) {
-                return new RttPeerAp(ScanResult.CREATOR.createFromParcel(in));
-            }
-        };
-
-        @Override
-        public String toString() {
-            return new StringBuilder("RttPeerAp: scanResult=").append(
-                    scanResult.toString()).toString();
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-
-            if (!(o instanceof RttPeerAp)) {
-                return false;
-            }
-
-            RttPeerAp lhs = (RttPeerAp) o;
-
-            // Note: the only thing which matters for the request identity is the BSSID of the AP
-            return TextUtils.equals(scanResult.BSSID, lhs.scanResult.BSSID);
-        }
-
-        @Override
-        public int hashCode() {
-            return scanResult.hashCode();
-        }
-    }
-
-    /** @hide */
-    public static class RttPeerAware implements RttPeer, Parcelable {
-        public PeerHandle peerHandle;
-        public byte[] peerMacAddress;
-
-        public RttPeerAware(PeerHandle peerHandle) {
-            if (peerHandle == null) {
-                throw new IllegalArgumentException("Null peerHandle");
-            }
-            this.peerHandle = peerHandle;
-            peerMacAddress = null;
-        }
-
-        public RttPeerAware(byte[] peerMacAddress) {
-            if (peerMacAddress == null) {
-                throw new IllegalArgumentException("Null peerMacAddress");
-            }
-
-            this.peerMacAddress = peerMacAddress;
-            peerHandle = null;
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            if (peerHandle == null) {
-                dest.writeBoolean(false);
-                dest.writeByteArray(peerMacAddress);
-            } else {
-                dest.writeBoolean(true);
-                dest.writeInt(peerHandle.peerId);
-            }
-        }
-
-        public static final Creator<RttPeerAware> CREATOR = new Creator<RttPeerAware>() {
-            @Override
-            public RttPeerAware[] newArray(int size) {
-                return new RttPeerAware[size];
-            }
-
-            @Override
-            public RttPeerAware createFromParcel(Parcel in) {
-                boolean peerHandleAvail = in.readBoolean();
-                if (peerHandleAvail) {
-                    return new RttPeerAware(new PeerHandle(in.readInt()));
-                } else {
-                    return new RttPeerAware(in.createByteArray());
-                }
-            }
-        };
-
-        @Override
-        public String toString() {
-            return new StringBuilder("RttPeerAware: peerHandle=").append(
-                    peerHandle == null ? "<null>" : Integer.toString(peerHandle.peerId)).append(
-                    ", peerMacAddress=").append(peerMacAddress == null ? "<null>"
-                    : new String(HexEncoding.encode(peerMacAddress))).toString();
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-
-            if (!(o instanceof RttPeerAware)) {
-                return false;
-            }
-
-            RttPeerAware lhs = (RttPeerAware) o;
-
-            return Objects.equals(peerHandle, lhs.peerHandle) && Arrays.equals(peerMacAddress,
-                    lhs.peerMacAddress);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(peerHandle.peerId, peerMacAddress);
-        }
-    }
 }
diff --git a/wifi/java/android/net/wifi/rtt/ResponderConfig.aidl b/wifi/java/android/net/wifi/rtt/ResponderConfig.aidl
new file mode 100644 (file)
index 0000000..fd3988a
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.rtt;
+
+parcelable ResponderConfig;
diff --git a/wifi/java/android/net/wifi/rtt/ResponderConfig.java b/wifi/java/android/net/wifi/rtt/ResponderConfig.java
new file mode 100644 (file)
index 0000000..3d96bfd
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.rtt;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.net.MacAddress;
+import android.net.wifi.ScanResult;
+import android.net.wifi.aware.PeerHandle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import libcore.util.HexEncoding;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Defines the configuration of an IEEE 802.11mc Responder. The Responder may be an Access Point
+ * (AP), a Wi-Fi Aware device, or a manually configured Responder.
+ * <p>
+ * A Responder configuration may be constructed from a {@link ScanResult} or manually (with the
+ * data obtained out-of-band from a peer).
+ *
+ * @hide (@SystemApi)
+ */
+public class ResponderConfig implements Parcelable {
+    /** @hide */
+    @IntDef({RESPONDER_AP, RESPONDER_STA, RESPONDER_P2P_GO, RESPONDER_P2P_CLIENT, RESPONDER_AWARE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ResponderType {
+    }
+
+    /**
+     * Responder is an AP.
+     */
+    public static final int RESPONDER_AP = 0;
+    /**
+     * Responder is a STA.
+     */
+    public static final int RESPONDER_STA = 1;
+    /**
+     * Responder is a Wi-Fi Direct Group Owner (GO).
+     */
+    public static final int RESPONDER_P2P_GO = 2;
+    /**
+     * Responder is a Wi-Fi Direct Group Client.
+     */
+    public static final int RESPONDER_P2P_CLIENT = 3;
+    /**
+     * Responder is a Wi-Fi Aware device.
+     */
+    public static final int RESPONDER_AWARE = 4;
+
+
+    /** @hide */
+    @IntDef({
+            CHANNEL_WIDTH_20MHZ, CHANNEL_WIDTH_40MHZ, CHANNEL_WIDTH_80MHZ, CHANNEL_WIDTH_160MHZ,
+            CHANNEL_WIDTH_80MHZ_PLUS_MHZ})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ChannelWidth {
+    }
+
+    /**
+     * Channel bandwidth is 20 MHZ
+     */
+    public static final int CHANNEL_WIDTH_20MHZ = 0;
+    /**
+     * Channel bandwidth is 40 MHZ
+     */
+    public static final int CHANNEL_WIDTH_40MHZ = 1;
+    /**
+     * Channel bandwidth is 80 MHZ
+     */
+    public static final int CHANNEL_WIDTH_80MHZ = 2;
+    /**
+     * Channel bandwidth is 160 MHZ
+     */
+    public static final int CHANNEL_WIDTH_160MHZ = 3;
+    /**
+     * Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ
+     */
+    public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4;
+
+    /** @hide */
+    @IntDef({PREAMBLE_LEGACY, PREAMBLE_HT, PREAMBLE_VHT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PreambleType {
+    }
+
+    /**
+     * Preamble type: Legacy.
+     */
+    public static final int PREAMBLE_LEGACY = 0;
+
+    /**
+     * Preamble type: HT.
+     */
+    public static final int PREAMBLE_HT = 1;
+
+    /**
+     * Preamble type: VHT.
+     */
+    public static final int PREAMBLE_VHT = 2;
+
+
+    /**
+     * The MAC address of the Responder. Will be null if a Wi-Fi Aware peer identifier (the
+     * peerHandle field) ise used to identify the Responder.
+     * TODO: convert to MacAddress
+     */
+    public byte[] macAddress;
+
+    /**
+     * The peer identifier of a Wi-Fi Aware Responder. Will be null if a MAC Address (the macAddress
+     * field) is used to identify the Responder.
+     */
+    public final PeerHandle peerHandle;
+
+    /**
+     * The device type of the Responder.
+     */
+    public final int responderType;
+
+    /**
+     * Indicates whether the Responder device supports IEEE 802.11mc.
+     */
+    public final boolean supports80211mc;
+
+    /**
+     * Responder channel bandwidth, specified using {@link ChannelWidth}.
+     */
+    public final int channelWidth;
+
+    /**
+     * The primary 20 MHz frequency (in MHz) of the channel of the Responder.
+     */
+    public final int frequency;
+
+    /**
+     * Not used if the {@link #channelWidth} is 20 MHz. If the Responder uses 40, 80 or 160 MHz,
+     * this is the center frequency (in MHz), if the Responder uses 80 + 80 MHz, this is the
+     * center frequency of the first segment (in MHz).
+     */
+    public final int centerFreq0;
+
+    /**
+     * Only used if the {@link #channelWidth} is 80 + 80 MHz. If the Responder uses 80 + 80 MHz,
+     * this is the center frequency of the second segment (in MHz).
+     */
+    public final int centerFreq1;
+
+    /**
+     * The preamble used by the Responder, specified using {@link PreambleType}.
+     */
+    public final int preamble;
+
+    /**
+     * Constructs Responder configuration.
+     *
+     * @param macAddress      The MAC address of the Responder.
+     * @param responderType   The type of the responder device, specified using
+     *                        {@link ResponderType}.
+     * @param supports80211mc Indicates whether the responder supports IEEE 802.11mc.
+     * @param channelWidth    Responder channel bandwidth, specified using {@link ChannelWidth}.
+     * @param frequency       The primary 20 MHz frequency (in MHz) of the channel of the Responder.
+     * @param centerFreq0     Not used if the {@code channelWidth} is 20 MHz. If the Responder uses
+     *                        40, 80 or 160 MHz, this is the center frequency (in MHz), if the
+     *                        Responder uses 80 + 80 MHz, this is the center frequency of the first
+     *                        segment (in MHz).
+     * @param centerFreq1     Only used if the {@code channelWidth} is 80 + 80 MHz. If the
+     *                        Responder
+     *                        uses 80 + 80 MHz, this is the center frequency of the second segment
+     *                        (in
+     *                        MHz).
+     * @param preamble        The preamble used by the Responder, specified using
+     *                        {@link PreambleType}.
+     */
+    public ResponderConfig(@NonNull byte[] macAddress, @ResponderType int responderType,
+            boolean supports80211mc, @ChannelWidth int channelWidth, int frequency, int centerFreq0,
+            int centerFreq1, @PreambleType int preamble) {
+        this.macAddress = macAddress;
+        this.peerHandle = null;
+        this.responderType = responderType;
+        this.supports80211mc = supports80211mc;
+        this.channelWidth = channelWidth;
+        this.frequency = frequency;
+        this.centerFreq0 = centerFreq0;
+        this.centerFreq1 = centerFreq1;
+        this.preamble = preamble;
+    }
+
+    /**
+     * Constructs Responder configuration.
+     *
+     * @param peerHandle      The Wi-Fi Aware peer identifier of the Responder.
+     * @param responderType   The type of the responder device, specified using
+     *                        {@link ResponderType}.
+     * @param supports80211mc Indicates whether the responder supports IEEE 802.11mc.
+     * @param channelWidth    Responder channel bandwidth, specified using {@link ChannelWidth}.
+     * @param frequency       The primary 20 MHz frequency (in MHz) of the channel of the Responder.
+     * @param centerFreq0     Not used if the {@code channelWidth} is 20 MHz. If the Responder uses
+     *                        40, 80 or 160 MHz, this is the center frequency (in MHz), if the
+     *                        Responder uses 80 + 80 MHz, this is the center frequency of the first
+     *                        segment (in MHz).
+     * @param centerFreq1     Only used if the {@code channelWidth} is 80 + 80 MHz. If the
+     *                        Responder
+     *                        uses 80 + 80 MHz, this is the center frequency of the second segment
+     *                        (in
+     *                        MHz).
+     * @param preamble        The preamble used by the Responder, specified using
+     *                        {@link PreambleType}.
+     */
+    public ResponderConfig(@NonNull PeerHandle peerHandle, @ResponderType int responderType,
+            boolean supports80211mc, @ChannelWidth int channelWidth, int frequency, int centerFreq0,
+            int centerFreq1, @PreambleType int preamble) {
+        this.macAddress = null;
+        this.peerHandle = peerHandle;
+        this.responderType = responderType;
+        this.supports80211mc = supports80211mc;
+        this.channelWidth = channelWidth;
+        this.frequency = frequency;
+        this.centerFreq0 = centerFreq0;
+        this.centerFreq1 = centerFreq1;
+        this.preamble = preamble;
+    }
+
+    /**
+     * Creates a Responder configuration from a {@link ScanResult} corresponding to an Access
+     * Point (AP), which can be obtained from {@link android.net.wifi.WifiManager#getScanResults()}.
+     */
+    public static ResponderConfig fromScanResult(ScanResult scanResult) {
+        byte[] macAddress = new MacAddress(scanResult.BSSID).toByteArray();
+        int responderType = RESPONDER_AP;
+        boolean supports80211mc = scanResult.is80211mcResponder();
+        int channelWidth = translcateScanResultChannelWidth(scanResult.channelWidth);
+        int frequency = scanResult.frequency;
+        int centerFreq0 = scanResult.centerFreq0;
+        int centerFreq1 = scanResult.centerFreq1;
+
+        // TODO: b/68936111 - extract preamble info from IE
+        int preamble;
+        if (channelWidth == CHANNEL_WIDTH_80MHZ || channelWidth == CHANNEL_WIDTH_160MHZ) {
+            preamble = PREAMBLE_VHT;
+        } else {
+            preamble = PREAMBLE_HT;
+        }
+
+        return new ResponderConfig(macAddress, responderType, supports80211mc, channelWidth,
+                frequency, centerFreq0, centerFreq1, preamble);
+    }
+
+    /**
+     * Creates a Responder configuration from a MAC address corresponding to a Wi-Fi Aware
+     * Responder. The Responder parameters are set to defaults.
+     */
+    public static ResponderConfig fromWifiAwarePeerMacAddressWithDefaults(byte[] macAddress) {
+        // TODO b/67678464: determine "right" parameters or
+        return new ResponderConfig(macAddress, RESPONDER_AWARE, true, CHANNEL_WIDTH_80MHZ,
+                5200, 5210, 0, PREAMBLE_VHT);
+    }
+
+    /**
+     * Creates a Responder configuration from a {@link PeerHandle} corresponding to a Wi-Fi Aware
+     * Responder. The Responder parameters are set to defaults.
+     */
+    public static ResponderConfig fromWifiAwarePeerHandleWithDefaults(PeerHandle peerHandle) {
+        // TODO b/67678464: determine "right" parameters or
+        return new ResponderConfig(peerHandle, RESPONDER_AWARE, true, CHANNEL_WIDTH_80MHZ,
+                5200, 5210, 0, PREAMBLE_VHT);
+    }
+
+    /**
+     * Check whether the Responder configuration is valid.
+     *
+     * @return true if valid, false otherwise.
+     * @hide
+     */
+    public boolean isValid(boolean awareSupported) {
+        if (macAddress == null && peerHandle == null || macAddress != null && peerHandle != null) {
+            return false;
+        }
+        if (!awareSupported && responderType == RESPONDER_AWARE) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeByteArray(macAddress);
+        if (peerHandle == null) {
+            dest.writeInt(0);
+        } else {
+            dest.writeInt(1);
+            dest.writeInt(peerHandle.peerId);
+        }
+        dest.writeInt(responderType);
+        dest.writeInt(supports80211mc ? 1 : 0);
+        dest.writeInt(channelWidth);
+        dest.writeInt(frequency);
+        dest.writeInt(centerFreq0);
+        dest.writeInt(centerFreq1);
+        dest.writeInt(preamble);
+    }
+
+    public static final Creator<ResponderConfig> CREATOR = new Creator<ResponderConfig>() {
+        @Override
+        public ResponderConfig[] newArray(int size) {
+            return new ResponderConfig[size];
+        }
+
+        @Override
+        public ResponderConfig createFromParcel(Parcel in) {
+            byte[] macAddress = in.createByteArray();
+            int peerHandleFlag = in.readInt();
+            PeerHandle peerHandle = null;
+            if (peerHandleFlag == 1) {
+                peerHandle = new PeerHandle(in.readInt());
+            }
+            int responderType = in.readInt();
+            boolean supports80211mc = in.readInt() == 1;
+            int channelWidth = in.readInt();
+            int frequency = in.readInt();
+            int centerFreq0 = in.readInt();
+            int centerFreq1 = in.readInt();
+            int preamble = in.readInt();
+
+            if (peerHandle == null) {
+                return new ResponderConfig(macAddress, responderType, supports80211mc, channelWidth,
+                        frequency, centerFreq0, centerFreq1, preamble);
+            } else {
+                return new ResponderConfig(peerHandle, responderType, supports80211mc, channelWidth,
+                        frequency, centerFreq0, centerFreq1, preamble);
+            }
+        }
+    };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof ResponderConfig)) {
+            return false;
+        }
+
+        ResponderConfig lhs = (ResponderConfig) o;
+
+        return Arrays.equals(macAddress, lhs.macAddress) && Objects.equals(peerHandle,
+                lhs.peerHandle) && responderType == lhs.responderType
+                && supports80211mc == lhs.supports80211mc && channelWidth == lhs.channelWidth
+                && frequency == lhs.frequency && centerFreq0 == lhs.centerFreq0
+                && centerFreq1 == lhs.centerFreq1 && preamble == lhs.preamble;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(macAddress, peerHandle, responderType, supports80211mc, channelWidth,
+                frequency, centerFreq0, centerFreq1, preamble);
+    }
+
+    /** @hide */
+    @Override
+    public String toString() {
+        return new StringBuffer("ResponderConfig: macAddress=").append(
+                macAddress == null ? "<null>" : new String(HexEncoding.encode(macAddress))).append(
+                ", peerHandle=").append(peerHandle == null ? "<null>" : peerHandle.peerId).append(
+                ", responderType=").append(responderType).append(", supports80211mc=").append(
+                supports80211mc).append(", channelWidth=").append(channelWidth).append(
+                ", frequency=").append(frequency).append(", centerFreq0=").append(
+                centerFreq0).append(", centerFreq1=").append(centerFreq1).append(
+                ", preamble=").append(preamble).toString();
+    }
+
+    /** @hide */
+    static int translcateScanResultChannelWidth(int scanResultChannelWidth) {
+        switch (scanResultChannelWidth) {
+            case ScanResult.CHANNEL_WIDTH_20MHZ:
+                return CHANNEL_WIDTH_20MHZ;
+            case ScanResult.CHANNEL_WIDTH_40MHZ:
+                return CHANNEL_WIDTH_40MHZ;
+            case ScanResult.CHANNEL_WIDTH_80MHZ:
+                return CHANNEL_WIDTH_80MHZ;
+            case ScanResult.CHANNEL_WIDTH_160MHZ:
+                return CHANNEL_WIDTH_160MHZ;
+            case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
+                return CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
+            default:
+                throw new IllegalArgumentException(
+                        "translcateScanResultChannelWidth: bad " + scanResultChannelWidth);
+        }
+    }
+}