diff options
| -rw-r--r-- | api/system-current.txt | 22 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/IWifiManager.aidl | 12 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/SoftApConfiguration.java | 276 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/WifiManager.java | 101 | ||||
| -rw-r--r-- | wifi/java/com/android/server/wifi/BaseWifiService.java | 26 | ||||
| -rw-r--r-- | wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java | 37 | ||||
| -rw-r--r-- | wifi/tests/src/android/net/wifi/WifiManagerTest.java | 64 |
7 files changed, 518 insertions, 20 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 5ff6778f64ba..a72e24ba28b8 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5276,18 +5276,30 @@ package android.net.wifi { 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); } @@ -5441,8 +5453,9 @@ package android.net.wifi { 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(); @@ -5460,17 +5473,20 @@ package android.net.wifi { 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 4a89c66dd0a0..032f66af2433 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -142,6 +142,8 @@ interface IWifiManager boolean startSoftAp(in WifiConfiguration wifiConfig); + boolean startTetheredHotspot(in SoftApConfiguration softApConfig); + boolean stopSoftAp(); int startLocalOnlyHotspot(in ILocalOnlyHotspotCallback callback, String packageName, @@ -159,8 +161,14 @@ interface IWifiManager @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 @@ interface IWifiManager 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 4cc86539926c..8030bd66e313 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 @@ import java.util.concurrent.Executor; */ @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 @@ public final class SoftApConfiguration implements Parcelable { 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 @@ public final class SoftApConfiguration implements Parcelable { 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 @@ public final class SoftApConfiguration implements Parcelable { 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 @@ public final class SoftApConfiguration implements Parcelable { } }; + /** + * 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 @@ public final class SoftApConfiguration implements Parcelable { 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 @@ public final class SoftApConfiguration implements Parcelable { mSsid = null; mBssid = null; mWpa2Passphrase = null; + mHiddenSsid = false; + mBand = BAND_2GHZ; + mChannel = 0; } /** @@ -161,6 +335,9 @@ public final class SoftApConfiguration implements Parcelable { mSsid = other.mSsid; mBssid = other.mBssid; mWpa2Passphrase = other.mWpa2Passphrase; + mHiddenSsid = other.mHiddenSsid; + mBand = other.mBand; + mChannel = other.mChannel; } /** @@ -170,11 +347,16 @@ public final class SoftApConfiguration implements Parcelable { */ @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 @@ public final class SoftApConfiguration implements Parcelable { /** * 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 @@ public final class SoftApConfiguration implements Parcelable { } /** - * 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 @@ public final class SoftApConfiguration implements Parcelable { @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 bf609d765502..e2e6728068a9 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -2739,7 +2739,6 @@ public class WifiManager { * * @hide */ - @SystemApi @RequiresPermission(anyOf = { android.Manifest.permission.NETWORK_STACK, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK @@ -2753,6 +2752,31 @@ public class WifiManager { } /** + * 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 @@ public class WifiManager { * 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,14 +3075,33 @@ public class WifiManager { } /** - * 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()); @@ -3066,6 +3111,26 @@ public class WifiManager { } /** + * 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.NETWORK_SETTINGS) + public boolean setSoftApConfiguration(@NonNull SoftApConfiguration softApConfig) { + try { + return mService.setSoftApConfiguration( + softApConfig, mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Enable/Disable TDLS on a specific local route. * * <p> @@ -4548,6 +4613,36 @@ public class WifiManager { } /** + * 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 534e609f9af4..bc8683921321 100644 --- a/wifi/java/com/android/server/wifi/BaseWifiService.java +++ b/wifi/java/com/android/server/wifi/BaseWifiService.java @@ -285,6 +285,11 @@ public class BaseWifiService extends IWifiManager.Stub { } @Override + public boolean startTetheredHotspot(SoftApConfiguration softApConfig) { + throw new UnsupportedOperationException(); + } + + @Override public boolean stopSoftAp() { throw new UnsupportedOperationException(); } @@ -321,10 +326,21 @@ public class BaseWifiService extends IWifiManager.Stub { } @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 @@ public class BaseWifiService extends IWifiManager.Stub { } @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 949b4790d998..b8d3e413f1d2 100644 --- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java @@ -46,6 +46,10 @@ public class SoftApConfigurationTest { 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 @@ public class SoftApConfigurationTest { .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 d326201fa574..ab027b38348e 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -181,6 +181,33 @@ public class WifiManagerTest { } /** + * 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 @@ public class WifiManagerTest { } /** + * 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 |