Merge "wifi: Use SoftApConfiguration to replace WifiConfiguration for SoftAp"
diff --git a/api/system-current.txt b/api/system-current.txt
index 0e8981d..189585e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5276,18 +5276,30 @@
public final class SoftApConfiguration implements android.os.Parcelable {
method public int describeContents();
+ method public int getBand();
method @Nullable public android.net.MacAddress getBssid();
+ method public int getChannel();
+ method public int getSecurityType();
method @Nullable public String getSsid();
method @Nullable public String getWpa2Passphrase();
+ method public boolean isHiddenSsid();
method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int BAND_2GHZ = 0; // 0x0
+ field public static final int BAND_5GHZ = 1; // 0x1
+ field public static final int BAND_ANY = -1; // 0xffffffff
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApConfiguration> CREATOR;
+ field public static final int SECURITY_TYPE_OPEN = 0; // 0x0
+ field public static final int SECURITY_TYPE_WPA2_PSK = 1; // 0x1
}
public static final class SoftApConfiguration.Builder {
ctor public SoftApConfiguration.Builder();
ctor public SoftApConfiguration.Builder(@NonNull android.net.wifi.SoftApConfiguration);
method @NonNull public android.net.wifi.SoftApConfiguration build();
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBand(int);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setSsid(@Nullable String);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setWpa2Passphrase(@Nullable String);
}
@@ -5467,8 +5479,9 @@
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(@Nullable java.util.List<android.net.wifi.ScanResult>);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
method public int getVerboseLoggingLevel();
- method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
method public boolean isApMacRandomizationSupported();
method public boolean isConnectedMacRandomizationSupported();
@@ -5486,17 +5499,20 @@
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.TrafficStateCallback);
method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreBackupData(@NonNull byte[]);
+ method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSoftApBackupData(@NonNull byte[]);
method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSupplicantBackupData(@NonNull byte[], @NonNull byte[]);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveBackupData();
+ method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
- method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startLocalOnlyHotspot(@NonNull android.net.wifi.SoftApConfiguration, @Nullable java.util.concurrent.Executor, @Nullable android.net.wifi.WifiManager.LocalOnlyHotspotCallback);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public boolean startScan(android.os.WorkSource);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startSoftAp(@Nullable android.net.wifi.WifiConfiguration);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startSubscriptionProvisioning(@NonNull android.net.wifi.hotspot2.OsuProvider, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.hotspot2.ProvisioningCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startTetheredHotspot(@Nullable android.net.wifi.SoftApConfiguration);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopEasyConnectSession();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean stopSoftAp();
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterNetworkRequestMatchCallback(@NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 4a89c66..032f66a 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -142,6 +142,8 @@
boolean startSoftAp(in WifiConfiguration wifiConfig);
+ boolean startTetheredHotspot(in SoftApConfiguration softApConfig);
+
boolean stopSoftAp();
int startLocalOnlyHotspot(in ILocalOnlyHotspotCallback callback, String packageName,
@@ -159,8 +161,14 @@
@UnsupportedAppUsage
WifiConfiguration getWifiApConfiguration();
+ SoftApConfiguration getSoftApConfiguration();
+
boolean setWifiApConfiguration(in WifiConfiguration wifiConfig, String packageName);
+ boolean setSoftApConfiguration(in SoftApConfiguration softApConfig, String packageName);
+
+ void notifyUserOfApBandConversion(String packageName);
+
void enableTdls(String remoteIPAddress, boolean enable);
void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable);
@@ -184,6 +192,10 @@
void restoreBackupData(in byte[] data);
+ byte[] retrieveSoftApBackupData();
+
+ void restoreSoftApBackupData(in byte[] data);
+
void restoreSupplicantBackupData(in byte[] supplicantData, in byte[] ipConfigData);
void startSubscriptionProvisioning(in OsuProvider provider, in IProvisioningCallback callback);
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index 4cc8653..8030bd6 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -16,28 +16,34 @@
package android.net.wifi;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.MacAddress;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.concurrent.Executor;
/**
- * WiFi configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot).
+ * Configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot).
*
* This is input for the framework provided by a client app, i.e. it exposes knobs to instruct the
- * framework how it should open a hotspot. It is not meant to describe the network as it will be
- * seen by clients; this role is currently served by {@link WifiConfiguration} (see
- * {@link WifiManager.LocalOnlyHotspotReservation#getWifiConfiguration()}).
+ * framework how it should configure a hotspot.
*
- * System apps can use this to configure a local-only hotspot using
+ * System apps can use this to configure a tethered hotspot using
+ * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} and
+ * {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)}
+ * or local-only hotspot using
* {@link WifiManager#startLocalOnlyHotspot(SoftApConfiguration, Executor,
* WifiManager.LocalOnlyHotspotCallback)}.
*
@@ -48,25 +54,106 @@
*/
@SystemApi
public final class SoftApConfiguration implements Parcelable {
+
+ /**
+ * 2GHz band.
+ * @hide
+ */
+ @SystemApi
+ public static final int BAND_2GHZ = 0;
+
+ /**
+ * 5GHz band.
+ * @hide
+ */
+ @SystemApi
+ public static final int BAND_5GHZ = 1;
+
+ /**
+ * Device is allowed to choose the optimal band (2Ghz or 5Ghz) based on device capability,
+ * operating country code and current radio conditions.
+ * @hide
+ */
+ @SystemApi
+ public static final int BAND_ANY = -1;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "BAND_TYPE_" }, value = {
+ BAND_2GHZ,
+ BAND_5GHZ,
+ BAND_ANY,
+ })
+ public @interface BandType {}
+
/**
* SSID for the AP, or null for a framework-determined SSID.
*/
private final @Nullable String mSsid;
+
/**
* BSSID for the AP, or null to use a framework-determined BSSID.
*/
private final @Nullable MacAddress mBssid;
+
/**
* Pre-shared key for WPA2-PSK encryption (non-null enables WPA2-PSK).
*/
private final @Nullable String mWpa2Passphrase;
+ /**
+ * This is a network that does not broadcast its SSID, so an
+ * SSID-specific probe request must be used for scans.
+ */
+ private final boolean mHiddenSsid;
+
+ /**
+ * The operating band of the AP.
+ * One of the band types from {@link @BandType}.
+ */
+ private final @BandType int mBand;
+
+ /**
+ * The operating channel of the AP.
+ */
+ private final int mChannel;
+
+ /**
+ * The operating security type of the AP.
+ * One of the security types from {@link @SecurityType}
+ */
+ private final @SecurityType int mSecurityType;
+
+ /**
+ * Security types we support.
+ */
+ /** @hide */
+ @SystemApi
+ public static final int SECURITY_TYPE_OPEN = 0;
+
+ /** @hide */
+ @SystemApi
+ public static final int SECURITY_TYPE_WPA2_PSK = 1;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "SECURITY_TYPE" }, value = {
+ SECURITY_TYPE_OPEN,
+ SECURITY_TYPE_WPA2_PSK,
+ })
+ public @interface SecurityType {}
+
/** Private constructor for Builder and Parcelable implementation. */
- private SoftApConfiguration(
- @Nullable String ssid, @Nullable MacAddress bssid, String wpa2Passphrase) {
+ private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid,
+ @Nullable String wpa2Passphrase, boolean hiddenSsid, @BandType int band, int channel,
+ @SecurityType int securityType) {
mSsid = ssid;
mBssid = bssid;
mWpa2Passphrase = wpa2Passphrase;
+ mHiddenSsid = hiddenSsid;
+ mBand = band;
+ mChannel = channel;
+ mSecurityType = securityType;
}
@Override
@@ -80,12 +167,31 @@
SoftApConfiguration other = (SoftApConfiguration) otherObj;
return Objects.equals(mSsid, other.mSsid)
&& Objects.equals(mBssid, other.mBssid)
- && Objects.equals(mWpa2Passphrase, other.mWpa2Passphrase);
+ && Objects.equals(mWpa2Passphrase, other.mWpa2Passphrase)
+ && mHiddenSsid == other.mHiddenSsid
+ && mBand == other.mBand
+ && mChannel == other.mChannel
+ && mSecurityType == other.mSecurityType;
}
@Override
public int hashCode() {
- return Objects.hash(mSsid, mBssid, mWpa2Passphrase);
+ return Objects.hash(mSsid, mBssid, mWpa2Passphrase, mHiddenSsid,
+ mBand, mChannel, mSecurityType);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sbuf = new StringBuilder();
+ sbuf.append("ssid=").append(mSsid);
+ if (mBssid != null) sbuf.append(" \n bssid=").append(mBssid.toString());
+ sbuf.append(" \n Wpa2Passphrase =").append(
+ TextUtils.isEmpty(mWpa2Passphrase) ? "<empty>" : "<non-empty>");
+ sbuf.append(" \n HiddenSsid =").append(mHiddenSsid);
+ sbuf.append(" \n Band =").append(mBand);
+ sbuf.append(" \n Channel =").append(mChannel);
+ sbuf.append(" \n SecurityType=").append(getSecurityType());
+ return sbuf.toString();
}
@Override
@@ -93,6 +199,10 @@
dest.writeString(mSsid);
dest.writeParcelable(mBssid, flags);
dest.writeString(mWpa2Passphrase);
+ dest.writeBoolean(mHiddenSsid);
+ dest.writeInt(mBand);
+ dest.writeInt(mChannel);
+ dest.writeInt(mSecurityType);
}
@Override
@@ -107,7 +217,7 @@
return new SoftApConfiguration(
in.readString(),
in.readParcelable(MacAddress.class.getClassLoader()),
- in.readString());
+ in.readString(), in.readBoolean(), in.readInt(), in.readInt(), in.readInt());
}
@Override
@@ -116,22 +226,68 @@
}
};
+ /**
+ * Return String set to be the SSID for the AP.
+ * {@link #setSsid(String)}.
+ */
@Nullable
public String getSsid() {
return mSsid;
}
+ /**
+ * Returns MAC address set to be BSSID for the AP.
+ * {@link #setBssid(MacAddress)}.
+ */
@Nullable
public MacAddress getBssid() {
return mBssid;
}
+ /**
+ * Returns String set to be passphrase for the WPA2-PSK AP.
+ * {@link #setWpa2Passphrase(String)}.
+ */
@Nullable
public String getWpa2Passphrase() {
return mWpa2Passphrase;
}
/**
+ * Returns Boolean set to be indicate hidden (true: doesn't broadcast its SSID) or
+ * not (false: broadcasts its SSID) for the AP.
+ * {@link #setHiddenSsid(boolean)}.
+ */
+ public boolean isHiddenSsid() {
+ return mHiddenSsid;
+ }
+
+ /**
+ * Returns {@link BandType} set to be the band for the AP.
+ * {@link #setBand(@BandType int)}.
+ */
+ public @BandType int getBand() {
+ return mBand;
+ }
+
+ /**
+ * Returns Integer set to be the channel for the AP.
+ * {@link #setChannel(int)}.
+ */
+ public int getChannel() {
+ return mChannel;
+ }
+
+ /**
+ * Get security type params which depends on which security passphrase to set.
+ *
+ * @return One of the security types from {@link SecurityType}.
+ */
+ public @SecurityType int getSecurityType() {
+ return mSecurityType;
+ }
+
+ /**
* Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a
* Soft AP.
*
@@ -142,6 +298,21 @@
private String mSsid;
private MacAddress mBssid;
private String mWpa2Passphrase;
+ private boolean mHiddenSsid;
+ private int mBand;
+ private int mChannel;
+
+ private int setSecurityType() {
+ int securityType = SECURITY_TYPE_OPEN;
+ if (!TextUtils.isEmpty(mWpa2Passphrase)) { // WPA2-PSK network.
+ securityType = SECURITY_TYPE_WPA2_PSK;
+ }
+ return securityType;
+ }
+
+ private void clearAllPassphrase() {
+ mWpa2Passphrase = null;
+ }
/**
* Constructs a Builder with default values (see {@link Builder}).
@@ -150,6 +321,9 @@
mSsid = null;
mBssid = null;
mWpa2Passphrase = null;
+ mHiddenSsid = false;
+ mBand = BAND_2GHZ;
+ mChannel = 0;
}
/**
@@ -161,6 +335,9 @@
mSsid = other.mSsid;
mBssid = other.mBssid;
mWpa2Passphrase = other.mWpa2Passphrase;
+ mHiddenSsid = other.mHiddenSsid;
+ mBand = other.mBand;
+ mChannel = other.mChannel;
}
/**
@@ -170,11 +347,16 @@
*/
@NonNull
public SoftApConfiguration build() {
- return new SoftApConfiguration(mSsid, mBssid, mWpa2Passphrase);
+ return new SoftApConfiguration(mSsid, mBssid, mWpa2Passphrase,
+ mHiddenSsid, mBand, mChannel, setSecurityType());
}
/**
* Specifies an SSID for the AP.
+ * <p>
+ * Null SSID only support when configure a local-only hotspot.
+ * <p>
+ * <li>If not set, defaults to null.</li>
*
* @param ssid SSID of valid Unicode characters, or null to have the SSID automatically
* chosen by the framework.
@@ -193,7 +375,10 @@
/**
* Specifies a BSSID for the AP.
- *
+ * <p>
+ * Only supported when configuring a local-only hotspot.
+ * <p>
+ * <li>If not set, defaults to null.</li>
* @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is
* responsible for avoiding collisions.
* @return Builder for chaining.
@@ -211,8 +396,9 @@
}
/**
- * Specifies that this AP should use WPA2-PSK with the given passphrase. When set to null
- * and no other encryption method is configured, an open network is created.
+ * Specifies that this AP should use WPA2-PSK with the given ASCII WPA2 passphrase.
+ * When set to null, an open network is created.
+ * <p>
*
* @param passphrase The passphrase to use, or null to unset a previously-set WPA2-PSK
* configuration.
@@ -222,10 +408,72 @@
@NonNull
public Builder setWpa2Passphrase(@Nullable String passphrase) {
if (passphrase != null) {
+ final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
+ if (!asciiEncoder.canEncode(passphrase)) {
+ throw new IllegalArgumentException("passphrase not ASCII encodable");
+ }
Preconditions.checkStringNotEmpty(passphrase);
}
+ clearAllPassphrase();
mWpa2Passphrase = passphrase;
return this;
}
+
+ /**
+ * Specifies whether the AP is hidden (doesn't broadcast its SSID) or
+ * not (broadcasts its SSID).
+ * <p>
+ * <li>If not set, defaults to false (i.e not a hidden network).</li>
+ *
+ * @param hiddenSsid true for a hidden SSID, false otherwise.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setHiddenSsid(boolean hiddenSsid) {
+ mHiddenSsid = hiddenSsid;
+ return this;
+ }
+
+ /**
+ * Specifies the band for the AP.
+ * <p>
+ * <li>If not set, defaults to BAND_2GHZ {@link @BandType}.</li>
+ *
+ * @param band One of the band types from {@link @BandType}.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setBand(@BandType int band) {
+ switch (band) {
+ case BAND_2GHZ:
+ break;
+ case BAND_5GHZ:
+ break;
+ case BAND_ANY:
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid band type");
+ }
+ mBand = band;
+ return this;
+ }
+
+ /**
+ * Specifies the channel for the AP.
+ *
+ * The channel which AP resides on. Valid channels are country dependent.
+ * Use the special channel value 0 to have the framework auto-select a valid channel
+ * from the band configured with {@link #setBand(@BandType int)}.
+ *
+ * <p>
+ * <li>If not set, defaults to 0.</li>
+ * @param channel operating channel of the AP.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setChannel(int channel) {
+ mChannel = channel;
+ return this;
+ }
}
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index bf609d7..e2e6728 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2739,7 +2739,6 @@
*
* @hide
*/
- @SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STACK,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
@@ -2753,6 +2752,31 @@
}
/**
+ * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
+ * Note that starting Soft AP mode may disable station mode operation if the device does not
+ * support concurrency.
+ * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP,
+ * or null to use the persisted Soft AP configuration that was previously
+ * set using {@link #setSoftApConfiguration(softApConfiguration)}.
+ * @return {@code true} if the operation succeeded, {@code false} otherwise
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
+ public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
+ try {
+ return mService.startTetheredHotspot(softApConfig);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+
+ /**
* Stop SoftAp mode.
* Note that stopping softap mode will restore the previous wifi mode.
* @return {@code true} if the operation succeeds, {@code false} otherwise
@@ -3036,10 +3060,12 @@
* Gets the Wi-Fi AP Configuration.
* @return AP details in WifiConfiguration
*
+ * @deprecated This API is deprecated. Use {@link #getSoftApConfiguration()} instead.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
+ @Deprecated
public WifiConfiguration getWifiApConfiguration() {
try {
return mService.getWifiApConfiguration();
@@ -3049,17 +3075,56 @@
}
/**
- * Sets the Wi-Fi AP Configuration. The AP configuration must either be open or
- * WPA2 PSK networks.
+ * Gets the Wi-Fi AP Configuration.
+ * @return AP details in {@link SoftApConfiguration}
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
+ public SoftApConfiguration getSoftApConfiguration() {
+ try {
+ return mService.getSoftApConfiguration();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets the Wi-Fi AP Configuration.
+ * @return {@code true} if the operation succeeded, {@code false} otherwise
+ *
+ * @deprecated This API is deprecated. Use {@link #setSoftApConfiguration(SoftApConfiguration)}
+ * instead.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
+ @Deprecated
+ public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
+ try {
+ return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets the Wi-Fi AP Configuration.
+ *
+ * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP.
+
* @return {@code true} if the operation succeeded, {@code false} otherwise
*
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
- public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public boolean setSoftApConfiguration(@NonNull SoftApConfiguration softApConfig) {
try {
- return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
+ return mService.setSoftApConfiguration(
+ softApConfig, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4548,6 +4613,36 @@
}
/**
+ * Retrieve the soft ap config data to be backed to save current config data.
+ * @hide
+ */
+ @Nullable
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public byte[] retrieveSoftApBackupData() {
+ try {
+ return mService.retrieveSoftApBackupData();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Restore soft ap config from the backed up data.
+ * @hide
+ */
+ @Nullable
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void restoreSoftApBackupData(@NonNull byte[] data) {
+ try {
+ mService.restoreSoftApBackupData(data);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Restore state from the older version of back up data.
* The old backup data was essentially a backup of wpa_supplicant.conf
* and ipconfig.txt file.
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 534e609..bc86839 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -285,6 +285,11 @@
}
@Override
+ public boolean startTetheredHotspot(SoftApConfiguration softApConfig) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean stopSoftAp() {
throw new UnsupportedOperationException();
}
@@ -321,10 +326,21 @@
}
@Override
+ public SoftApConfiguration getSoftApConfiguration() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) {
throw new UnsupportedOperationException();
}
+ @Override
+ public boolean setSoftApConfiguration(SoftApConfiguration softApConfig, String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void notifyUserOfApBandConversion(String packageName) {
throw new UnsupportedOperationException();
}
@@ -385,6 +401,16 @@
}
@Override
+ public byte[] retrieveSoftApBackupData() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void restoreSoftApBackupData(byte[] data) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
throw new UnsupportedOperationException();
}
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
index 949b479..b8d3e41 100644
--- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -46,6 +46,10 @@
assertThat(original.getSsid()).isEqualTo("ssid");
assertThat(original.getBssid()).isEqualTo(MacAddress.fromString("11:22:33:44:55:66"));
assertThat(original.getWpa2Passphrase()).isNull();
+ assertThat(original.getSecurityType()).isEqualTo(SoftApConfiguration.SECURITY_TYPE_OPEN);
+ assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
+ assertThat(original.getChannel()).isEqualTo(0);
+ assertThat(original.isHiddenSsid()).isEqualTo(false);
SoftApConfiguration unparceled = parcelUnparcel(original);
assertThat(unparceled).isNotSameAs(original);
@@ -64,6 +68,39 @@
.setWpa2Passphrase("secretsecret")
.build();
assertThat(original.getWpa2Passphrase()).isEqualTo("secretsecret");
+ assertThat(original.getSecurityType()).isEqualTo(
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
+ assertThat(original.getChannel()).isEqualTo(0);
+ assertThat(original.isHiddenSsid()).isEqualTo(false);
+
+
+ SoftApConfiguration unparceled = parcelUnparcel(original);
+ assertThat(unparceled).isNotSameAs(original);
+ assertThat(unparceled).isEqualTo(original);
+ assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
+
+ SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
+ assertThat(copy).isNotSameAs(original);
+ assertThat(copy).isEqualTo(original);
+ assertThat(copy.hashCode()).isEqualTo(original.hashCode());
+ }
+
+ @Test
+ public void testWpa2WithBandAndChannelAndHiddenNetwork() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setWpa2Passphrase("secretsecret")
+ .setBand(SoftApConfiguration.BAND_ANY)
+ .setChannel(149)
+ .setHiddenSsid(true)
+ .build();
+ assertThat(original.getWpa2Passphrase()).isEqualTo("secretsecret");
+ assertThat(original.getSecurityType()).isEqualTo(
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_ANY);
+ assertThat(original.getChannel()).isEqualTo(149);
+ assertThat(original.isHiddenSsid()).isEqualTo(true);
+
SoftApConfiguration unparceled = parcelUnparcel(original);
assertThat(unparceled).isNotSameAs(original);
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 8b68bb4..d22dbd3 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -181,6 +181,33 @@
}
/**
+ * Check the call to startSoftAp calls WifiService to startSoftAp with the provided
+ * WifiConfiguration. Verify that the return value is propagated to the caller.
+ */
+ @Test
+ public void testStartTetheredHotspotCallsServiceWithSoftApConfig() throws Exception {
+ SoftApConfiguration mSoftApConfig = new SoftApConfiguration.Builder().build();
+ when(mWifiService.startTetheredHotspot(eq(mSoftApConfig))).thenReturn(true);
+ assertTrue(mWifiManager.startTetheredHotspot(mSoftApConfig));
+
+ when(mWifiService.startTetheredHotspot(eq(mSoftApConfig))).thenReturn(false);
+ assertFalse(mWifiManager.startTetheredHotspot(mSoftApConfig));
+ }
+
+ /**
+ * Check the call to startSoftAp calls WifiService to startSoftAp with a null config. Verify
+ * that the return value is propagated to the caller.
+ */
+ @Test
+ public void testStartTetheredHotspotCallsServiceWithNullConfig() throws Exception {
+ when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(true);
+ assertTrue(mWifiManager.startTetheredHotspot(null));
+
+ when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(false);
+ assertFalse(mWifiManager.startTetheredHotspot(null));
+ }
+
+ /**
* Test creation of a LocalOnlyHotspotReservation and verify that close properly calls
* WifiService.stopLocalOnlyHotspot.
*/
@@ -1148,6 +1175,43 @@
}
/**
+ * Verify that a successful call properly returns true.
+ */
+ @Test
+ public void testSetSoftApConfigurationSuccessReturnsTrue() throws Exception {
+ SoftApConfiguration apConfig = new SoftApConfiguration.Builder().build();
+
+ when(mWifiService.setSoftApConfiguration(eq(apConfig), eq(TEST_PACKAGE_NAME)))
+ .thenReturn(true);
+ assertTrue(mWifiManager.setSoftApConfiguration(apConfig));
+ }
+
+ /**
+ * Verify that a failed call properly returns false.
+ */
+ @Test
+ public void testSetSoftApConfigurationFailureReturnsFalse() throws Exception {
+ SoftApConfiguration apConfig = new SoftApConfiguration.Builder().build();
+
+ when(mWifiService.setSoftApConfiguration(eq(apConfig), eq(TEST_PACKAGE_NAME)))
+ .thenReturn(false);
+ assertFalse(mWifiManager.setSoftApConfiguration(apConfig));
+ }
+
+ /**
+ * Verify Exceptions are rethrown when underlying calls to WifiService throw exceptions.
+ */
+ @Test
+ public void testSetSoftApConfigurationRethrowsException() throws Exception {
+ doThrow(new SecurityException()).when(mWifiService).setSoftApConfiguration(any(), any());
+
+ try {
+ mWifiManager.setSoftApConfiguration(new SoftApConfiguration.Builder().build());
+ fail("setWifiApConfiguration should rethrow Exceptions from WifiService");
+ } catch (SecurityException e) { }
+ }
+
+ /**
* Check the call to startScan calls WifiService.
*/
@Test