summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp2
-rwxr-xr-xapi/current.txt47
-rw-r--r--api/system-current.txt16
-rw-r--r--core/java/android/net/MacAddress.java15
-rw-r--r--tests/net/java/android/net/MacAddressTest.java35
-rw-r--r--wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl36
-rw-r--r--wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl31
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl5
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java4
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java417
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java187
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java511
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSpecifier.java181
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSuggestion.java143
-rw-r--r--wifi/tests/src/android/net/wifi/WifiManagerTest.java89
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java453
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java481
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java212
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java146
19 files changed, 2974 insertions, 37 deletions
diff --git a/Android.bp b/Android.bp
index 44f7edd98e0a..65f232d85614 100644
--- a/Android.bp
+++ b/Android.bp
@@ -595,6 +595,8 @@ java_defaults {
"telephony/java/com/android/internal/telephony/euicc/ISetDefaultSmdpAddressCallback.aidl",
"telephony/java/com/android/internal/telephony/euicc/ISetNicknameCallback.aidl",
"telephony/java/com/android/internal/telephony/euicc/ISwitchToProfileCallback.aidl",
+ "wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl",
+ "wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl",
"wifi/java/android/net/wifi/ISoftApCallback.aidl",
"wifi/java/android/net/wifi/ITrafficStateCallback.aidl",
"wifi/java/android/net/wifi/IWifiManager.aidl",
diff --git a/api/current.txt b/api/current.txt
index f387c5d7e11b..dd4c781b6e7b 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -28690,7 +28690,7 @@ package android.net.wifi {
enum_constant public static final android.net.wifi.SupplicantState UNINITIALIZED;
}
- public class WifiConfiguration implements android.os.Parcelable {
+ public deprecated class WifiConfiguration implements android.os.Parcelable {
ctor public WifiConfiguration();
method public int describeContents();
method public android.net.ProxyInfo getHttpProxy();
@@ -28844,7 +28844,8 @@ package android.net.wifi {
}
public class WifiManager {
- method public int addNetwork(android.net.wifi.WifiConfiguration);
+ method public deprecated int addNetwork(android.net.wifi.WifiConfiguration);
+ method public boolean addNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>, android.app.PendingIntent);
method public void addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
method public static int calculateSignalLevel(int, int);
method public deprecated void cancelWps(android.net.wifi.WifiManager.WpsCallback);
@@ -28852,10 +28853,10 @@ package android.net.wifi {
method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(java.lang.String);
method public android.net.wifi.WifiManager.WifiLock createWifiLock(int, java.lang.String);
method public android.net.wifi.WifiManager.WifiLock createWifiLock(java.lang.String);
- method public boolean disableNetwork(int);
- method public boolean disconnect();
- method public boolean enableNetwork(int, boolean);
- method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
+ method public deprecated boolean disableNetwork(int);
+ method public deprecated boolean disconnect();
+ method public deprecated boolean enableNetwork(int, boolean);
+ method public deprecated java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
method public android.net.wifi.WifiInfo getConnectionInfo();
method public android.net.DhcpInfo getDhcpInfo();
method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
@@ -28870,18 +28871,19 @@ package android.net.wifi {
method public boolean isTdlsSupported();
method public boolean isWifiEnabled();
method public deprecated boolean pingSupplicant();
- method public boolean reassociate();
- method public boolean reconnect();
- method public boolean removeNetwork(int);
+ method public deprecated boolean reassociate();
+ method public deprecated boolean reconnect();
+ method public deprecated boolean removeNetwork(int);
+ method public boolean removeNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>);
method public void removePasspointConfiguration(java.lang.String);
method public deprecated boolean saveConfiguration();
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
- method public boolean setWifiEnabled(boolean);
+ method public deprecated boolean setWifiEnabled(boolean);
method public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, android.os.Handler);
method public deprecated boolean startScan();
method public deprecated void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
- method public int updateNetwork(android.net.wifi.WifiConfiguration);
+ method public deprecated int updateNetwork(android.net.wifi.WifiConfiguration);
field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
field public static final deprecated int ERROR_AUTHENTICATING = 1; // 0x1
@@ -28955,6 +28957,29 @@ package android.net.wifi {
method public abstract deprecated void onSucceeded();
}
+ public class WifiNetworkConfigBuilder {
+ ctor public WifiNetworkConfigBuilder();
+ method public android.net.NetworkSpecifier buildNetworkSpecifier();
+ method public android.net.wifi.WifiNetworkSuggestion buildNetworkSuggestion();
+ method public android.net.wifi.WifiNetworkConfigBuilder setBssid(android.net.MacAddress);
+ method public android.net.wifi.WifiNetworkConfigBuilder setBssidPattern(android.net.MacAddress, android.net.MacAddress);
+ method public android.net.wifi.WifiNetworkConfigBuilder setEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
+ method public android.net.wifi.WifiNetworkConfigBuilder setIsAppInteractionRequired();
+ method public android.net.wifi.WifiNetworkConfigBuilder setIsHiddenSsid();
+ method public android.net.wifi.WifiNetworkConfigBuilder setIsMetered();
+ method public android.net.wifi.WifiNetworkConfigBuilder setIsUserInteractionRequired();
+ method public android.net.wifi.WifiNetworkConfigBuilder setPriority(int);
+ method public android.net.wifi.WifiNetworkConfigBuilder setPskPassphrase(java.lang.String);
+ method public android.net.wifi.WifiNetworkConfigBuilder setSsid(java.lang.String);
+ method public android.net.wifi.WifiNetworkConfigBuilder setSsidPattern(android.os.PatternMatcher);
+ }
+
+ public final class WifiNetworkSuggestion implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.WifiNetworkSuggestion> CREATOR;
+ }
+
public deprecated class WpsInfo implements android.os.Parcelable {
ctor public deprecated WpsInfo();
ctor public deprecated WpsInfo(android.net.wifi.WpsInfo);
diff --git a/api/system-current.txt b/api/system-current.txt
index 3074efdc5567..d8da475e3eec 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3615,7 +3615,7 @@ package android.net.wifi {
field public byte id;
}
- public class WifiConfiguration implements android.os.Parcelable {
+ public deprecated class WifiConfiguration implements android.os.Parcelable {
method public boolean hasNoInternetAccess();
method public boolean isEphemeral();
method public boolean isNoInternetAccessExpected();
@@ -3644,8 +3644,10 @@ package android.net.wifi {
method public boolean isPortableHotspotSupported();
method public boolean isWifiApEnabled();
method public boolean isWifiScannerSupported();
+ method public void registerNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback, android.os.Handler);
method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
method public boolean startScan(android.os.WorkSource);
+ method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback);
field public static final int CHANGE_REASON_ADDED = 0; // 0x0
field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
field public static final int CHANGE_REASON_REMOVED = 1; // 0x1
@@ -3673,6 +3675,18 @@ package android.net.wifi {
method public abstract void onSuccess();
}
+ public static abstract interface WifiManager.NetworkRequestMatchCallback {
+ method public abstract void onMatch(java.util.List<android.net.wifi.WifiConfiguration>);
+ method public abstract void onUserSelectionCallbackRegistration(android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback);
+ method public abstract void onUserSelectionConnectFailure(android.net.wifi.WifiConfiguration);
+ method public abstract void onUserSelectionConnectSuccess(android.net.wifi.WifiConfiguration);
+ }
+
+ public static abstract interface WifiManager.NetworkRequestUserSelectionCallback {
+ method public abstract void reject();
+ method public abstract void select(android.net.wifi.WifiConfiguration);
+ }
+
public class WifiNetworkConnectionStatistics implements android.os.Parcelable {
ctor public WifiNetworkConnectionStatistics(int, int);
ctor public WifiNetworkConnectionStatistics();
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 98f356722bf3..4cd000113b7e 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -393,4 +393,19 @@ public final class MacAddress implements Parcelable {
}
return out;
}
+
+ /**
+ * Checks if this MAC Address matches the provided range.
+ *
+ * @param baseAddress MacAddress representing the base address to compare with.
+ * @param mask MacAddress representing the mask to use during comparison.
+ * @return true if this MAC Address matches the given range.
+ *
+ * @hide
+ */
+ public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
+ Preconditions.checkNotNull(baseAddress);
+ Preconditions.checkNotNull(mask);
+ return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr);
+ }
}
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index 04266c5b3a0f..b9222a86a092 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -17,8 +17,8 @@
package android.net;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.support.test.filters.SmallTest;
@@ -252,6 +252,39 @@ public class MacAddressTest {
}
}
+ @Test
+ public void testMatches() {
+ // match 4 bytes prefix
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:00:00"),
+ MacAddress.fromString("ff:ff:ff:ff:00:00")));
+
+ // match bytes 0,1,2 and 5
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:00:00:11"),
+ MacAddress.fromString("ff:ff:ff:00:00:ff")));
+
+ // match 34 bit prefix
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:c0:00"),
+ MacAddress.fromString("ff:ff:ff:ff:c0:00")));
+
+ // fail to match 36 bit prefix
+ assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:40:00"),
+ MacAddress.fromString("ff:ff:ff:ff:f0:00")));
+
+ // match all 6 bytes
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:ee:11"),
+ MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
+
+ // match none of 6 bytes
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("00:00:00:00:00:00"),
+ MacAddress.fromString("00:00:00:00:00:00")));
+ }
+
static byte[] toByteArray(int... in) {
byte[] out = new byte[in.length];
for (int i = 0; i < in.length; i++) {
diff --git a/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl b/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl
new file mode 100644
index 000000000000..f472a021b031
--- /dev/null
+++ b/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.net.wifi.INetworkRequestUserSelectionCallback;
+import android.net.wifi.WifiConfiguration;
+
+/**
+ * Interface for network request match callback.
+ *
+ * @hide
+ */
+oneway interface INetworkRequestMatchCallback
+{
+ void onUserSelectionCallbackRegistration(in INetworkRequestUserSelectionCallback userSelectionCallback);
+
+ void onMatch(in List<WifiConfiguration> wificonfigurations);
+
+ void onUserSelectionConnectSuccess(in WifiConfiguration wificonfiguration);
+
+ void onUserSelectionConnectFailure(in WifiConfiguration wificonfiguration);
+}
diff --git a/wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl b/wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl
new file mode 100644
index 000000000000..524cefbb295f
--- /dev/null
+++ b/wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.net.wifi.WifiConfiguration;
+
+/**
+ * Interface for providing user selection in response to
+ * network request match callback.
+ * @hide
+ */
+oneway interface INetworkRequestUserSelectionCallback
+{
+ void select(in WifiConfiguration wificonfiguration);
+
+ void reject();
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 12f50c8af8a9..1fd68ec1df70 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -25,6 +25,7 @@ import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.DhcpInfo;
import android.net.Network;
+import android.net.wifi.INetworkRequestMatchCallback;
import android.net.wifi.ISoftApCallback;
import android.net.wifi.ITrafficStateCallback;
import android.net.wifi.PasspointManagementObjectDefinition;
@@ -185,5 +186,9 @@ interface IWifiManager
void registerTrafficStateCallback(in IBinder binder, in ITrafficStateCallback callback, int callbackIdentifier);
void unregisterTrafficStateCallback(int callbackIdentifier);
+
+ void registerNetworkRequestMatchCallback(in IBinder binder, in INetworkRequestMatchCallback callback, int callbackIdentifier);
+
+ void unregisterNetworkRequestMatchCallback(int callbackIdentifier);
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 03306143872b..05747163550e 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -47,7 +47,11 @@ import java.util.HashMap;
/**
* A class representing a configured Wi-Fi network, including the
* security configuration.
+ *
+ * @deprecated Use {@link WifiNetworkConfigBuilder} to create {@link NetworkSpecifier} and
+ * {@link WifiNetworkSuggestion}. This will become a system use only object in the future.
*/
+@Deprecated
public class WifiConfiguration implements Parcelable {
private static final String TAG = "WifiConfiguration";
/**
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 9adbe67c1553..9ce548601f23 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -25,19 +25,17 @@ import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage;
+import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.hotspot2.ProvisioningCallback;
import android.os.Binder;
-import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -52,7 +50,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
-import com.android.server.net.NetworkPinner;
import dalvik.system.CloseGuard;
@@ -1035,7 +1032,17 @@ public class WifiManager {
* </ul>
* @return a list of network configurations in the form of a list
* of {@link WifiConfiguration} objects.
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return an empty list.
*/
+ @Deprecated
public List<WifiConfiguration> getConfiguredNetworks() {
try {
ParceledListSlice<WifiConfiguration> parceledList =
@@ -1135,7 +1142,17 @@ public class WifiManager {
* @return the ID of the newly created network description. This is used in
* other operations to specified the network to be acted upon.
* Returns {@code -1} on failure.
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code -1}.
*/
+ @Deprecated
public int addNetwork(WifiConfiguration config) {
if (config == null) {
return -1;
@@ -1160,7 +1177,17 @@ public class WifiManager {
* Returns {@code -1} on failure, including when the {@code networkId}
* field of the {@code WifiConfiguration} does not refer to an
* existing network.
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code -1}.
*/
+ @Deprecated
public int updateNetwork(WifiConfiguration config) {
if (config == null || config.networkId < 0) {
return -1;
@@ -1185,6 +1212,302 @@ public class WifiManager {
}
/**
+ * Interface for indicating user selection from the list of networks presented in the
+ * {@link NetworkRequestMatchCallback#onMatch(List)}.
+ *
+ * The platform will implement this callback and pass it along with the
+ * {@link NetworkRequestMatchCallback#onUserSelectionCallbackRegistration(
+ * NetworkRequestUserSelectionCallback)}. The UI component handling
+ * {@link NetworkRequestMatchCallback} will invoke {@link #select(WifiConfiguration)} or
+ * {@link #reject()} to return the user's selection back to the platform via this callback.
+ * @hide
+ */
+ @SystemApi
+ public interface NetworkRequestUserSelectionCallback {
+ /**
+ * User selected this network to connect to.
+ * @param wifiConfiguration WifiConfiguration object corresponding to the network
+ * user selected.
+ */
+ void select(@NonNull WifiConfiguration wifiConfiguration);
+
+ /**
+ * User rejected the app's request.
+ */
+ void reject();
+ }
+
+ /**
+ * Interface for network request callback. Should be implemented by applications and passed when
+ * calling {@link #registerNetworkRequestMatchCallback(NetworkRequestMatchCallback, Handler)}.
+ *
+ * This is meant to be implemented by a UI component to present the user with a list of networks
+ * matching the app's request. The user is allowed to pick one of these networks to connect to
+ * or reject the request by the app.
+ * @hide
+ */
+ @SystemApi
+ public interface NetworkRequestMatchCallback {
+ /**
+ * Invoked to register a callback to be invoked to convey user selection. The callback
+ * object paased in this method is to be invoked by the UI component after the service sends
+ * a list of matching scan networks using {@link #onMatch(List)} and user picks a network
+ * from that list.
+ *
+ * @param userSelectionCallback Callback object to send back the user selection.
+ */
+ void onUserSelectionCallbackRegistration(
+ @NonNull NetworkRequestUserSelectionCallback userSelectionCallback);
+
+ /**
+ * Invoked when a network request initiated by an app matches some networks in scan results.
+ * This may be invoked multiple times for a single network request as the platform finds new
+ * networks in scan results.
+ *
+ * @param wifiConfigurations List of {@link WifiConfiguration} objects corresponding to the
+ * networks matching the request.
+ */
+ void onMatch(@NonNull List<WifiConfiguration> wifiConfigurations);
+
+ /**
+ * Invoked on a successful connection with the network that the user selected
+ * via {@link NetworkRequestUserSelectionCallback}.
+ *
+ * @param wifiConfiguration WifiConfiguration object corresponding to the network that the
+ * user selected.
+ */
+ void onUserSelectionConnectSuccess(@NonNull WifiConfiguration wifiConfiguration);
+
+ /**
+ * Invoked on failure to establish connection with the network that the user selected
+ * via {@link NetworkRequestUserSelectionCallback}.
+ *
+ * @param wifiConfiguration WifiConfiguration object corresponding to the network
+ * user selected.
+ */
+ void onUserSelectionConnectFailure(@NonNull WifiConfiguration wifiConfiguration);
+ }
+
+ /**
+ * Callback proxy for NetworkRequestUserSelectionCallback objects.
+ * @hide
+ */
+ private class NetworkRequestUserSelectionCallbackProxy implements
+ NetworkRequestUserSelectionCallback {
+ private final INetworkRequestUserSelectionCallback mCallback;
+
+ NetworkRequestUserSelectionCallbackProxy(
+ INetworkRequestUserSelectionCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void select(@NonNull WifiConfiguration wifiConfiguration) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: select "
+ + "wificonfiguration: " + wifiConfiguration);
+ }
+ try {
+ mCallback.select(wifiConfiguration);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to invoke onSelected", e);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public void reject() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: reject");
+ }
+ try {
+ mCallback.reject();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to invoke onRejected", e);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Callback proxy for NetworkRequestMatchCallback objects.
+ * @hide
+ */
+ private class NetworkRequestMatchCallbackProxy extends INetworkRequestMatchCallback.Stub {
+ private final Handler mHandler;
+ private final NetworkRequestMatchCallback mCallback;
+
+ NetworkRequestMatchCallbackProxy(Looper looper, NetworkRequestMatchCallback callback) {
+ mHandler = new Handler(looper);
+ mCallback = callback;
+ }
+
+ @Override
+ public void onUserSelectionCallbackRegistration(
+ INetworkRequestUserSelectionCallback userSelectionCallback) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestMatchCallbackProxy: "
+ + "onUserSelectionCallbackRegistration callback: " + userSelectionCallback);
+ }
+ mHandler.post(() -> {
+ mCallback.onUserSelectionCallbackRegistration(
+ new NetworkRequestUserSelectionCallbackProxy(userSelectionCallback));
+ });
+ }
+
+ @Override
+ public void onMatch(List<WifiConfiguration> wifiConfigurations) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestMatchCallbackProxy: onMatch wificonfigurations: "
+ + wifiConfigurations);
+ }
+ mHandler.post(() -> {
+ mCallback.onMatch(wifiConfigurations);
+ });
+ }
+
+ @Override
+ public void onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectSuccess "
+ + " wificonfiguration: " + wifiConfiguration);
+ }
+ mHandler.post(() -> {
+ mCallback.onUserSelectionConnectSuccess(wifiConfiguration);
+ });
+ }
+
+ @Override
+ public void onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectFailure"
+ + " wificonfiguration: " + wifiConfiguration);
+ }
+ mHandler.post(() -> {
+ mCallback.onUserSelectionConnectFailure(wifiConfiguration);
+ });
+ }
+ }
+
+ /**
+ * Registers a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
+ * Caller can unregister a previously registered callback using
+ * {@link #unregisterNetworkRequestMatchCallback(NetworkRequestMatchCallback)}
+ * <p>
+ * Applications should have the
+ * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
+ * without the permission will trigger a {@link java.lang.SecurityException}.
+ * <p>
+ *
+ * @param callback Callback for network match events
+ * @param handler The Handler on whose thread to execute the callbacks of the {@code callback}
+ * object. If null, then the application's main thread will be used.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void registerNetworkRequestMatchCallback(@NonNull NetworkRequestMatchCallback callback,
+ @Nullable Handler handler) {
+ if (callback == null) throw new IllegalArgumentException("callback cannot be null");
+ Log.v(TAG, "registerNetworkRequestMatchCallback: callback=" + callback
+ + ", handler=" + handler);
+
+ Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
+ Binder binder = new Binder();
+ try {
+ mService.registerNetworkRequestMatchCallback(
+ binder, new NetworkRequestMatchCallbackProxy(looper, callback),
+ callback.hashCode());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregisters a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
+ * <p>
+ * Applications should have the
+ * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
+ * without the permission will trigger a {@link java.lang.SecurityException}.
+ * <p>
+ *
+ * @param callback Callback for network match events
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void unregisterNetworkRequestMatchCallback(
+ @NonNull NetworkRequestMatchCallback callback) {
+ if (callback == null) throw new IllegalArgumentException("callback cannot be null");
+ Log.v(TAG, "unregisterNetworkRequestMatchCallback: callback=" + callback);
+
+ try {
+ mService.unregisterNetworkRequestMatchCallback(callback.hashCode());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Provide a list of network suggestions to the device. See {@link WifiNetworkSuggestion}
+ * for a detailed explanation of the parameters.
+ *<p>
+ * When the device decides to connect to one of the provided network suggestions, platform fires
+ * the associated {@code pendingIntent} if
+ * {@link WifiNetworkSuggestion#isAppInteractionRequired} is {@code true} and the
+ * provided {@code pendingIntent} is non-null.
+ *<p>
+ * Registration of a non-null pending intent {@code pendingIntent} requires
+ * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission.
+ *<p>
+ * NOTE:
+ * <li> These networks are just a suggestion to the platform. The platform will ultimately
+ * decide on which network the device connects to. </li>
+ * <li> When an app is uninstalled, all its suggested networks are discarded. If the device is
+ * currently connected to a suggested network which is being removed then the device will
+ * disconnect from that network.</li>
+ * <li> No in-place modification of existing suggestions are allowed. Apps are expected to
+ * remove suggestions using {@link #removeNetworkSuggestions(List)} and then add the modified
+ * suggestion back using this API.</li>
+ *
+ * @param networkSuggestions List of network suggestions provided by the app.
+ * @param pendingIntent Pending intent to be fired post connection for networks. These will be
+ * fired only when connecting to a network which has the
+ * {@link WifiNetworkSuggestion#isAppInteractionRequired} flag set.
+ * Pending intent must hold a foreground service, else will be rejected.
+ * (i.e {@link PendingIntent#isForegroundService()} should return true)
+ * @return true on success, false if any of the suggestions match (See
+ * {@link WifiNetworkSuggestion#equals(Object)} any previously provided suggestions by the app.
+ * @throws {@link SecurityException} if the caller is missing required permissions.
+ */
+ public boolean addNetworkSuggestions(
+ @NonNull List<WifiNetworkSuggestion> networkSuggestions,
+ @Nullable PendingIntent pendingIntent) {
+ // TODO(b/115504887): Implementation
+ return false;
+ }
+
+
+ /**
+ * Remove a subset of or all of networks from previously provided suggestions by the app to the
+ * device.
+ * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
+ * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
+ *
+ * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
+ * to remove all the previous suggestions provided by the app.
+ * @return true on success, false if any of the suggestions do not match any suggestions
+ * previously provided by the app. Any matching suggestions are removed from the device and
+ * will not be considered for any further connection attempts.
+ */
+ public boolean removeNetworkSuggestions(
+ @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
+ // TODO(b/115504887): Implementation
+ return false;
+ }
+
+ /**
* Add or update a Passpoint configuration. The configuration provides a credential
* for connecting to Passpoint networks that are operated by the Passpoint
* service provider specified in the configuration.
@@ -1299,7 +1622,17 @@ public class WifiManager {
* @param netId the ID of the network as returned by {@link #addNetwork} or {@link
* #getConfiguredNetworks}.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean removeNetwork(int netId) {
try {
return mService.removeNetwork(netId, mContext.getOpPackageName());
@@ -1314,10 +1647,8 @@ public class WifiManager {
* network is initiated. This may result in the asynchronous delivery
* of state change events.
* <p>
- * <b>Note:</b> If an application's target SDK version is
- * {@link android.os.Build.VERSION_CODES#LOLLIPOP} or newer, network
- * communication may not use Wi-Fi even if Wi-Fi is connected; traffic may
- * instead be sent through another network, such as cellular data,
+ * <b>Note:</b> Network communication may not use Wi-Fi even if Wi-Fi is connected;
+ * traffic may instead be sent through another network, such as cellular data,
* Bluetooth tethering, or Ethernet. For example, traffic will never use a
* Wi-Fi network that does not provide Internet access (e.g. a wireless
* printer), if another network that does offer Internet access (e.g.
@@ -1335,29 +1666,24 @@ public class WifiManager {
* @param attemptConnect The way to select a particular network to connect to is specify
* {@code true} for this parameter.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean enableNetwork(int netId, boolean attemptConnect) {
- final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
- if (pin) {
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .build();
- NetworkPinner.pin(mContext, request);
- }
-
boolean success;
try {
success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
-
- if (pin && !success) {
- NetworkPinner.unpin();
- }
-
return success;
}
@@ -1372,7 +1698,17 @@ public class WifiManager {
* @param netId the ID of the network as returned by {@link #addNetwork} or {@link
* #getConfiguredNetworks}.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean disableNetwork(int netId) {
try {
return mService.disableNetwork(netId, mContext.getOpPackageName());
@@ -1385,7 +1721,17 @@ public class WifiManager {
* Disassociate from the currently active access point. This may result
* in the asynchronous delivery of state change events.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean disconnect() {
try {
mService.disconnect(mContext.getOpPackageName());
@@ -1400,7 +1746,17 @@ public class WifiManager {
* disconnected. This may result in the asynchronous delivery of state
* change events.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean reconnect() {
try {
mService.reconnect(mContext.getOpPackageName());
@@ -1415,7 +1771,17 @@ public class WifiManager {
* connected. This may result in the asynchronous delivery of state
* change events.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean reassociate() {
try {
mService.reassociate(mContext.getOpPackageName());
@@ -1821,7 +2187,12 @@ public class WifiManager {
* @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
* either already in the requested state, or in progress toward the requested state.
* @throws {@link java.lang.SecurityException} if the caller is missing required permissions.
+ *
+ * @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to
+ * enable/disable Wi-Fi regardless of application's target SDK. This API will have no effect
+ * and will always return false.
*/
+ @Deprecated
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
diff --git a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
new file mode 100644
index 000000000000..55fde4ca335e
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.Preconditions.checkState;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.net.NetworkAgent;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Network specifier object used by wifi's {@link android.net.NetworkAgent}.
+ * @hide
+ */
+public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements Parcelable {
+ /**
+ * Security credentials for the currently connected network.
+ */
+ private final WifiConfiguration mWifiConfiguration;
+
+ /**
+ * The UID of the app that requested a specific wifi network using {@link WifiNetworkSpecifier}.
+ *
+ * Will only be filled when the device connects to a wifi network as a result of a
+ * {@link NetworkRequest} with {@link WifiNetworkSpecifier}. Will be set to -1 if the device
+ * auto-connected to a wifi network.
+ */
+ private final int mOriginalRequestorUid;
+
+ public WifiNetworkAgentSpecifier(@NonNull WifiConfiguration wifiConfiguration,
+ int originalRequestorUid) {
+ checkNotNull(wifiConfiguration);
+
+ mWifiConfiguration = wifiConfiguration;
+ mOriginalRequestorUid = originalRequestorUid;
+ }
+
+ /**
+ * @hide
+ */
+ public static final Creator<WifiNetworkAgentSpecifier> CREATOR =
+ new Creator<WifiNetworkAgentSpecifier>() {
+ @Override
+ public WifiNetworkAgentSpecifier createFromParcel(@NonNull Parcel in) {
+ WifiConfiguration wifiConfiguration = in.readParcelable(null);
+ int originalRequestorUid = in.readInt();
+ return new WifiNetworkAgentSpecifier(wifiConfiguration, originalRequestorUid);
+ }
+
+ @Override
+ public WifiNetworkAgentSpecifier[] newArray(int size) {
+ return new WifiNetworkAgentSpecifier[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mWifiConfiguration, flags);
+ dest.writeInt(mOriginalRequestorUid);
+ }
+
+ @Override
+ public boolean satisfiedBy(@Nullable NetworkSpecifier other) {
+ if (this == other) {
+ return true;
+ }
+ // Any generic requests should be satisifed by a specific wifi network.
+ if (other == null || other instanceof MatchAllNetworkSpecifier) {
+ return true;
+ }
+ if (other instanceof WifiNetworkSpecifier) {
+ return satisfiesNetworkSpecifier((WifiNetworkSpecifier) other);
+ }
+ if (other instanceof WifiNetworkAgentSpecifier) {
+ throw new IllegalStateException("WifiNetworkAgentSpecifier instances should never be "
+ + "compared");
+ }
+ return false;
+ }
+
+ /**
+ * Match {@link WifiNetworkSpecifier} in app's {@link NetworkRequest} with the
+ * {@link WifiNetworkAgentSpecifier} in wifi platform's {@link NetworkAgent}.
+ */
+ public boolean satisfiesNetworkSpecifier(@NonNull WifiNetworkSpecifier ns) {
+ // None of these should be null by construction.
+ // {@link WifiNetworkConfigBuilder} enforces non-null in {@link WifiNetworkSpecifier}.
+ // {@link WifiNetworkFactory} ensures non-null in {@link WifiNetworkAgentSpecifier}.
+ checkNotNull(ns);
+ checkNotNull(ns.ssidPatternMatcher);
+ checkNotNull(ns.bssidPatternMatcher);
+ checkNotNull(ns.wifiConfiguration.allowedKeyManagement);
+ checkNotNull(this.mWifiConfiguration.SSID);
+ checkNotNull(this.mWifiConfiguration.BSSID);
+ checkNotNull(this.mWifiConfiguration.allowedKeyManagement);
+
+ final String ssidWithQuotes = this.mWifiConfiguration.SSID;
+ checkState(ssidWithQuotes.startsWith("\"") && ssidWithQuotes.endsWith("\""));
+ final String ssidWithoutQuotes = ssidWithQuotes.substring(1, ssidWithQuotes.length() - 1);
+ if (!ns.ssidPatternMatcher.match(ssidWithoutQuotes)) {
+ return false;
+ }
+ final MacAddress bssid = MacAddress.fromString(this.mWifiConfiguration.BSSID);
+ final MacAddress matchBaseAddress = ns.bssidPatternMatcher.first;
+ final MacAddress matchMask = ns.bssidPatternMatcher.second;
+ if (!bssid.matches(matchBaseAddress, matchMask)) {
+ return false;
+ }
+ if (!ns.wifiConfiguration.allowedKeyManagement.equals(
+ this.mWifiConfiguration.allowedKeyManagement)) {
+ return false;
+ }
+ if (ns.requestorUid != this.mOriginalRequestorUid) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mWifiConfiguration.SSID,
+ mWifiConfiguration.BSSID,
+ mWifiConfiguration.allowedKeyManagement,
+ mOriginalRequestorUid);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof WifiNetworkAgentSpecifier)) {
+ return false;
+ }
+ WifiNetworkAgentSpecifier lhs = (WifiNetworkAgentSpecifier) obj;
+ 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)
+ && mOriginalRequestorUid == lhs.mOriginalRequestorUid;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("WifiNetworkAgentSpecifier [");
+ sb.append(", WifiConfiguration=").append(
+ mWifiConfiguration == null ? null : mWifiConfiguration.configKey())
+ .append(", mOriginalRequestorUid=").append(mOriginalRequestorUid)
+ .append("]");
+ return sb.toString();
+ }
+
+ @Override
+ public void assertValidFromUid(int requestorUid) {
+ throw new IllegalStateException("WifiNetworkAgentSpecifier should never be used "
+ + "for requests.");
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
new file mode 100644
index 000000000000..ae4f40511b58
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.net.MacAddress;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.os.PatternMatcher;
+import android.os.Process;
+import android.text.TextUtils;
+import android.util.Pair;
+
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+/**
+ * WifiNetworkConfigBuilder to use for creating Wi-Fi network configuration.
+ * <li>See {@link #buildNetworkSpecifier()} for creating a network specifier to use in
+ * {@link NetworkRequest}.</li>
+ * <li>See {@link #buildNetworkSuggestion()} for creating a network suggestion to use in
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}.</li>
+ */
+public class WifiNetworkConfigBuilder {
+ private static final String MATCH_ALL_SSID_PATTERN_PATH = ".*";
+ private static final String MATCH_EMPTY_SSID_PATTERN_PATH = "";
+ private static final Pair<MacAddress, MacAddress> MATCH_NO_BSSID_PATTERN =
+ new Pair(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS);
+ private static final Pair<MacAddress, MacAddress> MATCH_ALL_BSSID_PATTERN =
+ new Pair(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ private static final MacAddress MATCH_EXACT_BSSID_PATTERN_MASK =
+ MacAddress.BROADCAST_ADDRESS;
+ private static final int UNASSIGNED_PRIORITY = -1;
+
+ /**
+ * SSID pattern match specified by the app.
+ */
+ private @Nullable PatternMatcher mSsidPatternMatcher;
+ /**
+ * BSSID pattern match specified by the app.
+ * Pair of <BaseAddress, Mask>.
+ */
+ private @Nullable Pair<MacAddress, MacAddress> mBssidPatternMatcher;
+ /**
+ * Pre-shared key for use with WPA-PSK networks.
+ */
+ private @Nullable String mPskPassphrase;
+ /**
+ * The enterprise configuration details specifying the EAP method,
+ * certificates and other settings associated with the EAP.
+ */
+ private @Nullable WifiEnterpriseConfig mEnterpriseConfig;
+ /**
+ * This is a network that does not broadcast its SSID, so an
+ * SSID-specific probe request must be used for scans.
+ */
+ private boolean mIsHiddenSSID;
+ /**
+ * Whether app needs to log in to captive portal to obtain Internet access.
+ */
+ private boolean mIsAppInteractionRequired;
+ /**
+ * Whether user needs to log in to captive portal to obtain Internet access.
+ */
+ private boolean mIsUserInteractionRequired;
+ /**
+ * Whether this network is metered or not.
+ */
+ private boolean mIsMetered;
+ /**
+ * Priority of this network among other network suggestions provided by the app.
+ * The lower the number, the higher the priority (i.e value of 0 = highest priority).
+ */
+ private int mPriority;
+
+ public WifiNetworkConfigBuilder() {
+ mSsidPatternMatcher = null;
+ mBssidPatternMatcher = null;
+ mPskPassphrase = null;
+ mEnterpriseConfig = null;
+ mIsHiddenSSID = false;
+ mIsAppInteractionRequired = false;
+ mIsUserInteractionRequired = false;
+ mIsMetered = false;
+ mPriority = UNASSIGNED_PRIORITY;
+ }
+
+ /**
+ * Set the unicode SSID match pattern to use for filtering networks from scan results.
+ * <p>
+ * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li>
+ * <li>Overrides any previous value set using {@link #setSsid(String)} or
+ * {@link #setSsidPattern(PatternMatcher)}.</li>
+ *
+ * @param ssidPattern Instance of {@link PatternMatcher} containing the UTF-8 encoded
+ * string pattern to use for matching the network's SSID.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setSsidPattern(@NonNull PatternMatcher ssidPattern) {
+ checkNotNull(ssidPattern);
+ mSsidPatternMatcher = ssidPattern;
+ return this;
+ }
+
+ /**
+ * Set the unicode SSID for the network.
+ * <p>
+ * <li>For network requests ({@link NetworkSpecifier}), built using
+ * {@link #buildNetworkSpecifier}, sets the SSID to use for filtering networks from scan
+ * results. Will only match networks whose SSID is identical to the UTF-8 encoding of the
+ * specified value.</li>
+ * <li>For network suggestions ({@link WifiNetworkSuggestion}), built using
+ * {@link #buildNetworkSuggestion()}, sets the SSID for the network.</li>
+ * <li>Overrides any previous value set using {@link #setSsid(String)} or
+ * {@link #setSsidPattern(PatternMatcher)}.</li>
+ *
+ * @param ssid The SSID of the network. It must be valid Unicode.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ * @throws IllegalArgumentException if the SSID is not valid unicode.
+ */
+ public WifiNetworkConfigBuilder setSsid(@NonNull String ssid) {
+ checkNotNull(ssid);
+ final CharsetEncoder unicodeEncoder = StandardCharsets.UTF_8.newEncoder();
+ if (!unicodeEncoder.canEncode(ssid)) {
+ throw new IllegalArgumentException("SSID is not a valid unicode string");
+ }
+ mSsidPatternMatcher = new PatternMatcher(ssid, PatternMatcher.PATTERN_LITERAL);
+ return this;
+ }
+
+ /**
+ * Set the BSSID match pattern to use for filtering networks from scan results.
+ * Will match all networks with BSSID which satisfies the following:
+ * {@code BSSID & mask == baseAddress}.
+ * <p>
+ * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li>
+ * <li>Overrides any previous value set using {@link #setBssid(MacAddress)} or
+ * {@link #setBssidPattern(MacAddress, MacAddress)}.</li>
+ *
+ * @param baseAddress Base address for BSSID pattern.
+ * @param mask Mask for BSSID pattern.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setBssidPattern(
+ @NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
+ checkNotNull(baseAddress, mask);
+ mBssidPatternMatcher = Pair.create(baseAddress, mask);
+ return this;
+ }
+
+ /**
+ * Set the BSSID to use for filtering networks from scan results. Will only match network whose
+ * BSSID is identical to the specified value.
+ * <p>
+ * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li>
+ * <li>Overrides any previous value set using {@link #setBssid(MacAddress)} or
+ * {@link #setBssidPattern(MacAddress, MacAddress)}.</li>
+ *
+ * @param bssid BSSID of the network.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setBssid(@NonNull MacAddress bssid) {
+ checkNotNull(bssid);
+ mBssidPatternMatcher = Pair.create(bssid, MATCH_EXACT_BSSID_PATTERN_MASK);
+ return this;
+ }
+
+ /**
+ * Set the ASCII PSK passphrase for this network. Needed for authenticating to
+ * WPA_PSK networks.
+ *
+ * @param pskPassphrase PSK passphrase of the network.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ * @throws IllegalArgumentException if the passphrase is not ASCII encodable.
+ */
+ public WifiNetworkConfigBuilder setPskPassphrase(@NonNull String pskPassphrase) {
+ checkNotNull(pskPassphrase);
+ final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
+ if (!asciiEncoder.canEncode(pskPassphrase)) {
+ throw new IllegalArgumentException("passphrase not ASCII encodable");
+ }
+ mPskPassphrase = pskPassphrase;
+ return this;
+ }
+
+ /**
+ * Set the associated enterprise configuration for this network. Needed for authenticating to
+ * WPA_EAP networks. See {@link WifiEnterpriseConfig} for description.
+ *
+ * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setEnterpriseConfig(
+ @NonNull WifiEnterpriseConfig enterpriseConfig) {
+ checkNotNull(enterpriseConfig);
+ mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+ return this;
+ }
+
+ /**
+ * Specifies whether this represents a hidden network.
+ * <p>
+ * <li>For network requests (see {@link NetworkSpecifier}), built using
+ * {@link #buildNetworkSpecifier}, setting this disallows the usage of
+ * {@link #setSsidPattern(PatternMatcher)} since hidden networks need to be explicitly
+ * probed for.</li>
+ * <li>If not set, defaults to false (i.e not a hidden network).</li>
+ *
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setIsHiddenSsid() {
+ mIsHiddenSSID = true;
+ return this;
+ }
+
+ /**
+ * Specifies whether the app needs to log in to a captive portal to obtain Internet access.
+ * <p>
+ * This will dictate if the associated pending intent in
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)} will be sent after
+ * successfully connecting to the network.
+ * Use this for captive portal type networks where the app needs to authenticate the user
+ * before the device can access the network.
+ * This setting will be ignored if the {@code PendingIntent} used to add this network
+ * suggestion is null.
+ * <p>
+ * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+ * <li>If not set, defaults to false (i.e no app interaction required).</li>
+ *
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setIsAppInteractionRequired() {
+ mIsAppInteractionRequired = true;
+ return this;
+ }
+
+ /**
+ * Specifies whether the user needs to log in to a captive portal to obtain Internet access.
+ * <p>
+ * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+ * <li>If not set, defaults to false (i.e no user interaction required).</li>
+ *
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setIsUserInteractionRequired() {
+ mIsUserInteractionRequired = true;
+ return this;
+ }
+
+ /**
+ * Specify the priority of this network among other network suggestions provided by the same app
+ * (priorities have no impact on suggestions by different apps). The lower the number, the
+ * higher the priority (i.e value of 0 = highest priority).
+ * <p>
+ * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+ * <li>If not set, defaults to -1 (i.e unassigned priority).</li>
+ *
+ * @param priority Integer number representing the priority among suggestions by the app.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ * @throws IllegalArgumentException if the priority value is negative.
+ */
+ public WifiNetworkConfigBuilder setPriority(int priority) {
+ if (priority < 0) {
+ throw new IllegalArgumentException("Invalid priority value " + priority);
+ }
+ mPriority = priority;
+ return this;
+ }
+
+ /**
+ * Specifies whether this network is metered.
+ * <p>
+ * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+ * <li>If not set, defaults to false (i.e not metered).</li>
+ *
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setIsMetered() {
+ mIsMetered = true;
+ return this;
+ }
+
+ /**
+ * Set defaults for the various low level credential type fields in the newly created
+ * WifiConfiguration object.
+ *
+ * See {@link com.android.server.wifi.WifiConfigManager#setDefaultsInWifiConfiguration(
+ * WifiConfiguration)}.
+ *
+ * @param configuration provided WifiConfiguration object.
+ */
+ private static void setDefaultsInWifiConfiguration(@NonNull WifiConfiguration configuration) {
+ configuration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
+ configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+ configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+ configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
+ }
+
+ private void setKeyMgmtInWifiConfiguration(@NonNull WifiConfiguration configuration) {
+ if (!TextUtils.isEmpty(mPskPassphrase)) {
+ // WPA_PSK network.
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ } else if (mEnterpriseConfig != null) {
+ // WPA_EAP network
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+ } else {
+ // Open network
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ }
+ }
+
+ /**
+ * Helper method to build WifiConfiguration object from the builder.
+ * @return Instance of {@link WifiConfiguration}.
+ */
+ private WifiConfiguration buildWifiConfiguration() {
+ final WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ setDefaultsInWifiConfiguration(wifiConfiguration);
+ // WifiConfiguration.SSID needs quotes around unicode SSID.
+ if (mSsidPatternMatcher.getType() == PatternMatcher.PATTERN_LITERAL) {
+ wifiConfiguration.SSID = "\"" + mSsidPatternMatcher.getPath() + "\"";
+ }
+ setKeyMgmtInWifiConfiguration(wifiConfiguration);
+ // WifiConfiguration.preSharedKey needs quotes around ASCII password.
+ if (mPskPassphrase != null) {
+ wifiConfiguration.preSharedKey = "\"" + mPskPassphrase + "\"";
+ }
+ wifiConfiguration.enterpriseConfig = mEnterpriseConfig;
+ wifiConfiguration.hiddenSSID = mIsHiddenSSID;
+ wifiConfiguration.priority = mPriority;
+ wifiConfiguration.meteredOverride =
+ mIsMetered ? WifiConfiguration.METERED_OVERRIDE_METERED
+ : WifiConfiguration.METERED_OVERRIDE_NONE;
+ return wifiConfiguration;
+ }
+
+ private boolean hasSetAnyPattern() {
+ return mSsidPatternMatcher != null || mBssidPatternMatcher != null;
+ }
+
+ private void setMatchAnyPatternIfUnset() {
+ if (mSsidPatternMatcher == null) {
+ mSsidPatternMatcher = new PatternMatcher(MATCH_ALL_SSID_PATTERN_PATH,
+ PatternMatcher.PATTERN_SIMPLE_GLOB);
+ }
+ if (mBssidPatternMatcher == null) {
+ mBssidPatternMatcher = MATCH_ALL_BSSID_PATTERN;
+ }
+ }
+
+ private boolean hasSetMatchNonePattern() {
+ if (mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_PREFIX
+ && mSsidPatternMatcher.getPath().equals(MATCH_EMPTY_SSID_PATTERN_PATH)) {
+ return true;
+ }
+ if (mBssidPatternMatcher.equals(MATCH_NO_BSSID_PATTERN)) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean hasSetMatchAllPattern() {
+ if ((mSsidPatternMatcher.match(MATCH_EMPTY_SSID_PATTERN_PATH))
+ && mBssidPatternMatcher.equals(MATCH_ALL_BSSID_PATTERN)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 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}.
+ *<p>
+ * Note: 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
+ * <li> BSSID Pattern using {@link #setBssidPattern(MacAddress, MacAddress)} OR Specific BSSID
+ * using {@link #setBssid(MacAddress)} </li>
+ * to trigger connection to a network that matches the set params.
+ * 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.
+ *</p>
+ *
+ * For example:
+ * To connect to an open network with a SSID prefix of "test" and a BSSID OUI of "10:03:23":
+ * {@code
+ * final NetworkSpecifier specifier =
+ * new WifiNetworkConfigBuilder()
+ * .setSsidPattern(new PatternMatcher("test", PatterMatcher.PATTERN_PREFIX))
+ * .setBssidPattern(MacAddress.fromString("10:03:23:00:00:00"),
+ * MacAddress.fromString("ff:ff:ff:00:00:00"))
+ * .buildNetworkSpecifier()
+ * final NetworkRequest request =
+ * new NetworkRequest.Builder()
+ * .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ * .setNetworkSpecifier(specifier)
+ * .build();
+ * final ConnectivityManager connectivityManager =
+ * context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ * final NetworkCallback networkCallback = new NetworkCallback() {
+ * ...
+ * @Override
+ * void onAvailable(...) {}
+ * // etc.
+ * };
+ * connectivityManager.requestNetwork(request, networkCallback);
+ * }
+ *
+ * @return Instance of {@link NetworkSpecifier}.
+ * @throws IllegalStateException on invalid params set.
+ */
+ public NetworkSpecifier buildNetworkSpecifier() {
+ if (!hasSetAnyPattern()) {
+ throw new IllegalStateException("one of setSsidPattern/setSsid/setBssidPattern/setBssid"
+ + " should be invoked for specifier");
+ }
+ setMatchAnyPatternIfUnset();
+ if (hasSetMatchNonePattern()) {
+ throw new IllegalStateException("cannot set match-none pattern for specifier");
+ }
+ if (hasSetMatchAllPattern()) {
+ throw new IllegalStateException("cannot set match-all pattern for specifier");
+ }
+ if (mIsHiddenSSID && mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_LITERAL) {
+ throw new IllegalStateException("setSsid should also be invoked when "
+ + "setIsHiddenSsid is invoked for network specifier");
+ }
+ if (mIsAppInteractionRequired || mIsUserInteractionRequired
+ || mPriority != -1 || mIsMetered) {
+ throw new IllegalStateException("none of setIsAppInteractionRequired/"
+ + "setIsUserInteractionRequired/setPriority/setIsMetered are allowed for "
+ + "specifier");
+ }
+ if (!TextUtils.isEmpty(mPskPassphrase) && mEnterpriseConfig != null) {
+ throw new IllegalStateException("only one of setPreSharedKey or setEnterpriseConfig can"
+ + " be invoked for network specifier");
+ }
+
+ return new WifiNetworkSpecifier(
+ mSsidPatternMatcher,
+ mBssidPatternMatcher,
+ buildWifiConfiguration(),
+ Process.myUid());
+ }
+
+ /**
+ * Create a network suggestion object use in
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}.
+ * See {@link WifiNetworkSuggestion}.
+ *
+ * @return Instance of {@link WifiNetworkSuggestion}.
+ * @throws IllegalStateException on invalid params set.
+ */
+ public WifiNetworkSuggestion buildNetworkSuggestion() {
+ if (mSsidPatternMatcher == null) {
+ throw new IllegalStateException("setSsid should be invoked for suggestion");
+ }
+ if (mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_LITERAL
+ || mBssidPatternMatcher != null) {
+ throw new IllegalStateException("none of setSsidPattern/setBssidPattern/setBssid are"
+ + " allowed for suggestion");
+ }
+ if (!TextUtils.isEmpty(mPskPassphrase) && mEnterpriseConfig != null) {
+ throw new IllegalStateException("only one of setPreSharedKey or setEnterpriseConfig can"
+ + "be invoked for suggestion");
+ }
+
+ return new WifiNetworkSuggestion(
+ buildWifiConfiguration(),
+ mIsAppInteractionRequired,
+ mIsUserInteractionRequired,
+ Process.myUid());
+
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
new file mode 100644
index 000000000000..4348399b404b
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.net.NetworkSpecifier;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PatternMatcher;
+import android.util.Pair;
+
+import java.util.Objects;
+
+/**
+ * Network specifier object used to request a Wi-Fi network. Apps should use the
+ * {@link WifiNetworkConfigBuilder} class to create an instance.
+ * @hide
+ */
+public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+ /**
+ * SSID pattern match specified by the app.
+ */
+ public final PatternMatcher ssidPatternMatcher;
+
+ /**
+ * BSSID pattern match specified by the app.
+ * Pair of <BaseAddress, Mask>.
+ */
+ public final Pair<MacAddress, MacAddress> bssidPatternMatcher;
+
+ /**
+ * Security credentials for the network.
+ * <p>
+ * Note: {@link WifiConfiguration#SSID} & {@link WifiConfiguration#BSSID} fields from
+ * WifiConfiguration are not used. Instead we use the {@link #ssidPatternMatcher} &
+ * {@link #bssidPatternMatcher} fields embedded directly
+ * within {@link WifiNetworkSpecifier}.
+ */
+ public final WifiConfiguration wifiConfiguration;
+
+ /**
+ * The UID of the process initializing this network specifier. Validated by receiver using
+ * checkUidIfNecessary() and is used by satisfiedBy() to determine whether the specifier
+ * matches the offered network.
+ */
+ public final int requestorUid;
+
+ public WifiNetworkSpecifier(@NonNull PatternMatcher ssidPatternMatcher,
+ @NonNull Pair<MacAddress, MacAddress> bssidPatternMatcher,
+ @NonNull WifiConfiguration wifiConfiguration,
+ int requestorUid) {
+ checkNotNull(ssidPatternMatcher);
+ checkNotNull(bssidPatternMatcher);
+ checkNotNull(wifiConfiguration);
+
+ this.ssidPatternMatcher = ssidPatternMatcher;
+ this.bssidPatternMatcher = bssidPatternMatcher;
+ this.wifiConfiguration = wifiConfiguration;
+ this.requestorUid = requestorUid;
+ }
+
+ public static final Creator<WifiNetworkSpecifier> CREATOR =
+ new Creator<WifiNetworkSpecifier>() {
+ @Override
+ public WifiNetworkSpecifier createFromParcel(Parcel in) {
+ PatternMatcher ssidPatternMatcher = in.readParcelable(/* classLoader */null);
+ MacAddress baseAddress = in.readParcelable(null);
+ MacAddress mask = in.readParcelable(null);
+ Pair<MacAddress, MacAddress> bssidPatternMatcher =
+ Pair.create(baseAddress, mask);
+ WifiConfiguration wifiConfiguration = in.readParcelable(null);
+ int requestorUid = in.readInt();
+ return new WifiNetworkSpecifier(ssidPatternMatcher, bssidPatternMatcher,
+ wifiConfiguration, requestorUid);
+ }
+
+ @Override
+ public WifiNetworkSpecifier[] newArray(int size) {
+ return new WifiNetworkSpecifier[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(ssidPatternMatcher, flags);
+ dest.writeParcelable(bssidPatternMatcher.first, flags);
+ dest.writeParcelable(bssidPatternMatcher.second, flags);
+ dest.writeParcelable(wifiConfiguration, flags);
+ dest.writeInt(requestorUid);
+ }
+
+ @Override
+ public boolean satisfiedBy(NetworkSpecifier other) {
+ if (this == other) {
+ return true;
+ }
+ // Any generic requests should be satisifed by a specific wifi network.
+ if (other == null || other instanceof MatchAllNetworkSpecifier) {
+ return true;
+ }
+ if (other instanceof WifiNetworkAgentSpecifier) {
+ return ((WifiNetworkAgentSpecifier) other).satisfiesNetworkSpecifier(this);
+ }
+ // Specific requests are checked for equality although testing for equality of 2 patterns do
+ // not make much sense!
+ return equals(other);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ ssidPatternMatcher.getPath(),
+ ssidPatternMatcher.getType(),
+ bssidPatternMatcher,
+ wifiConfiguration.allowedKeyManagement,
+ requestorUid);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof WifiNetworkSpecifier)) {
+ return false;
+ }
+ WifiNetworkSpecifier lhs = (WifiNetworkSpecifier) obj;
+ return Objects.equals(this.ssidPatternMatcher.getPath(),
+ lhs.ssidPatternMatcher.getPath())
+ && Objects.equals(this.ssidPatternMatcher.getType(),
+ lhs.ssidPatternMatcher.getType())
+ && Objects.equals(this.bssidPatternMatcher,
+ lhs.bssidPatternMatcher)
+ && Objects.equals(this.wifiConfiguration.allowedKeyManagement,
+ lhs.wifiConfiguration.allowedKeyManagement)
+ && requestorUid == lhs.requestorUid;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append("WifiNetworkSpecifierWifiNetworkSpecifier [")
+ .append(", SSID Match pattern=").append(ssidPatternMatcher)
+ .append(", BSSID Match pattern=").append(bssidPatternMatcher)
+ .append(", WifiConfiguration=").append(
+ wifiConfiguration == null ? null : wifiConfiguration.configKey())
+ .append(", requestorUid=").append(requestorUid)
+ .append("]")
+ .toString();
+ }
+
+ @Override
+ public void assertValidFromUid(int requestorUid) {
+ if (this.requestorUid != requestorUid) {
+ throw new SecurityException("mismatched UIDs");
+ }
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
new file mode 100644
index 000000000000..04b9cb5dfb8d
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.app.PendingIntent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The Network Suggestion object is used to provide a Wi-Fi network for consideration when
+ * auto-connecting to networks. Apps cannot directly create this object, they must use
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} to obtain an instance
+ * of this object.
+ *<p>
+ * Apps can provide a list of such networks to the platform using
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}.
+ */
+public final class WifiNetworkSuggestion implements Parcelable {
+ /**
+ * Network configuration for the provided network.
+ * @hide
+ */
+ public final WifiConfiguration wifiConfiguration;
+
+ /**
+ * Whether app needs to log in to captive portal to obtain Internet access.
+ * This will dictate if the associated pending intent in
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)} needs to be sent after
+ * successfully connecting to the network.
+ * @hide
+ */
+ public final boolean isAppInteractionRequired;
+
+ /**
+ * Whether user needs to log in to captive portal to obtain Internet access.
+ * @hide
+ */
+ public final boolean isUserInteractionRequired;
+
+ /**
+ * The UID of the process initializing this network suggestion.
+ * @hide
+ */
+ public final int suggestorUid;
+
+ /** @hide */
+ public WifiNetworkSuggestion(WifiConfiguration wifiConfiguration,
+ boolean isAppInteractionRequired,
+ boolean isUserInteractionRequired,
+ int suggestorUid) {
+ checkNotNull(wifiConfiguration);
+
+ this.wifiConfiguration = wifiConfiguration;
+ this.isAppInteractionRequired = isAppInteractionRequired;
+ this.isUserInteractionRequired = isUserInteractionRequired;
+ this.suggestorUid = suggestorUid;
+ }
+
+ public static final Creator<WifiNetworkSuggestion> CREATOR =
+ new Creator<WifiNetworkSuggestion>() {
+ @Override
+ public WifiNetworkSuggestion createFromParcel(Parcel in) {
+ return new WifiNetworkSuggestion(
+ in.readParcelable(null), // wifiConfiguration
+ in.readBoolean(), // isAppInteractionRequired
+ in.readBoolean(), // isUserInteractionRequired
+ in.readInt() // suggestorUid
+ );
+ }
+
+ @Override
+ public WifiNetworkSuggestion[] newArray(int size) {
+ return new WifiNetworkSuggestion[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(wifiConfiguration, flags);
+ dest.writeBoolean(isAppInteractionRequired);
+ dest.writeBoolean(isUserInteractionRequired);
+ dest.writeInt(suggestorUid);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.allowedKeyManagement,
+ suggestorUid);
+ }
+
+ /**
+ * Equals for network suggestions.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof WifiNetworkSuggestion)) {
+ return false;
+ }
+ WifiNetworkSuggestion lhs = (WifiNetworkSuggestion) obj;
+ return Objects.equals(this.wifiConfiguration.SSID, lhs.wifiConfiguration.SSID)
+ && Objects.equals(this.wifiConfiguration.allowedKeyManagement,
+ lhs.wifiConfiguration.allowedKeyManagement)
+ && suggestorUid == lhs.suggestorUid;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("WifiNetworkSuggestion [")
+ .append(", WifiConfiguration=").append(wifiConfiguration)
+ .append(", isAppInteractionRequired=").append(isAppInteractionRequired)
+ .append(", isUserInteractionRequired=").append(isUserInteractionRequired)
+ .append(", suggestorUid=").append(suggestorUid)
+ .append("]");
+ return sb.toString();
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index e40b657aded0..ea41bb39c4d5 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -43,6 +43,8 @@ import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
import android.net.wifi.WifiManager.LocalOnlyHotspotObserver;
import android.net.wifi.WifiManager.LocalOnlyHotspotReservation;
import android.net.wifi.WifiManager.LocalOnlyHotspotSubscription;
+import android.net.wifi.WifiManager.NetworkRequestMatchCallback;
+import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback;
import android.net.wifi.WifiManager.SoftApCallback;
import android.net.wifi.WifiManager.TrafficStateCallback;
import android.os.Handler;
@@ -59,6 +61,8 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+
/**
* Unit tests for {@link android.net.wifi.WifiManager}.
*/
@@ -67,16 +71,19 @@ public class WifiManagerTest {
private static final int ERROR_NOT_SET = -1;
private static final int ERROR_TEST_REASON = 5;
+ private static final int TEST_UID = 14553;
private static final String TEST_PACKAGE_NAME = "TestPackage";
private static final String TEST_COUNTRY_CODE = "US";
@Mock Context mContext;
- @Mock IWifiManager mWifiService;
+ @Mock
+ android.net.wifi.IWifiManager mWifiService;
@Mock ApplicationInfo mApplicationInfo;
@Mock WifiConfiguration mApConfig;
@Mock IBinder mAppBinder;
@Mock SoftApCallback mSoftApCallback;
@Mock TrafficStateCallback mTrafficStateCallback;
+ @Mock NetworkRequestMatchCallback mNetworkRequestMatchCallback;
private Handler mHandler;
private TestLooper mLooper;
@@ -1163,4 +1170,84 @@ i * Verify that a call to cancel WPS immediately returns a failure.
assertEquals(1, altLooper.dispatchAll());
verify(mTrafficStateCallback).onStateChanged(TrafficStateCallback.DATA_ACTIVITY_INOUT);
}
+
+ /**
+ * Verify the call to registerNetworkRequestMatchCallback goes to WifiServiceImpl.
+ */
+ @Test
+ public void registerNetworkRequestMatchCallbackCallGoesToWifiServiceImpl()
+ throws Exception {
+ when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
+ ArgumentCaptor<INetworkRequestMatchCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(INetworkRequestMatchCallback.Stub.class);
+ mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, null);
+ verify(mWifiService).registerNetworkRequestMatchCallback(
+ any(IBinder.class), callbackCaptor.capture(), anyInt());
+
+ INetworkRequestUserSelectionCallback iUserSelectionCallback =
+ mock(INetworkRequestUserSelectionCallback.class);
+
+ assertEquals(0, mLooper.dispatchAll());
+ callbackCaptor.getValue().onMatch(new ArrayList<WifiConfiguration>());
+ assertEquals(1, mLooper.dispatchAll());
+ verify(mNetworkRequestMatchCallback).onMatch(anyList());
+
+ callbackCaptor.getValue().onUserSelectionConnectSuccess(new WifiConfiguration());
+ assertEquals(1, mLooper.dispatchAll());
+ verify(mNetworkRequestMatchCallback).onUserSelectionConnectSuccess(
+ any(WifiConfiguration.class));
+
+ callbackCaptor.getValue().onUserSelectionConnectFailure(new WifiConfiguration());
+ assertEquals(1, mLooper.dispatchAll());
+ verify(mNetworkRequestMatchCallback).onUserSelectionConnectFailure(
+ any(WifiConfiguration.class));
+ }
+
+ /**
+ * Verify the call to unregisterNetworkRequestMatchCallback goes to WifiServiceImpl.
+ */
+ @Test
+ public void unregisterNetworkRequestMatchCallbackCallGoesToWifiServiceImpl() throws Exception {
+ ArgumentCaptor<Integer> callbackIdentifier = ArgumentCaptor.forClass(Integer.class);
+ mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, mHandler);
+ verify(mWifiService).registerNetworkRequestMatchCallback(
+ any(IBinder.class), any(INetworkRequestMatchCallback.class),
+ callbackIdentifier.capture());
+
+ mWifiManager.unregisterNetworkRequestMatchCallback(mNetworkRequestMatchCallback);
+ verify(mWifiService).unregisterNetworkRequestMatchCallback(
+ eq((int) callbackIdentifier.getValue()));
+ }
+
+ /**
+ * Verify the call to NetworkRequestUserSelectionCallback goes to
+ * WifiServiceImpl.
+ */
+ @Test
+ public void networkRequestUserSelectionCallbackCallGoesToWifiServiceImpl()
+ throws Exception {
+ when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
+ ArgumentCaptor<INetworkRequestMatchCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(INetworkRequestMatchCallback.Stub.class);
+ mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, null);
+ verify(mWifiService).registerNetworkRequestMatchCallback(
+ any(IBinder.class), callbackCaptor.capture(), anyInt());
+
+ INetworkRequestUserSelectionCallback iUserSelectionCallback =
+ mock(INetworkRequestUserSelectionCallback.class);
+ ArgumentCaptor<NetworkRequestUserSelectionCallback> userSelectionCallbackCaptor =
+ ArgumentCaptor.forClass(NetworkRequestUserSelectionCallback.class);
+ callbackCaptor.getValue().onUserSelectionCallbackRegistration(
+ iUserSelectionCallback);
+ assertEquals(1, mLooper.dispatchAll());
+ verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration(
+ userSelectionCallbackCaptor.capture());
+
+ WifiConfiguration selected = new WifiConfiguration();
+ userSelectionCallbackCaptor.getValue().select(selected);
+ verify(iUserSelectionCallback).select(selected);
+
+ userSelectionCallbackCaptor.getValue().reject();
+ verify(iUserSelectionCallback).reject();
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
new file mode 100644
index 000000000000..1b0007c9e732
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.os.Parcel;
+import android.os.PatternMatcher;
+import android.support.test.filters.SmallTest;
+import android.util.Pair;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkAgentSpecifier}.
+ */
+@SmallTest
+public class WifiNetworkAgentSpecifierTest {
+ private static final int TEST_UID = 5;
+ private static final int TEST_UID_1 = 8;
+ private static final String TEST_SSID = "Test123";
+ private static final String TEST_SSID_PATTERN = "Test";
+ private static final String TEST_SSID_1 = "456test";
+ private static final String TEST_BSSID = "12:12:12:aa:0b:c0";
+ private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
+ private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
+ private static final String TEST_BSSID_1 = "aa:cc:12:aa:0b:c0";
+ private static final String TEST_PRESHARED_KEY = "\"Test123\"";
+
+ /**
+ * Validate that parcel marshalling/unmarshalling works
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierParcel() {
+ WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier();
+
+ Parcel parcelW = Parcel.obtain();
+ specifier.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ WifiNetworkAgentSpecifier parcelSpecifier =
+ WifiNetworkAgentSpecifier.CREATOR.createFromParcel(parcelR);
+
+ assertEquals(specifier, parcelSpecifier);
+ }
+
+ /**
+ * Validate that the NetworkAgentSpecifier cannot be used in a {@link NetworkRequest} by apps.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkAgentSpecifierNotUsedInNetworkRequest() {
+ WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier();
+
+ specifier.assertValidFromUid(TEST_UID);
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier equals with itself.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with the same params as specifier 1.
+ * c) Ensure that the specifier 2 equals specifier 1.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierEqualsSame() {
+ WifiNetworkAgentSpecifier specifier1 = createDefaultNetworkAgentSpecifier();
+ WifiNetworkAgentSpecifier specifier2 = createDefaultNetworkAgentSpecifier();
+
+ assertTrue(specifier2.equals(specifier1));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with different key mgmt params.
+ * c) Ensure that the specifier 2 does not equal specifier 1.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierDoesNotEqualsWhenKeyMgmtDifferent() {
+ WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
+ WifiNetworkAgentSpecifier specifier1 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration1,
+ TEST_UID);
+
+ WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
+ wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkAgentSpecifier specifier2 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration2,
+ TEST_UID);
+
+ assertFalse(specifier2.equals(specifier1));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with different SSID.
+ * c) Ensure that the specifier 2 does not equal specifier 1.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierDoesNotSatisifyWhenSsidDifferent() {
+ WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
+ WifiNetworkAgentSpecifier specifier1 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration1,
+ TEST_UID);
+
+ WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
+ wifiConfiguration2.SSID = TEST_SSID_1;
+ WifiNetworkAgentSpecifier specifier2 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration2,
+ TEST_UID);
+
+ assertFalse(specifier2.equals(specifier1));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with different BSSID.
+ * c) Ensure that the specifier 2 does not equal specifier 1.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierDoesNotSatisifyWhenBssidDifferent() {
+ WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
+ WifiNetworkAgentSpecifier specifier1 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration1,
+ TEST_UID);
+
+ WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
+ wifiConfiguration2.BSSID = TEST_BSSID_1;
+ WifiNetworkAgentSpecifier specifier2 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration2,
+ TEST_UID);
+
+ assertFalse(specifier2.equals(specifier1));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier matching.
+ * a) Create a network agent specifier for WPA_PSK network
+ * b) Ensure that the specifier matches {@code null} and {@link MatchAllNetworkSpecifier}
+ * specifiers.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierSatisifiesNullAndAllMatch() {
+ WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier();
+
+ assertTrue(specifier.satisfiedBy(null));
+ assertTrue(specifier.satisfiedBy(new MatchAllNetworkSpecifier()));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier matching with itself.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with the same params as specifier 1.
+ * c) Ensure that invoking {@link NetworkSpecifier#satisfiedBy(NetworkSpecifier)} on 2
+ * {@link WifiNetworkAgentSpecifier} throws an exception.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkAgentSpecifierDoesNotSatisifySame() {
+ WifiNetworkAgentSpecifier specifier1 = createDefaultNetworkAgentSpecifier();
+ WifiNetworkAgentSpecifier specifier2 = createDefaultNetworkAgentSpecifier();
+
+ assertTrue(specifier2.satisfiedBy(specifier1));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching SSID pattern.
+ * c) Ensure that the agent specifier is satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithSsidPattern() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching BSSID pattern.
+ * c) Ensure that the agent specifier is satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithBssidPattern() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB);
+ 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);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching SSID & BSSID pattern.
+ * c) Ensure that the agent specifier is satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithSsidAndBssidPattern() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ 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);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with non-matching SSID pattern.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithSsidPattern() {
+ WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration();
+ wifiConfigurationNetworkAgent.SSID = "\"" + TEST_SSID_1 + "\"";
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
+ new WifiNetworkAgentSpecifier(
+ wifiConfigurationNetworkAgent,
+ TEST_UID);
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(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.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithBssidPattern() {
+ WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration();
+ wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1;
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
+ new WifiNetworkAgentSpecifier(
+ wifiConfigurationNetworkAgent,
+ TEST_UID);
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB);
+ 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);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with non-matching SSID and BSSID pattern.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithSsidAndBssidPattern() {
+ WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration();
+ wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1;
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
+ new WifiNetworkAgentSpecifier(
+ wifiConfigurationNetworkAgent,
+ TEST_UID);
+
+ 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);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching SSID and BSSID pattern, but different key mgmt.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithDifferentKeyMgmt() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ 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.NONE);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching SSID and BSSID pattern, but different UID.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithDifferentUid() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ 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);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID_1);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ private WifiConfiguration createDefaultWifiConfiguration() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.SSID = "\"" + TEST_SSID + "\"";
+ wifiConfiguration.BSSID = TEST_BSSID;
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+ return wifiConfiguration;
+ }
+
+ private WifiNetworkAgentSpecifier createDefaultNetworkAgentSpecifier() {
+ return new WifiNetworkAgentSpecifier(createDefaultWifiConfiguration(), TEST_UID);
+ }
+
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
new file mode 100644
index 000000000000..8980ddba238b
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static android.os.PatternMatcher.PATTERN_LITERAL;
+import static android.os.PatternMatcher.PATTERN_PREFIX;
+import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.MacAddress;
+import android.net.NetworkSpecifier;
+import android.os.PatternMatcher;
+import android.os.Process;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkConfigBuilder}.
+ */
+@SmallTest
+public class WifiNetworkConfigBuilderTest {
+ private static final String TEST_SSID = "Test123";
+ private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
+ private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
+ private static final String TEST_BSSID = "12:12:12:12:12:12";
+ private static final String TEST_PRESHARED_KEY = "Test123";
+
+ /**
+ * Validate correctness of WifiNetworkSpecifier object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for open network with SSID pattern.
+ */
+ @Test
+ public void testWifiNetworkSpecifierBuilderForOpenNetworkWithSsidPattern() {
+ NetworkSpecifier specifier = new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_PREFIX))
+ .buildNetworkSpecifier();
+
+ assertTrue(specifier instanceof WifiNetworkSpecifier);
+ WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+ assertEquals(Process.myUid(), wifiNetworkSpecifier.requestorUid);
+ assertEquals(TEST_SSID, wifiNetworkSpecifier.ssidPatternMatcher.getPath());
+ assertEquals(PATTERN_PREFIX, wifiNetworkSpecifier.ssidPatternMatcher.getType());
+ assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.first);
+ assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.second);
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.NONE));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
+ .get(WifiConfiguration.Protocol.RSN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
+ .get(WifiConfiguration.AuthAlgorithm.OPEN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
+ .get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.TKIP));
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSpecifier object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for WPA_PSK network with BSSID
+ * pattern.
+ */
+ @Test
+ public void testWifiNetworkSpecifierBuilderForWpaPskNetworkWithBssidPattern() {
+ NetworkSpecifier specifier = new WifiNetworkConfigBuilder()
+ .setBssidPattern(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK))
+ .setPskPassphrase(TEST_PRESHARED_KEY)
+ .buildNetworkSpecifier();
+
+ assertTrue(specifier instanceof WifiNetworkSpecifier);
+ WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+ assertEquals(".*", wifiNetworkSpecifier.ssidPatternMatcher.getPath());
+ assertEquals(PATTERN_SIMPLE_GLOB, wifiNetworkSpecifier.ssidPatternMatcher.getType());
+ assertEquals(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ wifiNetworkSpecifier.bssidPatternMatcher.first);
+ assertEquals(MacAddress.fromString(TEST_BSSID_OUI_MASK),
+ wifiNetworkSpecifier.bssidPatternMatcher.second);
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WPA_PSK));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
+ .get(WifiConfiguration.Protocol.RSN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
+ .get(WifiConfiguration.AuthAlgorithm.OPEN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
+ .get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.TKIP));
+ assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+ wifiNetworkSpecifier.wifiConfiguration.preSharedKey);
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSpecifier object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for WPA_EAP network with
+ * SSID and BSSID pattern.
+ */
+ @Test
+ public void testWifiNetworkSpecifierBuilderForEnterpriseHiddenNetworkWithSsidAndBssid() {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+ enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
+
+ NetworkSpecifier specifier = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setBssid(MacAddress.fromString(TEST_BSSID))
+ .setEnterpriseConfig(enterpriseConfig)
+ .setIsHiddenSsid()
+ .buildNetworkSpecifier();
+
+ assertTrue(specifier instanceof WifiNetworkSpecifier);
+ WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+ assertEquals(TEST_SSID, wifiNetworkSpecifier.ssidPatternMatcher.getPath());
+ assertEquals(PATTERN_LITERAL, wifiNetworkSpecifier.ssidPatternMatcher.getType());
+ assertEquals(MacAddress.fromString(TEST_BSSID),
+ wifiNetworkSpecifier.bssidPatternMatcher.first);
+ assertEquals(MacAddress.BROADCAST_ADDRESS,
+ wifiNetworkSpecifier.bssidPatternMatcher.second);
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WPA_EAP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.IEEE8021X));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
+ .get(WifiConfiguration.Protocol.RSN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
+ .get(WifiConfiguration.AuthAlgorithm.OPEN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
+ .get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.TKIP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.hiddenSSID);
+ assertEquals(enterpriseConfig.getEapMethod(),
+ wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig.getEapMethod());
+ assertEquals(enterpriseConfig.getPhase2Method(),
+ wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig.getPhase2Method());
+ }
+
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#setSsid(String)} throws an exception
+ * when the string is not Unicode.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetSsidWithNonUnicodeString() {
+ new WifiNetworkConfigBuilder()
+ .setSsid("\ud800")
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#setPskPassphrase(String)} throws an exception
+ * when the string is not ASCII encodable.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetPskPassphraseWithNonAsciiString() {
+ new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setPskPassphrase("salvē")
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when neither SSID nor BSSID patterns were set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithNoSsidAndBssidPattern() {
+ new WifiNetworkConfigBuilder().buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-all SSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern1() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB))
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-all SSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern2() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(".*", PatternMatcher.PATTERN_ADVANCED_GLOB))
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-all SSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern3() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher("", PatternMatcher.PATTERN_PREFIX))
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-all BSSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchAllBssidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setBssidPattern(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS)
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-none SSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchNoneSsidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher("", PatternMatcher.PATTERN_LITERAL))
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-none BSSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchNoneBssidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setBssidPattern(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS)
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when SSID pattern is set for hidden network.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithBssidMatchPatternForHiddenNetwork() {
+ new WifiNetworkConfigBuilder()
+ .setBssidPattern(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK))
+ .setIsHiddenSsid()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when both {@link WifiNetworkConfigBuilder#setPskPassphrase(String)} and
+ * {@link WifiNetworkConfigBuilder#setEnterpriseConfig(WifiEnterpriseConfig)} are invoked.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithBothPskPassphraseAndEnterpriseConfig() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setPskPassphrase(TEST_PRESHARED_KEY)
+ .setEnterpriseConfig(new WifiEnterpriseConfig())
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when SSID pattern is set for hidden network.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithSsidMatchPatternForHiddenNetwork() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_PREFIX))
+ .setIsHiddenSsid()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setIsAppInteractionRequired()} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithRequiredAppInteraction() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setIsAppInteractionRequired()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setIsUserInteractionRequired()} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithRequiredUserInteraction() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setIsUserInteractionRequired()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setPriority(int)} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithSetPriority() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setPriority(4)
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setIsMetered()} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMetered() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setIsMetered()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for Open network which requires
+ * app interaction.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForOpenNetworkWithReqAppInteraction() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setIsAppInteractionRequired()
+ .buildNetworkSuggestion();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.NONE));
+ assertTrue(suggestion.isAppInteractionRequired);
+ assertFalse(suggestion.isUserInteractionRequired);
+ assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
+ suggestion.wifiConfiguration.meteredOverride);
+ assertEquals(-1, suggestion.wifiConfiguration.priority);
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for WPA_EAP network which requires
+ * app interaction and has a priority of zero set.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForWpaEapNetworkWithPriorityAndReqAppInteraction() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setPskPassphrase(TEST_PRESHARED_KEY)
+ .setIsAppInteractionRequired()
+ .setPriority(0)
+ .buildNetworkSuggestion();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WPA_PSK));
+ assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+ suggestion.wifiConfiguration.preSharedKey);
+ assertTrue(suggestion.isAppInteractionRequired);
+ assertFalse(suggestion.isUserInteractionRequired);
+ assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
+ suggestion.wifiConfiguration.meteredOverride);
+ assertEquals(0, suggestion.wifiConfiguration.priority);
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for WPA_PSK network which requires
+ * user interaction and is metered.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForWpaPskNetworkWithMeteredAndReqUserInteraction() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setPskPassphrase(TEST_PRESHARED_KEY)
+ .setIsUserInteractionRequired()
+ .setIsMetered()
+ .buildNetworkSuggestion();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WPA_PSK));
+ assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+ suggestion.wifiConfiguration.preSharedKey);
+ assertFalse(suggestion.isAppInteractionRequired);
+ assertTrue(suggestion.isUserInteractionRequired);
+ assertEquals(WifiConfiguration.METERED_OVERRIDE_METERED,
+ suggestion.wifiConfiguration.meteredOverride);
+ assertEquals(-1, suggestion.wifiConfiguration.priority);
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setSsidPattern(PatternMatcher)} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithSsidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_PREFIX))
+ .buildNetworkSuggestion();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setBssid(MacAddress)} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithBssidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setBssidPattern(MacAddress.fromString(TEST_BSSID),
+ MacAddress.fromString(TEST_BSSID))
+ .buildNetworkSuggestion();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setBssidPattern(MacAddress, MacAddress)} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithBssid() {
+ new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setBssid(MacAddress.fromString(TEST_BSSID))
+ .buildNetworkSuggestion();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setSsid(String)} is not set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithNoSsid() {
+ new WifiNetworkConfigBuilder()
+ .buildNetworkSuggestion();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#setPriority(int)} throws an exception
+ * when the value is negative.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testWifiNetworkSuggestionBuilderWithInvalidPriority() {
+ new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setPriority(-1)
+ .buildNetworkSuggestion();
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
new file mode 100644
index 000000000000..856f0c79a2e7
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static android.os.PatternMatcher.PATTERN_LITERAL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.os.Parcel;
+import android.os.PatternMatcher;
+import android.support.test.filters.SmallTest;
+import android.util.Pair;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkSpecifier}.
+ */
+@SmallTest
+public class WifiNetworkSpecifierTest {
+ private static final int TEST_UID = 5;
+ private static final String TEST_SSID = "Test123";
+ private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
+ private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
+ private static final String TEST_PRESHARED_KEY = "\"Test123\"";
+
+ /**
+ * Validate that parcel marshalling/unmarshalling works
+ */
+ @Test
+ public void testWifiNetworkSpecifierParcel() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+ WifiNetworkSpecifier specifier =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ Parcel parcelW = Parcel.obtain();
+ specifier.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ WifiNetworkSpecifier parcelSpecifier =
+ WifiNetworkSpecifier.CREATOR.createFromParcel(parcelR);
+
+ assertEquals(specifier, parcelSpecifier);
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create a network specifier for WPA_PSK network
+ * b) Ensure that the specifier matches {@code null} and {@link MatchAllNetworkSpecifier}
+ * specifiers.
+ */
+ @Test
+ public void testWifiNetworkSpecifierSatisfiesNullAndAllMatch() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+ WifiNetworkSpecifier specifier =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ assertTrue(specifier.satisfiedBy(null));
+ assertTrue(specifier.satisfiedBy(new MatchAllNetworkSpecifier()));
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create network specifier 1 for WPA_PSK network
+ * b) Create network specifier 2 with the same params as specifier 1.
+ * c) Ensure that the specifier 2 is satisfied by specifier 1.
+ */
+ @Test
+ public void testWifiNetworkSpecifierSatisfiesSame() {
+ 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)),
+ wifiConfiguration,
+ TEST_UID);
+
+ 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)),
+ wifiConfiguration,
+ TEST_UID);
+
+ assertTrue(specifier2.satisfiedBy(specifier1));
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create network specifier 1 for WPA_PSK network
+ * b) Create network specifier 2 with different key mgmt params.
+ * c) Ensure that the specifier 2 is not satisfied by specifier 1.
+ */
+ @Test
+ public void testWifiNetworkSpecifierDoesNotSatisfyWhenKeyMgmtDifferent() {
+ WifiConfiguration wifiConfiguration1 = new WifiConfiguration();
+ wifiConfiguration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration1.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)),
+ wifiConfiguration1,
+ TEST_UID);
+
+ WifiConfiguration wifiConfiguration2 = new WifiConfiguration();
+ wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ 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)),
+ wifiConfiguration2,
+ TEST_UID);
+
+ assertFalse(specifier2.satisfiedBy(specifier1));
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create network specifier 1 for WPA_PSK network
+ * b) Create network specifier 2 with different SSID pattern.
+ * c) Ensure that the specifier 2 is not satisfied by specifier 1.
+ */
+ @Test
+ public void testWifiNetworkSpecifierDoesNotSatisfyWhenSsidDifferent() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+
+ WifiNetworkSpecifier specifier1 =
+ new WifiNetworkSpecifier(new PatternMatcher("", PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ 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)),
+ wifiConfiguration,
+ TEST_UID);
+
+ assertFalse(specifier2.satisfiedBy(specifier1));
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create network specifier 1 for WPA_PSK network
+ * b) Create network specifier 2 with different BSSID pattern.
+ * c) Ensure that the specifier 2 is not satisfied by specifier 1.
+ */
+ @Test
+ public void testWifiNetworkSpecifierDoesNotSatisfyWhenBssidDifferent() {
+ 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)),
+ wifiConfiguration,
+ TEST_UID);
+
+ WifiNetworkSpecifier specifier2 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS),
+ wifiConfiguration,
+ TEST_UID);
+
+ assertFalse(specifier2.satisfiedBy(specifier1));
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
new file mode 100644
index 000000000000..6bab60dd480b
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static org.junit.Assert.*;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkSuggestion}.
+ */
+@SmallTest
+public class WifiNetworkSuggestionTest {
+ private static final String TEST_SSID = "\"Test123\"";
+ private static final String TEST_SSID_1 = "\"Test1234\"";
+
+ /**
+ * Check that parcel marshalling/unmarshalling works
+ */
+ @Test
+ public void testWifiNetworkSuggestionParcel() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, false, true, 0);
+
+ Parcel parcelW = Parcel.obtain();
+ suggestion.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ WifiNetworkSuggestion parcelSuggestion =
+ WifiNetworkSuggestion.CREATOR.createFromParcel(parcelR);
+
+ // Two suggestion objects are considered equal if they point to the same network (i.e same
+ // SSID + keyMgmt + same UID). |isAppInteractionRequired| & |isUserInteractionRequired| are
+ // not considered for equality and hence needs to be checked for explicitly below.
+ assertEquals(suggestion, parcelSuggestion);
+ assertEquals(suggestion.isAppInteractionRequired,
+ parcelSuggestion.isAppInteractionRequired);
+ assertEquals(suggestion.isUserInteractionRequired,
+ parcelSuggestion.isUserInteractionRequired);
+ }
+
+ /**
+ * Check NetworkSuggestion equals returns {@code true} for 2 network suggestions with the same
+ * SSID, key mgmt and UID.
+ */
+ @Test
+ public void testWifiNetworkSuggestionEqualsSame() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, true, false, 0);
+
+ WifiConfiguration configuration1 = new WifiConfiguration();
+ configuration1.SSID = TEST_SSID;
+ configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSuggestion suggestion1 =
+ new WifiNetworkSuggestion(configuration1, false, true, 0);
+
+ assertEquals(suggestion, suggestion1);
+ }
+
+ /**
+ * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
+ * key mgmt and UID, but different SSID.
+ */
+ @Test
+ public void testWifiNetworkSuggestionEqualsFailsWhenSsidIsDifferent() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, false, false, 0);
+
+ WifiConfiguration configuration1 = new WifiConfiguration();
+ configuration1.SSID = TEST_SSID_1;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion1 =
+ new WifiNetworkSuggestion(configuration1, false, false, 0);
+
+ assertNotEquals(suggestion, suggestion1);
+ }
+
+ /**
+ * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
+ * SSID and UID, but different key mgmt.
+ */
+ @Test
+ public void testWifiNetworkSuggestionEqualsFailsWhenKeyMgmtIsDifferent() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, false, false, 0);
+
+ WifiConfiguration configuration1 = new WifiConfiguration();
+ configuration1.SSID = TEST_SSID;
+ configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSuggestion suggestion1 =
+ new WifiNetworkSuggestion(configuration1, false, false, 0);
+
+ assertNotEquals(suggestion, suggestion1);
+ }
+
+ /**
+ * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
+ * SSID and key mgmt, but different UID.
+ */
+ @Test
+ public void testWifiNetworkSuggestionEqualsFailsWhenUidIsDifferent() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, false, false, 0);
+
+ WifiNetworkSuggestion suggestion1 =
+ new WifiNetworkSuggestion(configuration, false, false, 1);
+
+ assertNotEquals(suggestion, suggestion1);
+ }
+}