Add the ability to match a band on a WiFi network.

• Add API to set a band on WifiNetworkSpecifier
• Make sure all WiFi networks have a WifiNetworkAgentSpecifier
• Compute the band from WifiInfo and store it in WNASpecifier
• Make sure the specifiers match each other correctly
• Add a measure of protection against matching the (B)SSID
  on regular WiFis

The intended use of this patch is for apps to be able to match
a WiFi network by its band. Also, while this is not supported
in stock Android, OEMs may replace parts of the stack to support
requesting a network by band, so that apps with appropriate
permissions can request the device connects to multiple bands
at the same time.

Bug: 181741503
Test: new test in cts/ConnectivityManagerTest
Change-Id: I1c2b023bcd53296c9aed221c74fcfb734aebdc6d
diff --git a/framework/api/current.txt b/framework/api/current.txt
index a8ee1dc..c5d9c2f 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -559,6 +559,7 @@
 
   public final class WifiNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
     method public int describeContents();
+    method public int getBand();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiNetworkSpecifier> CREATOR;
   }
@@ -566,6 +567,7 @@
   public static final class WifiNetworkSpecifier.Builder {
     ctor public WifiNetworkSpecifier.Builder();
     method @NonNull public android.net.wifi.WifiNetworkSpecifier build();
+    method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setBand(int);
     method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setBssid(@NonNull android.net.MacAddress);
     method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setBssidPattern(@NonNull android.net.MacAddress, @NonNull android.net.MacAddress);
     method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setIsEnhancedOpen(boolean);
diff --git a/framework/java/android/net/wifi/ScanResult.java b/framework/java/android/net/wifi/ScanResult.java
index d124ac2..2a35874 100644
--- a/framework/java/android/net/wifi/ScanResult.java
+++ b/framework/java/android/net/wifi/ScanResult.java
@@ -389,6 +389,7 @@
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"WIFI_BAND_"}, value = {
+            UNSPECIFIED,
             WIFI_BAND_24_GHZ,
             WIFI_BAND_5_GHZ,
             WIFI_BAND_6_GHZ,
diff --git a/framework/java/android/net/wifi/WifiNetworkAgentSpecifier.java b/framework/java/android/net/wifi/WifiNetworkAgentSpecifier.java
index 0d13805..5cdcc16 100644
--- a/framework/java/android/net/wifi/WifiNetworkAgentSpecifier.java
+++ b/framework/java/android/net/wifi/WifiNetworkAgentSpecifier.java
@@ -25,6 +25,7 @@
 import android.net.MatchAllNetworkSpecifier;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
+import android.net.wifi.ScanResult.WifiBand;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -40,10 +41,31 @@
      */
     private final WifiConfiguration mWifiConfiguration;
 
-    public WifiNetworkAgentSpecifier(@NonNull WifiConfiguration wifiConfiguration) {
+    /**
+     * Band, as one of the ScanResult.WIFI_BAND_* constants.
+     */
+    @WifiBand private final int mBand;
+
+    /**
+     * Whether to match P2P requests.
+     *
+     * When matching against an instance of WifiNetworkSpecifier, simply matching SSID or
+     * BSSID patterns would let apps know if a given WiFi network's (B)SSID matches a pattern
+     * by simply filing a NetworkCallback with that pattern. Also, apps asking for a match on
+     * (B)SSID are apps requesting a P2P network, which involves protection with UI shown by
+     * the system, and the WifiNetworkSpecifiers for these P2P networks should never match
+     * an Internet-providing network to avoid calling back these apps on a network that happens
+     * to match their requested pattern but has not been brought up for them.
+     */
+    private final boolean mMatchLocalOnlySpecifiers;
+
+    public WifiNetworkAgentSpecifier(@NonNull WifiConfiguration wifiConfiguration,
+            @WifiBand int band, boolean matchLocalOnlySpecifiers) {
         checkNotNull(wifiConfiguration);
 
         mWifiConfiguration = wifiConfiguration;
+        mBand = band;
+        mMatchLocalOnlySpecifiers = matchLocalOnlySpecifiers;
     }
 
     /**
@@ -54,7 +76,10 @@
                 @Override
                 public WifiNetworkAgentSpecifier createFromParcel(@NonNull Parcel in) {
                     WifiConfiguration wifiConfiguration = in.readParcelable(null);
-                    return new WifiNetworkAgentSpecifier(wifiConfiguration);
+                    int band = in.readInt();
+                    boolean matchLocationSensitiveFields = in.readBoolean();
+                    return new WifiNetworkAgentSpecifier(wifiConfiguration, band,
+                            matchLocationSensitiveFields);
                 }
 
                 @Override
@@ -71,6 +96,8 @@
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeParcelable(mWifiConfiguration, flags);
+        dest.writeInt(mBand);
+        dest.writeBoolean(mMatchLocalOnlySpecifiers);
     }
 
     @Override
@@ -104,6 +131,13 @@
         checkNotNull(this.mWifiConfiguration.BSSID);
         checkNotNull(this.mWifiConfiguration.allowedKeyManagement);
 
+        if (!mMatchLocalOnlySpecifiers) {
+            // Specifiers that match non-local-only networks only match against the band.
+            return ns.getBand() == mBand;
+        }
+        if (ns.getBand() != ScanResult.UNSPECIFIED && ns.getBand() != mBand) {
+            return false;
+        }
         final String ssidWithQuotes = this.mWifiConfiguration.SSID;
         checkState(ssidWithQuotes.startsWith("\"") && ssidWithQuotes.endsWith("\""));
         final String ssidWithoutQuotes = ssidWithQuotes.substring(1, ssidWithQuotes.length() - 1);
@@ -128,7 +162,9 @@
         return Objects.hash(
                 mWifiConfiguration.SSID,
                 mWifiConfiguration.BSSID,
-                mWifiConfiguration.allowedKeyManagement);
+                mWifiConfiguration.allowedKeyManagement,
+                mBand,
+                mMatchLocalOnlySpecifiers);
     }
 
     @Override
@@ -143,7 +179,9 @@
         return Objects.equals(this.mWifiConfiguration.SSID, lhs.mWifiConfiguration.SSID)
                 && Objects.equals(this.mWifiConfiguration.BSSID, lhs.mWifiConfiguration.BSSID)
                 && Objects.equals(this.mWifiConfiguration.allowedKeyManagement,
-                    lhs.mWifiConfiguration.allowedKeyManagement);
+                    lhs.mWifiConfiguration.allowedKeyManagement)
+                && mBand == lhs.mBand
+                && mMatchLocalOnlySpecifiers == lhs.mMatchLocalOnlySpecifiers;
     }
 
     @Override
@@ -152,6 +190,8 @@
         sb.append("WifiConfiguration=")
                 .append(", SSID=").append(mWifiConfiguration.SSID)
                 .append(", BSSID=").append(mWifiConfiguration.BSSID)
+                .append(", band=").append(mBand)
+                .append(", matchLocationSensitiveFields=").append(mMatchLocalOnlySpecifiers)
                 .append("]");
         return sb.toString();
     }
diff --git a/framework/java/android/net/wifi/WifiNetworkSpecifier.java b/framework/java/android/net/wifi/WifiNetworkSpecifier.java
index e4b23bf..0b0eaff 100644
--- a/framework/java/android/net/wifi/WifiNetworkSpecifier.java
+++ b/framework/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -20,9 +20,13 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
 import android.net.MacAddress;
+import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
+import android.net.wifi.ScanResult.WifiBand;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PatternMatcher;
@@ -34,20 +38,65 @@
 import java.util.Objects;
 
 /**
- * Network specifier object used to request a local Wi-Fi network. Apps should use the
+ * Network specifier object used to request a Wi-Fi network. Apps should use the
  * {@link WifiNetworkSpecifier.Builder} class to create an instance.
  * <p>
- * On devices which support concurrent connections (indicated via
+ * This specifier can be used to request a local-only connection on devices that support concurrent
+ * connections (indicated via
  * {@link WifiManager#isStaConcurrencyForLocalOnlyConnectionsSupported()} and if the initiating app
- * targets SDK &ge; {@link android.os.Build.VERSION_CODES#S} or is a system app, these local only
+ * targets SDK &ge; {@link android.os.Build.VERSION_CODES#S} or is a system app. These local-only
  * connections may be brought up as a secondary concurrent connection (primary connection will be
  * used for networks with internet connectivity available to the user and all apps).
  * </p>
+ * <p>
+ * This specifier can also be used to listen for connected Wi-Fi networks on a particular band.
+ * Additionally, some devices may support requesting a connection to a particular band. If the
+ * device does not support such a request, it will send {@link NetworkCallback#onUnavailable()}
+ * upon request to the callback passed to
+ * {@link ConnectivityManager#requestNetwork(NetworkRequest, NetworkCallback)} or equivalent.
+ * See {@link Builder#build()} for details.
+ * </p>
  */
 public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parcelable {
     private static final String TAG = "WifiNetworkSpecifier";
 
     /**
+     * Returns the band for a given frequency in MHz.
+     * @hide
+     */
+    @WifiBand public static int getBand(final int freqMHz) {
+        if (ScanResult.is24GHz(freqMHz)) {
+            return ScanResult.WIFI_BAND_24_GHZ;
+        } else if (ScanResult.is5GHz(freqMHz)) {
+            return ScanResult.WIFI_BAND_5_GHZ;
+        } else if (ScanResult.is6GHz(freqMHz)) {
+            return ScanResult.WIFI_BAND_6_GHZ;
+        } else if (ScanResult.is60GHz(freqMHz)) {
+            return ScanResult.WIFI_BAND_60_GHZ;
+        }
+        return ScanResult.UNSPECIFIED;
+    }
+
+    /**
+     * Validates that the passed band is a valid band
+     * @param band the band to check
+     * @return true if the band is valid, false otherwise
+     * @hide
+     */
+    public static boolean validateBand(@WifiBand int band) {
+        switch (band) {
+            case ScanResult.UNSPECIFIED:
+            case ScanResult.WIFI_BAND_24_GHZ:
+            case ScanResult.WIFI_BAND_5_GHZ:
+            case ScanResult.WIFI_BAND_6_GHZ:
+            case ScanResult.WIFI_BAND_60_GHZ:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
      * Builder used to create {@link WifiNetworkSpecifier} objects.
      */
     public static final class Builder {
@@ -112,6 +161,10 @@
          * SSID-specific probe request must be used for scans.
          */
         private boolean mIsHiddenSSID;
+        /**
+         * The requested band for this connection, or BAND_UNSPECIFIED.
+         */
+        @WifiBand private int mBand;
 
         public Builder() {
             mSsidPatternMatcher = null;
@@ -122,6 +175,7 @@
             mWpa2EnterpriseConfig = null;
             mWpa3EnterpriseConfig = null;
             mIsHiddenSSID = false;
+            mBand = ScanResult.UNSPECIFIED;
         }
 
         /**
@@ -353,6 +407,23 @@
             return this;
         }
 
+        /**
+         * Specifies the band requested for this network.
+         *
+         * Only a single band can be requested. An app can file multiple callbacks concurrently
+         * if they need to know about multiple bands.
+         *
+         * @param band The requested band.
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         */
+        public @NonNull Builder setBand(@WifiBand int band) {
+            if (!validateBand(band)) {
+                throw new IllegalArgumentException("Unexpected band in setBand : " + band);
+            }
+            mBand = band;
+            return this;
+        }
+
         private void setSecurityParamsInWifiConfiguration(
                 @NonNull WifiConfiguration configuration) {
             if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network.
@@ -462,14 +533,27 @@
         }
 
         /**
-         * Create a specifier object used to request a local Wi-Fi network. The generated
+         * Create a specifier object used to request a Wi-Fi network. The generated
          * {@link NetworkSpecifier} should be used in
          * {@link NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} when building
-         * the {@link NetworkRequest}. These specifiers can only be used to request a local wifi
-         * network (i.e no internet capability). So, the device will not switch it's default route
-         * to wifi if there are other transports (cellular for example) available.
+         * the {@link NetworkRequest}.
+         *
          *<p>
-         * Note: Apps can set a combination of network match params:
+         * When using with {@link ConnectivityManager#requestNetwork(NetworkRequest,
+         * NetworkCallback)} or variants, note that some devices may not support requesting a
+         * network with all combinations of specifier members. For example, some devices may only
+         * support requesting local-only networks (networks without the
+         * {@link NetworkCapabilities#NET_CAPABILITY_INTERNET} capability), or not support
+         * requesting a particular band. However, there are no restrictions when using
+         * {@link ConnectivityManager#registerNetworkCallback(NetworkRequest, NetworkCallback)}
+         * or other similar methods which monitor but do not request networks.
+         *
+         * If the device can't support a request, the app will receive a call to
+         * {@link NetworkCallback#onUnavailable()}.
+         *</p>
+         *
+         *<p>
+         * When requesting a local-only network, apps can set a combination of network match params:
          * <li> SSID Pattern using {@link #setSsidPattern(PatternMatcher)} OR Specific SSID using
          * {@link #setSsid(String)}. </li>
          * AND/OR
@@ -479,6 +563,12 @@
          * The system will find the set of networks matching the request and present the user
          * with a system dialog which will allow the user to select a specific Wi-Fi network to
          * connect to or to deny the request.
+         *
+         * To protect user privacy, some limitations to the ability of matching patterns apply.
+         * In particular, when the system brings up a network to satisfy a {@link NetworkRequest}
+         * from some app, the system reserves the right to decline matching the SSID pattern to
+         * the real SSID of the network for other apps than the app that requested the network, and
+         * not send those callbacks even if the SSID matches the requested pattern.
          *</p>
          *
          * For example:
@@ -512,15 +602,15 @@
          * @throws IllegalStateException on invalid params set.
          */
         public @NonNull WifiNetworkSpecifier build() {
-            if (!hasSetAnyPattern()) {
+            if (!hasSetAnyPattern() && mBand == ScanResult.UNSPECIFIED) {
                 throw new IllegalStateException("one of setSsidPattern/setSsid/setBssidPattern/"
-                        + "setBssid should be invoked for specifier");
+                        + "setBssid/setBand should be invoked for specifier");
             }
             setMatchAnyPatternIfUnset();
             if (hasSetMatchNonePattern()) {
                 throw new IllegalStateException("cannot set match-none pattern for specifier");
             }
-            if (hasSetMatchAllPattern()) {
+            if (hasSetMatchAllPattern() && mBand == ScanResult.UNSPECIFIED) {
                 throw new IllegalStateException("cannot set match-all pattern for specifier");
             }
             if (mIsHiddenSSID && mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_LITERAL) {
@@ -532,6 +622,7 @@
             return new WifiNetworkSpecifier(
                     mSsidPatternMatcher,
                     mBssidPatternMatcher,
+                    mBand,
                     buildWifiConfiguration());
         }
     }
@@ -550,6 +641,11 @@
     public final Pair<MacAddress, MacAddress> bssidPatternMatcher;
 
     /**
+     * The band for this Wi-Fi network.
+     */
+    @WifiBand private final int mBand;
+
+    /**
      * Security credentials for the network.
      * <p>
      * Note: {@link WifiConfiguration#SSID} & {@link WifiConfiguration#BSSID} fields from
@@ -568,6 +664,7 @@
     /** @hide */
     public WifiNetworkSpecifier(@NonNull PatternMatcher ssidPatternMatcher,
                                 @NonNull Pair<MacAddress, MacAddress> bssidPatternMatcher,
+                                @WifiBand int band,
                                 @NonNull WifiConfiguration wifiConfiguration) {
         checkNotNull(ssidPatternMatcher);
         checkNotNull(bssidPatternMatcher);
@@ -575,9 +672,17 @@
 
         this.ssidPatternMatcher = ssidPatternMatcher;
         this.bssidPatternMatcher = bssidPatternMatcher;
+        this.mBand = band;
         this.wifiConfiguration = wifiConfiguration;
     }
 
+    /**
+     * The band for this Wi-Fi network specifier.
+     */
+    @WifiBand public int getBand() {
+        return mBand;
+    }
+
     public static final @NonNull Creator<WifiNetworkSpecifier> CREATOR =
             new Creator<WifiNetworkSpecifier>() {
                 @Override
@@ -587,8 +692,9 @@
                     MacAddress mask = in.readParcelable(null);
                     Pair<MacAddress, MacAddress> bssidPatternMatcher =
                             Pair.create(baseAddress, mask);
+                    int band = in.readInt();
                     WifiConfiguration wifiConfiguration = in.readParcelable(null);
-                    return new WifiNetworkSpecifier(ssidPatternMatcher, bssidPatternMatcher,
+                    return new WifiNetworkSpecifier(ssidPatternMatcher, bssidPatternMatcher, band,
                             wifiConfiguration);
                 }
 
@@ -608,6 +714,7 @@
         dest.writeParcelable(ssidPatternMatcher, flags);
         dest.writeParcelable(bssidPatternMatcher.first, flags);
         dest.writeParcelable(bssidPatternMatcher.second, flags);
+        dest.writeInt(mBand);
         dest.writeParcelable(wifiConfiguration, flags);
     }
 
@@ -615,7 +722,7 @@
     public int hashCode() {
         return Objects.hash(
                 ssidPatternMatcher.getPath(), ssidPatternMatcher.getType(), bssidPatternMatcher,
-                wifiConfiguration.allowedKeyManagement);
+                mBand, wifiConfiguration.allowedKeyManagement);
     }
 
     @Override
@@ -633,6 +740,7 @@
                     lhs.ssidPatternMatcher.getType())
                 && Objects.equals(this.bssidPatternMatcher,
                     lhs.bssidPatternMatcher)
+                && this.mBand == lhs.mBand
                 && Objects.equals(this.wifiConfiguration.allowedKeyManagement,
                     lhs.wifiConfiguration.allowedKeyManagement);
     }
@@ -645,6 +753,7 @@
                 .append(", BSSID Match pattern=").append(bssidPatternMatcher)
                 .append(", SSID=").append(wifiConfiguration.SSID)
                 .append(", BSSID=").append(wifiConfiguration.BSSID)
+                .append(", band=").append(mBand)
                 .append("]")
                 .toString();
     }
diff --git a/framework/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java b/framework/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
index d479aac..c33cad8 100644
--- a/framework/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
+++ b/framework/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
@@ -90,13 +90,13 @@
         WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
         WifiNetworkAgentSpecifier specifier1 =
                 new WifiNetworkAgentSpecifier(
-                        wifiConfiguration1);
+                        wifiConfiguration1, ScanResult.WIFI_BAND_24_GHZ, true);
 
         WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
         wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkAgentSpecifier specifier2 =
                 new WifiNetworkAgentSpecifier(
-                        wifiConfiguration2);
+                        wifiConfiguration2, ScanResult.WIFI_BAND_24_GHZ, true);
 
         assertFalse(specifier2.equals(specifier1));
     }
@@ -112,13 +112,13 @@
         WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
         WifiNetworkAgentSpecifier specifier1 =
                 new WifiNetworkAgentSpecifier(
-                        wifiConfiguration1);
+                        wifiConfiguration1, ScanResult.WIFI_BAND_5_GHZ, true);
 
         WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
         wifiConfiguration2.SSID = TEST_SSID_1;
         WifiNetworkAgentSpecifier specifier2 =
                 new WifiNetworkAgentSpecifier(
-                        wifiConfiguration2);
+                        wifiConfiguration2, ScanResult.WIFI_BAND_5_GHZ, true);
 
         assertFalse(specifier2.equals(specifier1));
     }
@@ -134,13 +134,13 @@
         WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
         WifiNetworkAgentSpecifier specifier1 =
                 new WifiNetworkAgentSpecifier(
-                        wifiConfiguration1);
+                        wifiConfiguration1, ScanResult.WIFI_BAND_24_GHZ, false);
 
         WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
         wifiConfiguration2.BSSID = TEST_BSSID_1;
         WifiNetworkAgentSpecifier specifier2 =
                 new WifiNetworkAgentSpecifier(
-                        wifiConfiguration2);
+                        wifiConfiguration2, ScanResult.WIFI_BAND_24_GHZ, false);
 
         assertFalse(specifier2.equals(specifier1));
     }
@@ -194,6 +194,7 @@
         WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
                 ssidPattern,
                 bssidPattern,
+                ScanResult.WIFI_BAND_5_GHZ,
                 wificonfigurationNetworkSpecifier);
 
         assertTrue(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
@@ -222,6 +223,7 @@
         WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
                 ssidPattern,
                 bssidPattern,
+                ScanResult.WIFI_BAND_5_GHZ,
                 wificonfigurationNetworkSpecifier);
 
         assertTrue(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
@@ -250,6 +252,7 @@
         WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
                 ssidPattern,
                 bssidPattern,
+                ScanResult.WIFI_BAND_5_GHZ,
                 wificonfigurationNetworkSpecifier);
 
         assertTrue(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
@@ -269,7 +272,7 @@
         wifiConfigurationNetworkAgent.SSID = "\"" + TEST_SSID_1 + "\"";
         WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
                 new WifiNetworkAgentSpecifier(
-                        wifiConfigurationNetworkAgent);
+                        wifiConfigurationNetworkAgent, ScanResult.WIFI_BAND_24_GHZ, true);
 
         PatternMatcher ssidPattern =
                 new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
@@ -281,6 +284,7 @@
         WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
                 ssidPattern,
                 bssidPattern,
+                ScanResult.WIFI_BAND_24_GHZ,
                 wificonfigurationNetworkSpecifier);
 
         assertFalse(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
@@ -288,6 +292,113 @@
     }
 
     /**
+     * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} band matching.
+     */
+    @Test
+    public void testWifiNetworkAgentSpecifierBandMatching() {
+        WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration();
+        wifiConfigurationNetworkAgent.SSID = "\"" + TEST_SSID + "\"";
+        WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
+                new WifiNetworkAgentSpecifier(
+                        wifiConfigurationNetworkAgent, ScanResult.WIFI_BAND_5_GHZ, true);
+
+        PatternMatcher ssidPattern =
+                new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+        Pair<MacAddress, MacAddress> bssidPattern =
+                Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                        MacAddress.fromString(TEST_BSSID_OUI_MASK));
+        WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+        wificonfigurationNetworkSpecifier.allowedKeyManagement
+                .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+
+        // Same band matches.
+        WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+                ssidPattern,
+                bssidPattern,
+                ScanResult.WIFI_BAND_5_GHZ,
+                wificonfigurationNetworkSpecifier);
+        assertTrue(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
+        assertTrue(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
+
+        // Different band does not match.
+        wifiNetworkSpecifier = new WifiNetworkSpecifier(
+                ssidPattern,
+                bssidPattern,
+                ScanResult.WIFI_BAND_24_GHZ,
+                wificonfigurationNetworkSpecifier);
+        assertFalse(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
+        assertFalse(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
+
+        // UNSPECIFIED matches a specified band.
+        wifiNetworkSpecifier = new WifiNetworkSpecifier(
+                ssidPattern,
+                bssidPattern,
+                ScanResult.UNSPECIFIED,
+                wificonfigurationNetworkSpecifier);
+        assertTrue(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
+        assertTrue(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
+    }
+
+    /**
+     * Validate {@link WifiNetworkAgentSpecifier} local-only matching.
+     */
+    @Test
+    public void testWifiNetworkAgentSpecifierLocalOnlyMatching() {
+        WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration();
+        wifiConfigurationNetworkAgent.SSID = "\"" + TEST_SSID_1 + "\"";
+
+        PatternMatcher ssidPattern =
+                new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+        Pair<MacAddress, MacAddress> bssidPattern =
+                Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                        MacAddress.fromString(TEST_BSSID_OUI_MASK));
+        WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+        wificonfigurationNetworkSpecifier.allowedKeyManagement
+                .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+
+        // There is no match because the SSID pattern does not match.
+        WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
+                new WifiNetworkAgentSpecifier(
+                        wifiConfigurationNetworkAgent, ScanResult.WIFI_BAND_5_GHZ, true);
+        WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+                ssidPattern,
+                bssidPattern,
+                ScanResult.WIFI_BAND_5_GHZ,
+                wificonfigurationNetworkSpecifier);
+        assertFalse(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
+        assertFalse(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
+
+        // If the WifiNetworkAgentSpecifier is not a local-only specifier, then it matches, because
+        // the SSID pattern is ignored.
+        // TODO: this should also fail to match. An app setting a specifier with a SSID or BSSID
+        // pattern should not match any peer-to-peer network.
+        wifiNetworkAgentSpecifier =
+                new WifiNetworkAgentSpecifier(
+                        wifiConfigurationNetworkAgent, ScanResult.WIFI_BAND_5_GHZ, false);
+        assertTrue(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
+        assertTrue(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
+
+        // If the band doesn't match, then there is no match.
+        wifiNetworkSpecifier = new WifiNetworkSpecifier(
+                ssidPattern,
+                bssidPattern,
+                ScanResult.WIFI_BAND_24_GHZ,
+                wificonfigurationNetworkSpecifier);
+        assertFalse(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
+        assertFalse(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
+
+        // An UNSPECIFIED band also doesn't match anything.
+        // TODO: this is also likely incorrect.
+        wifiNetworkSpecifier = new WifiNetworkSpecifier(
+                ssidPattern,
+                bssidPattern,
+                ScanResult.UNSPECIFIED,
+                wificonfigurationNetworkSpecifier);
+        assertFalse(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
+        assertFalse(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
+    }
+
+    /**
      * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
      * a) Create network agent specifier for WPA_PSK network
      * b) Create network specifier with non-matching BSSID pattern.
@@ -300,7 +411,7 @@
         wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1;
         WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
                 new WifiNetworkAgentSpecifier(
-                        wifiConfigurationNetworkAgent);
+                        wifiConfigurationNetworkAgent, ScanResult.WIFI_BAND_5_GHZ, true);
 
         PatternMatcher ssidPattern =
                 new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB);
@@ -313,6 +424,7 @@
         WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
                 ssidPattern,
                 bssidPattern,
+                ScanResult.WIFI_BAND_5_GHZ,
                 wificonfigurationNetworkSpecifier);
 
         assertFalse(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
@@ -332,7 +444,7 @@
         wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1;
         WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
                 new WifiNetworkAgentSpecifier(
-                        wifiConfigurationNetworkAgent);
+                        wifiConfigurationNetworkAgent, ScanResult.WIFI_BAND_24_GHZ, true);
 
         PatternMatcher ssidPattern =
                 new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
@@ -345,6 +457,7 @@
         WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
                 ssidPattern,
                 bssidPattern,
+                ScanResult.WIFI_BAND_24_GHZ,
                 wificonfigurationNetworkSpecifier);
 
         assertFalse(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
@@ -372,13 +485,13 @@
         WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
                 ssidPattern,
                 bssidPattern,
+                ScanResult.UNSPECIFIED,
                 wificonfigurationNetworkSpecifier);
 
         assertFalse(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
         assertFalse(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
     }
 
-
     private WifiConfiguration createDefaultWifiConfiguration() {
         WifiConfiguration wifiConfiguration = new WifiConfiguration();
         wifiConfiguration.SSID = "\"" + TEST_SSID + "\"";
@@ -389,7 +502,8 @@
     }
 
     private WifiNetworkAgentSpecifier createDefaultNetworkAgentSpecifier() {
-        return new WifiNetworkAgentSpecifier(createDefaultWifiConfiguration());
+        return new WifiNetworkAgentSpecifier(createDefaultWifiConfiguration(),
+                ScanResult.WIFI_BAND_5_GHZ, false);
     }
 
 }
diff --git a/framework/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/framework/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
index 1383f72..87dd8c2 100644
--- a/framework/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
+++ b/framework/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
@@ -653,6 +653,7 @@
                 new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        ScanResult.WIFI_BAND_5_GHZ,
                         wifiConfiguration);
 
         Parcel parcelW = Parcel.obtain();
@@ -684,6 +685,7 @@
                 new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        ScanResult.UNSPECIFIED,  /* band */
                         wifiConfiguration);
 
         assertFalse(specifier.canBeSatisfiedBy(null));
@@ -706,12 +708,14 @@
                 new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        ScanResult.WIFI_BAND_5_GHZ,
                         wifiConfiguration);
 
         WifiNetworkSpecifier specifier2 =
                 new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        ScanResult.WIFI_BAND_5_GHZ,
                         wifiConfiguration);
 
         assertTrue(specifier2.canBeSatisfiedBy(specifier1));
@@ -733,6 +737,7 @@
                 new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        ScanResult.WIFI_BAND_24_GHZ,
                         wifiConfiguration1);
 
         WifiConfiguration wifiConfiguration2 = new WifiConfiguration();
@@ -741,6 +746,7 @@
                 new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        ScanResult.WIFI_BAND_24_GHZ,
                         wifiConfiguration2);
 
         assertFalse(specifier2.canBeSatisfiedBy(specifier1));
@@ -762,12 +768,14 @@
                 new WifiNetworkSpecifier(new PatternMatcher("", PATTERN_LITERAL),
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        ScanResult.WIFI_BAND_5_GHZ,
                         wifiConfiguration);
 
         WifiNetworkSpecifier specifier2 =
                 new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        ScanResult.WIFI_BAND_5_GHZ,
                         wifiConfiguration);
 
         assertFalse(specifier2.canBeSatisfiedBy(specifier1));
@@ -789,14 +797,67 @@
                 new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        ScanResult.WIFI_BAND_24_GHZ,
                         wifiConfiguration);
 
         WifiNetworkSpecifier specifier2 =
                 new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
                         Pair.create(WifiManager.ALL_ZEROS_MAC_ADDRESS,
                                 WifiManager.ALL_ZEROS_MAC_ADDRESS),
+                        ScanResult.WIFI_BAND_24_GHZ,
                         wifiConfiguration);
 
         assertFalse(specifier2.canBeSatisfiedBy(specifier1));
     }
+
+    /**
+     * Validate NetworkSpecifier band matching.
+     */
+    @Test
+    public void testWifiNetworkSpecifierBandMatching() {
+        WifiConfiguration wifiConfiguration = new WifiConfiguration();
+        wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+
+        WifiNetworkSpecifier specifier1 =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                                MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        ScanResult.WIFI_BAND_24_GHZ,
+                        wifiConfiguration);
+
+        WifiNetworkSpecifier specifier2 =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                                MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        ScanResult.WIFI_BAND_24_GHZ,
+                        wifiConfiguration);
+
+        // Same band matches.
+        assertTrue(specifier2.canBeSatisfiedBy(specifier1));
+        assertTrue(specifier1.canBeSatisfiedBy(specifier2));
+
+        specifier2 =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(WifiManager.ALL_ZEROS_MAC_ADDRESS,
+                                WifiManager.ALL_ZEROS_MAC_ADDRESS),
+                        ScanResult.WIFI_BAND_5_GHZ,
+                        wifiConfiguration);
+
+        // Different band does not match.
+        assertFalse(specifier2.canBeSatisfiedBy(specifier1));
+        assertFalse(specifier1.canBeSatisfiedBy(specifier2));
+
+        specifier1 =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(WifiManager.ALL_ZEROS_MAC_ADDRESS,
+                                WifiManager.ALL_ZEROS_MAC_ADDRESS),
+                        ScanResult.UNSPECIFIED,
+                        wifiConfiguration);
+
+        // An UNSPECIFIED band does not match a specified band, because a WifiNetworkSpecifier
+        // satisfies another only if they are equal.
+        assertFalse(specifier2.canBeSatisfiedBy(specifier1));
+        assertFalse(specifier1.canBeSatisfiedBy(specifier2));
+    }
 }
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index 679c8fc..31eac23 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -78,6 +78,7 @@
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiNetworkAgentSpecifier;
+import android.net.wifi.WifiNetworkSpecifier;
 import android.net.wifi.hotspot2.IProvisioningCallback;
 import android.net.wifi.hotspot2.OsuProvider;
 import android.net.wifi.nl80211.DeviceWiphyCapabilities;
@@ -3847,10 +3848,15 @@
     }
 
     private WifiNetworkAgentSpecifier createNetworkAgentSpecifier(
-            @NonNull WifiConfiguration currentWifiConfiguration, @Nullable String currentBssid) {
-        currentWifiConfiguration.BSSID = currentBssid;
+            @NonNull WifiConfiguration currentWifiConfiguration, @Nullable String currentBssid,
+            boolean matchLocationSensitiveInformation) {
+        // Defensive copy to avoid mutating the passed argument
+        final WifiConfiguration conf = new WifiConfiguration(currentWifiConfiguration);
+        conf.BSSID = currentBssid;
         WifiNetworkAgentSpecifier wns =
-                new WifiNetworkAgentSpecifier(currentWifiConfiguration);
+                new WifiNetworkAgentSpecifier(conf,
+                        WifiNetworkSpecifier.getBand(mWifiInfo.getFrequency()),
+                        matchLocationSensitiveInformation);
         return wns;
     }
 
@@ -3922,10 +3928,18 @@
         if (mNetworkFactory.isSpecificRequestInProgress(currentWifiConfiguration, currentBssid)) {
             // Remove internet capability.
             builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
-            // Fill up the network agent specifier for this connection.
-            builder.setNetworkSpecifier(createNetworkAgentSpecifier(
-                    currentWifiConfiguration, getConnectedBssidInternal()));
+            // Fill up the network agent specifier for this connection, allowing NetworkCallbacks
+            // to match local-only specifiers in requests. TODO(b/187921303): a third-party app can
+            // observe this location-sensitive information by registering a NetworkCallback.
+            builder.setNetworkSpecifier(createNetworkAgentSpecifier(currentWifiConfiguration,
+                    getConnectedBssidInternal(), true /* matchLocalOnlySpecifiers */));
+        } else {
+            // Fill up the network agent specifier for this connection, without allowing
+            // NetworkCallbacks to match local-only specifiers in requests.
+            builder.setNetworkSpecifier(createNetworkAgentSpecifier(currentWifiConfiguration,
+                    getConnectedBssidInternal(), false /* matchLocalOnlySpecifiers */));
         }
+
         updateLinkBandwidth(builder);
         final NetworkCapabilities networkCapabilities = builder.build();
         if (mVcnManager == null || !currentWifiConfiguration.carrierMerged) {
diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
index 50ec9c7..5bfae26 100644
--- a/service/java/com/android/server/wifi/WifiConfigurationUtil.java
+++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
@@ -20,6 +20,7 @@
 
 import static com.android.server.wifi.util.NativeUtil.addEnclosingQuotes;
 
+import android.annotation.SuppressLint;
 import android.net.IpConfiguration;
 import android.net.MacAddress;
 import android.net.StaticIpConfiguration;
@@ -751,6 +752,12 @@
         return false;
     }
 
+    // TODO: b/177434707 calls inside same module are safe
+    @SuppressLint("NewApi")
+    private static int getBand(WifiNetworkSpecifier s) {
+        return s.getBand();
+    }
+
     /**
      * Validate the configuration received from an external application inside
      * {@link WifiNetworkSpecifier}.
@@ -758,15 +765,16 @@
      * This method checks for the following parameters:
      * 1. {@link WifiNetworkSpecifier#ssidPatternMatcher}
      * 2. {@link WifiNetworkSpecifier#bssidPatternMatcher}
-     * 3. {@link WifiConfiguration#SSID}
-     * 4. {@link WifiConfiguration#BSSID}
-     * 5. {@link WifiConfiguration#preSharedKey}
-     * 6. {@link WifiConfiguration#allowedKeyManagement}
-     * 7. {@link WifiConfiguration#allowedProtocols}
-     * 8. {@link WifiConfiguration#allowedAuthAlgorithms}
-     * 9. {@link WifiConfiguration#allowedGroupCiphers}
-     * 10. {@link WifiConfiguration#allowedPairwiseCiphers}
-     * 11. {@link WifiConfiguration#getIpConfiguration()}
+     * 3. {@link WifiNetworkSpecifier#getBand()}
+     * 4. {@link WifiConfiguration#SSID}
+     * 5. {@link WifiConfiguration#BSSID}
+     * 6. {@link WifiConfiguration#preSharedKey}
+     * 7. {@link WifiConfiguration#allowedKeyManagement}
+     * 8. {@link WifiConfiguration#allowedProtocols}
+     * 9. {@link WifiConfiguration#allowedAuthAlgorithms}
+     * 10. {@link WifiConfiguration#allowedGroupCiphers}
+     * 11. {@link WifiConfiguration#allowedPairwiseCiphers}
+     * 12. {@link WifiConfiguration#getIpConfiguration()}
      *
      * @param specifier Instance of {@link WifiNetworkSpecifier}.
      * @return true if the parameters are valid, false otherwise.
@@ -784,6 +792,9 @@
             Log.e(TAG, "validateNetworkSpecifier failed : match-all specifier");
             return false;
         }
+        if (!WifiNetworkSpecifier.validateBand(getBand(specifier))) {
+            return false;
+        }
         WifiConfiguration config = specifier.wifiConfiguration;
         if (specifier.ssidPatternMatcher.getType() == PatternMatcher.PATTERN_LITERAL) {
             // For literal SSID matches, the value should satisfy SSID requirements.
diff --git a/service/java/com/android/server/wifi/WifiNetworkFactory.java b/service/java/com/android/server/wifi/WifiNetworkFactory.java
index 9650be4..3f029bf 100644
--- a/service/java/com/android/server/wifi/WifiNetworkFactory.java
+++ b/service/java/com/android/server/wifi/WifiNetworkFactory.java
@@ -25,6 +25,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
@@ -646,6 +647,12 @@
         return false;
     }
 
+    // TODO: b/177434707 calls inside same module are safe
+    @SuppressLint("NewApi")
+    private static int getBand(WifiNetworkSpecifier s) {
+        return s.getBand();
+    }
+
     boolean isRequestWithWifiNetworkSpecifierValid(NetworkRequest networkRequest) {
         // Request cannot have internet capability since such a request can never be fulfilled.
         // (NetworkAgent for connection with WifiNetworkSpecifier will not have internet capability)
@@ -672,6 +679,10 @@
             return false;
         }
         WifiNetworkSpecifier wns = (WifiNetworkSpecifier) networkRequest.getNetworkSpecifier();
+        if (getBand(wns) != ScanResult.UNSPECIFIED) {
+            Log.e(TAG, "Requesting specific frequency bands is not yet supported. Rejecting");
+            return false;
+        }
         if (!WifiConfigurationUtil.validateNetworkSpecifier(wns)) {
             Log.e(TAG, "Invalid wifi network specifier: " + wns + ". Rejecting ");
             return false;
@@ -790,7 +801,8 @@
             mActiveSpecificNetworkRequest = networkRequest;
             WifiNetworkSpecifier wns = (WifiNetworkSpecifier) ns;
             mActiveSpecificNetworkRequestSpecifier = new WifiNetworkSpecifier(
-                    wns.ssidPatternMatcher, wns.bssidPatternMatcher, wns.wifiConfiguration);
+                    wns.ssidPatternMatcher, wns.bssidPatternMatcher, ScanResult.UNSPECIFIED,
+                    wns.wifiConfiguration);
             mWifiMetrics.incrementNetworkRequestApiNumRequest();
 
             if (!triggerConnectIfUserApprovedMatchFound()) {
@@ -1000,6 +1012,9 @@
         networkToConnect.shared = false;
         networkToConnect.fromWifiNetworkSpecifier = true;
 
+        // TODO(b/188021807): Implement the band request from the specifier on the network to
+        // connect.
+
         // Store the user selected network.
         mUserSelectedNetwork = networkToConnect;
 
diff --git a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
index 1d43666..5fcf778 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
@@ -107,6 +107,7 @@
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiNetworkAgentSpecifier;
+import android.net.wifi.WifiNetworkSpecifier;
 import android.net.wifi.WifiSsid;
 import android.net.wifi.hotspot2.IProvisioningCallback;
 import android.net.wifi.hotspot2.OsuProvider;
@@ -4333,6 +4334,7 @@
      */
     @Test
     public void verifyNetworkCapabilities() throws Exception {
+        mWifiInfo.setFrequency(5825);
         when(mPerNetwork.getTxLinkBandwidthKbps()).thenReturn(40_000);
         when(mPerNetwork.getRxLinkBandwidthKbps()).thenReturn(50_000);
         // Simulate the first connection.
@@ -4348,7 +4350,6 @@
 
         // Should have internet capability.
         assertTrue(networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
-        assertNull(networkCapabilities.getNetworkSpecifier());
 
         assertEquals(mConnectedNetwork.creatorUid, networkCapabilities.getOwnerUid());
         assertArrayEquals(
@@ -4359,6 +4360,16 @@
         assertEquals(-42, mWifiInfo.getRssi());
         assertEquals(40_000, networkCapabilities.getLinkUpstreamBandwidthKbps());
         assertEquals(50_000, networkCapabilities.getLinkDownstreamBandwidthKbps());
+
+        // Should set band correctly.
+        // There is no accessor to get the band from the WifiNetworkAgentSpecifier, so match against
+        // a WifiNetworkSpecifier.
+        // TODO: should there be?
+        final NetworkSpecifier spec = networkCapabilities.getNetworkSpecifier();
+        assertTrue(spec instanceof WifiNetworkAgentSpecifier);
+        final WifiNetworkAgentSpecifier wnas = (WifiNetworkAgentSpecifier) spec;
+        assertTrue(wnas.satisfiesNetworkSpecifier(
+                new WifiNetworkSpecifier.Builder().setBand(ScanResult.WIFI_BAND_5_GHZ).build()));
     }
 
     /**
@@ -4368,6 +4379,7 @@
      */
     @Test
     public void verifyNetworkCapabilitiesForSpecificRequest() throws Exception {
+        mWifiInfo.setFrequency(2437);
         when(mPerNetwork.getTxLinkBandwidthKbps()).thenReturn(30_000);
         when(mPerNetwork.getRxLinkBandwidthKbps()).thenReturn(40_000);
         when(mWifiNetworkFactory.isSpecificRequestInProgress(any(), any())).thenReturn(true);
@@ -4389,8 +4401,14 @@
         assertTrue(networkSpecifier instanceof WifiNetworkAgentSpecifier);
         WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
                 (WifiNetworkAgentSpecifier) networkSpecifier;
+
+        // createNetworkAgentSpecifier does not write the BSSID to the current wifi configuration.
+        WifiConfiguration expectedConfig = new WifiConfiguration(
+                mCmi.getConnectedWifiConfiguration());
+        expectedConfig.BSSID = TEST_BSSID_STR;
         WifiNetworkAgentSpecifier expectedWifiNetworkAgentSpecifier =
-                new WifiNetworkAgentSpecifier(mCmi.getConnectedWifiConfiguration());
+                new WifiNetworkAgentSpecifier(expectedConfig, ScanResult.WIFI_BAND_24_GHZ,
+                        true /* matchLocalOnlySpecifiers */);
         assertEquals(expectedWifiNetworkAgentSpecifier, wifiNetworkAgentSpecifier);
         assertEquals(30_000, networkCapabilities.getLinkUpstreamBandwidthKbps());
         assertEquals(40_000, networkCapabilities.getLinkDownstreamBandwidthKbps());
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
index 15729c8..01e255f 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
@@ -24,6 +24,7 @@
 import android.content.pm.UserInfo;
 import android.net.IpConfiguration;
 import android.net.MacAddress;
+import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiEnterpriseConfig;
 import android.net.wifi.WifiManager;
@@ -609,6 +610,7 @@
         WifiNetworkSpecifier specifier = new WifiNetworkSpecifier(
                 new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL),
                 Pair.create(WifiManager.ALL_ZEROS_MAC_ADDRESS, WifiManager.ALL_ZEROS_MAC_ADDRESS),
+                ScanResult.UNSPECIFIED,
                 WifiConfigurationTestUtil.createOpenNetwork());
         assertTrue(WifiConfigurationUtil.validateNetworkSpecifier(specifier));
     }
@@ -622,6 +624,7 @@
         WifiNetworkSpecifier specifier = new WifiNetworkSpecifier(
                 new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB),
                 Pair.create(MacAddress.fromString(TEST_BSSID), MacAddress.BROADCAST_ADDRESS),
+                ScanResult.UNSPECIFIED,
                 WifiConfigurationTestUtil.createOpenNetwork());
         assertTrue(WifiConfigurationUtil.validateNetworkSpecifier(specifier));
     }
@@ -635,11 +638,28 @@
         WifiNetworkSpecifier specifier = new WifiNetworkSpecifier(
                 new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL),
                 Pair.create(MacAddress.fromString(TEST_BSSID), MacAddress.BROADCAST_ADDRESS),
+                ScanResult.UNSPECIFIED,
                 WifiConfigurationTestUtil.createOpenNetwork());
         assertTrue(WifiConfigurationUtil.validateNetworkSpecifier(specifier));
     }
 
     /**
+     * Verify that the validate method validates a WifiNetworkSpecifier that specifies ssid, bssid,
+     * and band. Note that such requests will currently still be rejected by WifiNetworkFactory, but
+     * requesting specific bands may be supported in future releases.
+     */
+    @Test
+    public void testValidateNetworkSpecifierPositiveCases_SsidPatternAndBssidPatternAndBand() {
+        WifiNetworkSpecifier specifier = new WifiNetworkSpecifier(
+                new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL),
+                Pair.create(MacAddress.fromString(TEST_BSSID), MacAddress.BROADCAST_ADDRESS),
+                ScanResult.WIFI_BAND_5_GHZ,
+                WifiConfigurationTestUtil.createOpenNetwork());
+        assertTrue(WifiConfigurationUtil.validateNetworkSpecifier(specifier));
+    }
+
+
+    /**
      * Verify that the validate method fails to validate WifiNetworkSpecifier with no
      * ssid/bssid info.
      */
@@ -648,6 +668,7 @@
         WifiNetworkSpecifier specifier = new WifiNetworkSpecifier(
                 new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB),
                 Pair.create(WifiManager.ALL_ZEROS_MAC_ADDRESS, WifiManager.ALL_ZEROS_MAC_ADDRESS),
+                ScanResult.UNSPECIFIED,
                 WifiConfigurationTestUtil.createOpenNetwork());
         assertFalse(WifiConfigurationUtil.validateNetworkSpecifier(specifier));
     }
@@ -661,6 +682,7 @@
         WifiNetworkSpecifier specifier = new WifiNetworkSpecifier(
                 new PatternMatcher("", PatternMatcher.PATTERN_LITERAL),
                 Pair.create(WifiManager.ALL_ZEROS_MAC_ADDRESS, WifiManager.ALL_ZEROS_MAC_ADDRESS),
+                ScanResult.UNSPECIFIED,
                 WifiConfigurationTestUtil.createOpenNetwork());
         assertFalse(WifiConfigurationUtil.validateNetworkSpecifier(specifier));
     }
@@ -674,6 +696,7 @@
         WifiNetworkSpecifier specifier = new WifiNetworkSpecifier(
                 new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL),
                 Pair.create(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS),
+                ScanResult.UNSPECIFIED,
                 WifiConfigurationTestUtil.createOpenNetwork());
         assertFalse(WifiConfigurationUtil.validateNetworkSpecifier(specifier));
     }
@@ -687,6 +710,7 @@
         WifiNetworkSpecifier specifier = new WifiNetworkSpecifier(
                 new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL),
                 Pair.create(MacAddress.fromString(TEST_BSSID), WifiManager.ALL_ZEROS_MAC_ADDRESS),
+                ScanResult.UNSPECIFIED,
                 WifiConfigurationTestUtil.createOpenNetwork());
         assertFalse(WifiConfigurationUtil.validateNetworkSpecifier(specifier));
     }
@@ -700,11 +724,25 @@
         WifiNetworkSpecifier specifier = new WifiNetworkSpecifier(
                 new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_PREFIX),
                 Pair.create(WifiManager.ALL_ZEROS_MAC_ADDRESS, WifiManager.ALL_ZEROS_MAC_ADDRESS),
+                ScanResult.UNSPECIFIED,
                 WifiConfigurationTestUtil.createOpenHiddenNetwork());
         assertFalse(WifiConfigurationUtil.validateNetworkSpecifier(specifier));
     }
 
     /**
+     * Verify that the validate method fails to validate WifiNetworkSpecifier with an invalid band.
+     */
+    @Test
+    public void testValidateNetworkSpecifierNegativeCases_InvalidBand() {
+        WifiNetworkSpecifier specifier = new WifiNetworkSpecifier(
+                new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL),
+                Pair.create(MacAddress.fromString(TEST_BSSID), MacAddress.BROADCAST_ADDRESS),
+                42,  // invalid
+                WifiConfigurationTestUtil.createOpenNetwork());
+        assertFalse(WifiConfigurationUtil.validateNetworkSpecifier(specifier));
+    }
+
+    /**
      * Verify the instance of {@link android.net.wifi.WifiScanner.PnoSettings.PnoNetwork} created
      * for an open network using {@link WifiConfigurationUtil#createPnoNetwork(
      * WifiConfiguration)}.
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
index fa27119..880037b 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
@@ -363,6 +363,25 @@
     }
 
     /**
+     * Validates that requests that specify a frequency band are rejected.
+     */
+    @Test
+    public void testHandleAcceptNetworkRequestWithBand() throws Exception {
+        WifiNetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
+                .setBand(ScanResult.WIFI_BAND_5_GHZ)
+                .build();
+        mNetworkCapabilities.setNetworkSpecifier(specifier);
+        mNetworkRequest = new NetworkRequest.Builder()
+                .setCapabilities(mNetworkCapabilities)
+                .build();
+
+        // request should be rejected and released.
+        assertFalse(mWifiNetworkFactory.acceptRequest(mNetworkRequest));
+        mLooper.dispatchAll();
+        verify(mConnectivityManager).declareNetworkRequestUnfulfillable(any());
+    }
+
+    /**
      * Validates handling of acceptNetwork with a network specifier with invalid uid/package name.
      */
     @Test
@@ -3432,7 +3451,8 @@
         mNetworkCapabilities.setRequestorUid(uid);
         mNetworkCapabilities.setRequestorPackageName(packageName);
         mNetworkCapabilities.setNetworkSpecifier(
-                new WifiNetworkSpecifier(ssidPatternMatch, bssidPatternMatch, wifiConfiguration));
+                new WifiNetworkSpecifier(ssidPatternMatch, bssidPatternMatch,
+                        ScanResult.UNSPECIFIED, wifiConfiguration));
         mNetworkRequest = new NetworkRequest.Builder()
                 .setCapabilities(mNetworkCapabilities)
                 .build();