wifi: Add features in SoftApCapability

Caller can get hotspot feature list from SoftApCapability

Bug: 142752869
Test: atest frameworks/base/wifi/tests/
Change-Id: I31fea5c42eab092a838c08b328903d71c720090d
diff --git a/framework/java/android/net/wifi/SoftApCapability.java b/framework/java/android/net/wifi/SoftApCapability.java
index 506f493..c4474e2 100644
--- a/framework/java/android/net/wifi/SoftApCapability.java
+++ b/framework/java/android/net/wifi/SoftApCapability.java
@@ -16,12 +16,15 @@
 
 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;
 
 /**
@@ -33,6 +36,41 @@
 @SystemApi
 public final class SoftApCapability implements Parcelable {
 
+    /**
+     * Support for automatic channel selection in driver (ACS).
+     * Driver will auto select best channel based on interference to optimize performance.
+     *
+     * flag when {@link R.bool.config_wifi_softap_acs_supported)} is true.
+     *
+     * <p>
+     * Use {@link WifiManager.SoftApCallback#onInfoChanged(SoftApInfo)} and
+     * {@link SoftApInfo#getFrequency} and {@link SoftApInfo#getBandwidth} to get
+     * driver channel selection result.
+     */
+    public static final int SOFTAP_FEATURE_ACS_OFFLOAD = 1 << 0;
+
+    /**
+     * Support for client force disconnect.
+     * flag when {@link R.bool.config_wifi_sofap_client_force_disconnect_supported)} is true
+     *
+     * <p>
+     * Several Soft AP client control features, e.g. specifying the maximum number of
+     * Soft AP clients, only work when this feature support is present.
+     * Check feature support before invoking
+     * {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)}
+     */
+    public static final int SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 1 << 1;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = { "SOFTAP_FEATURE_" }, value = {
+            SOFTAP_FEATURE_ACS_OFFLOAD,
+            SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT,
+    })
+    public @interface HotspotFeatures {}
+
+    private @HotspotFeatures int mSupportedFeatures = 0;
+
     private int mMaximumSupportedClientNumber;
 
     /**
@@ -44,6 +82,8 @@
 
     /**
      * Set the maximum supported client numbers which AP resides on.
+     *
+     * @param maxClient maximum supported client numbers for the softap.
      * @hide
      */
     public void setMaxSupportedClients(int maxClient) {
@@ -51,18 +91,33 @@
     }
 
     /**
-     * @hide
+     * Returns true when feature supported, otherwise false.
+     *
+     * @param feature one of feature from {@link HotspotFeatures}
      */
-    public SoftApCapability(@Nullable SoftApCapability source) {
-        if (source != null) {
-            mMaximumSupportedClientNumber = source.mMaximumSupportedClientNumber;
-        }
+    public boolean isFeatureSupported(@HotspotFeatures int feature) {
+        return (mSupportedFeatures & feature) == feature;
     }
 
     /**
      * @hide
      */
-    public SoftApCapability() {
+    public SoftApCapability(@Nullable SoftApCapability source) {
+        if (source != null) {
+            mSupportedFeatures = source.mSupportedFeatures;
+            mMaximumSupportedClientNumber = source.mMaximumSupportedClientNumber;
+        }
+    }
+
+    /**
+     * Constructor with combination of the feature.
+     * Zero to no supported feature.
+     *
+     * @param features One or combination of the feature from {@link @HotspotFeatures}.
+     * @hide
+     */
+    public SoftApCapability(@HotspotFeatures int features) {
+        mSupportedFeatures = features;
     }
 
     @Override
@@ -74,6 +129,7 @@
     @Override
     /** Implement the Parcelable interface */
     public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mSupportedFeatures);
         dest.writeInt(mMaximumSupportedClientNumber);
     }
 
@@ -81,7 +137,8 @@
     /** Implement the Parcelable interface */
     public static final Creator<SoftApCapability> CREATOR = new Creator<SoftApCapability>() {
         public SoftApCapability createFromParcel(Parcel in) {
-            SoftApCapability capability = new SoftApCapability();
+            int supportedFeatures = in.readInt();
+            SoftApCapability capability = new SoftApCapability(supportedFeatures);
             capability.mMaximumSupportedClientNumber = in.readInt();
             return capability;
         }
@@ -95,6 +152,7 @@
     @Override
     public String toString() {
         StringBuilder sbuf = new StringBuilder();
+        sbuf.append("SupportedFeatures=").append(mSupportedFeatures);
         sbuf.append("MaximumSupportedClientNumber=").append(mMaximumSupportedClientNumber);
         return sbuf.toString();
     }
@@ -104,11 +162,12 @@
         if (this == o) return true;
         if (!(o instanceof SoftApCapability)) return false;
         SoftApCapability capability = (SoftApCapability) o;
-        return mMaximumSupportedClientNumber == capability.mMaximumSupportedClientNumber;
+        return mSupportedFeatures == capability.mSupportedFeatures
+                && mMaximumSupportedClientNumber == capability.mMaximumSupportedClientNumber;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mMaximumSupportedClientNumber);
+        return Objects.hash(mSupportedFeatures, mMaximumSupportedClientNumber);
     }
 }
diff --git a/framework/java/android/net/wifi/SoftApConfiguration.java b/framework/java/android/net/wifi/SoftApConfiguration.java
index cd2826b..05e245b 100644
--- a/framework/java/android/net/wifi/SoftApConfiguration.java
+++ b/framework/java/android/net/wifi/SoftApConfiguration.java
@@ -523,9 +523,16 @@
          * Specifies the channel and associated band for the AP.
          *
          * The channel which AP resides on. Valid channels are country dependent.
+         * <p>
          * The default for the channel is a the special value 0 to have the framework
          * auto-select a valid channel from the band configured with
          * {@link #setBand(@BandType int)}.
+         *
+         * The channel auto selection will offload to driver when
+         * {@link SoftApCapability#isFeatureSupported(SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD)}
+         * return true. Driver will auto select best channel which based on environment
+         * interference to get best performance. Check {@link SoftApCapability} to get more detail.
+         *
          * Note, since 6GHz band use the same channel numbering of 2.4GHz and 5GHZ bands,
          * the caller needs to pass the band containing the selected channel.
          *
@@ -565,6 +572,12 @@
          * {@link WifiManager#startTetheredHotspot} will report error code
          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
          *
+         * <p>
+         * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
+         * {@link SoftApCapability#isFeatureSupported(int)}
+         * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} to determine whether
+         * or not this feature is supported.
+         *
          * @param maxNumberOfClients maximum client number of the AP.
          * @return Builder for chaining.
          */
diff --git a/framework/tests/src/android/net/wifi/SoftApCapabilityTest.java b/framework/tests/src/android/net/wifi/SoftApCapabilityTest.java
index 9cb221d..ef476eb 100644
--- a/framework/tests/src/android/net/wifi/SoftApCapabilityTest.java
+++ b/framework/tests/src/android/net/wifi/SoftApCapabilityTest.java
@@ -35,7 +35,9 @@
      */
     @Test
     public void testCopyOperator() throws Exception {
-        SoftApCapability capability = new SoftApCapability();
+        int testSoftApFeature = SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT
+                | SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD;
+        SoftApCapability capability = new SoftApCapability(testSoftApFeature);
         capability.setMaxSupportedClients(10);
 
         SoftApCapability copiedCapability = new SoftApCapability(capability);
@@ -49,7 +51,9 @@
      */
     @Test
     public void testParcelOperation() throws Exception {
-        SoftApCapability capability = new SoftApCapability();
+        int testSoftApFeature = SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT
+                | SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD;
+        SoftApCapability capability = new SoftApCapability(testSoftApFeature);
         capability.setMaxSupportedClients(10);
 
         Parcel parcelW = Parcel.obtain();
diff --git a/framework/tests/src/android/net/wifi/WifiManagerTest.java b/framework/tests/src/android/net/wifi/WifiManagerTest.java
index d8bc134..f9bd31d 100644
--- a/framework/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/framework/tests/src/android/net/wifi/WifiManagerTest.java
@@ -883,7 +883,7 @@
      */
     @Test
     public void softApCallbackProxyCallsOnCapabilityChanged() throws Exception {
-        SoftApCapability testSoftApCapability = new SoftApCapability();
+        SoftApCapability testSoftApCapability = new SoftApCapability(0);
         testSoftApCapability.setMaxSupportedClients(10);
         ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
@@ -904,7 +904,7 @@
         SoftApInfo testSoftApInfo = new SoftApInfo();
         testSoftApInfo.setFrequency(TEST_AP_FREQUENCY);
         testSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH);
-        SoftApCapability testSoftApCapability = new SoftApCapability();
+        SoftApCapability testSoftApCapability = new SoftApCapability(0);
         testSoftApCapability.setMaxSupportedClients(10);
         ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISoftApCallback.Stub.class);