diff options
7 files changed, 200 insertions, 39 deletions
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index c6acd026bd39..d9a7b7cbd2e6 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -66,6 +66,8 @@ interface IWifiManager List<OsuProvider> getMatchingOsuProviders(in List<ScanResult> scanResult); + Map getMatchingPasspointConfigsForOsuProviders(in List<OsuProvider> osuProviders); + int addOrUpdateNetwork(in WifiConfiguration config, String packageName); boolean addOrUpdatePasspointConfiguration(in PasspointConfiguration config, String packageName); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 46ecc497da31..de88aab34f9a 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -57,8 +57,11 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.net.InetAddress; +import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.CountDownLatch; /** @@ -1230,6 +1233,30 @@ public class WifiManager { } /** + * Returns the matching Passpoint R2 configurations for given OSU (Online Sign-Up) providers. + * + * Given a list of OSU providers, this only returns OSU providers that already have Passpoint R2 + * configurations in the device. + * An empty map will be returned when there is no matching Passpoint R2 configuration for the + * given OsuProviders. + * + * @param osuProviders a set of {@link OsuProvider} + * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}. + * @throws UnsupportedOperationException if Passpoint is not enabled on the device. + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders( + @NonNull Set<OsuProvider> osuProviders) { + try { + return mService.getMatchingPasspointConfigsForOsuProviders( + new ArrayList<>(osuProviders)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Add a new network description to the set of configured networks. * The {@code networkId} field of the supplied configuration object * is ignored. diff --git a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java index 893b19ce3a3b..6d82ca152202 100644 --- a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java +++ b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java @@ -19,13 +19,16 @@ package android.net.wifi.hotspot2; import android.graphics.drawable.Icon; import android.net.Uri; import android.net.wifi.WifiSsid; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import java.util.ArrayList; -import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Objects; /** @@ -52,9 +55,9 @@ public final class OsuProvider implements Parcelable { private WifiSsid mOsuSsid; /** - * Friendly name of the OSU provider. + * Map of friendly names expressed as different language for the OSU provider. */ - private final String mFriendlyName; + private final Map<String, String> mFriendlyNames; /** * Description of the OSU provider. @@ -81,10 +84,11 @@ public final class OsuProvider implements Parcelable { */ private final Icon mIcon; - public OsuProvider(WifiSsid osuSsid, String friendlyName, String serviceDescription, - Uri serverUri, String nai, List<Integer> methodList, Icon icon) { + public OsuProvider(WifiSsid osuSsid, Map<String, String> friendlyNames, + String serviceDescription, Uri serverUri, String nai, List<Integer> methodList, + Icon icon) { mOsuSsid = osuSsid; - mFriendlyName = friendlyName; + mFriendlyNames = friendlyNames; mServiceDescription = serviceDescription; mServerUri = serverUri; mNetworkAccessIdentifier = nai; @@ -104,7 +108,7 @@ public final class OsuProvider implements Parcelable { public OsuProvider(OsuProvider source) { if (source == null) { mOsuSsid = null; - mFriendlyName = null; + mFriendlyNames = null; mServiceDescription = null; mServerUri = null; mNetworkAccessIdentifier = null; @@ -114,7 +118,7 @@ public final class OsuProvider implements Parcelable { } mOsuSsid = source.mOsuSsid; - mFriendlyName = source.mFriendlyName; + mFriendlyNames = source.mFriendlyNames; mServiceDescription = source.mServiceDescription; mServerUri = source.mServerUri; mNetworkAccessIdentifier = source.mNetworkAccessIdentifier; @@ -134,8 +138,32 @@ public final class OsuProvider implements Parcelable { mOsuSsid = osuSsid; } + /** + * Return the friendly Name for current language from the list of friendly names of OSU + * provider. + * + * The string matching the default locale will be returned if it is found, otherwise the string + * in english or the first string in the list will be returned if english is not found. + * A null will be returned if the list is empty. + * + * @return String matching the default locale, null otherwise + */ public String getFriendlyName() { - return mFriendlyName; + if (mFriendlyNames == null || mFriendlyNames.isEmpty()) return null; + String lang = Locale.getDefault().getLanguage(); + String friendlyName = mFriendlyNames.get(lang); + if (friendlyName != null) { + return friendlyName; + } + friendlyName = mFriendlyNames.get("en"); + if (friendlyName != null) { + return friendlyName; + } + return mFriendlyNames.get(mFriendlyNames.keySet().stream().findFirst().get()); + } + + public Map<String, String> getFriendlyNameList() { + return mFriendlyNames; } public String getServiceDescription() { @@ -151,7 +179,7 @@ public final class OsuProvider implements Parcelable { } public List<Integer> getMethodList() { - return Collections.unmodifiableList(mMethodList); + return mMethodList; } public Icon getIcon() { @@ -166,12 +194,14 @@ public final class OsuProvider implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(mOsuSsid, flags); - dest.writeString(mFriendlyName); dest.writeString(mServiceDescription); dest.writeParcelable(mServerUri, flags); dest.writeString(mNetworkAccessIdentifier); dest.writeList(mMethodList); dest.writeParcelable(mIcon, flags); + Bundle bundle = new Bundle(); + bundle.putSerializable("friendlyNameMap", (HashMap<String, String>) mFriendlyNames); + dest.writeBundle(bundle); } @Override @@ -184,7 +214,8 @@ public final class OsuProvider implements Parcelable { } OsuProvider that = (OsuProvider) thatObject; return (mOsuSsid == null ? that.mOsuSsid == null : mOsuSsid.equals(that.mOsuSsid)) - && TextUtils.equals(mFriendlyName, that.mFriendlyName) + && (mFriendlyNames == null) ? that.mFriendlyNames == null + : mFriendlyNames.equals(that.mFriendlyNames) && TextUtils.equals(mServiceDescription, that.mServiceDescription) && (mServerUri == null ? that.mServerUri == null : mServerUri.equals(that.mServerUri)) @@ -196,14 +227,15 @@ public final class OsuProvider implements Parcelable { @Override public int hashCode() { - return Objects.hash(mOsuSsid, mFriendlyName, mServiceDescription, mServerUri, - mNetworkAccessIdentifier, mMethodList, mIcon); + // mIcon is not hashable, skip the variable. + return Objects.hash(mOsuSsid, mServiceDescription, mFriendlyNames, + mServerUri, mNetworkAccessIdentifier, mMethodList); } @Override public String toString() { return "OsuProvider{mOsuSsid=" + mOsuSsid - + " mFriendlyName=" + mFriendlyName + + " mFriendlyNames=" + mFriendlyNames + " mServiceDescription=" + mServiceDescription + " mServerUri=" + mServerUri + " mNetworkAccessIdentifier=" + mNetworkAccessIdentifier @@ -212,20 +244,22 @@ public final class OsuProvider implements Parcelable { } public static final Creator<OsuProvider> CREATOR = - new Creator<OsuProvider>() { - @Override - public OsuProvider createFromParcel(Parcel in) { - WifiSsid osuSsid = (WifiSsid) in.readParcelable(null); - String friendlyName = in.readString(); - String serviceDescription = in.readString(); - Uri serverUri = (Uri) in.readParcelable(null); - String nai = in.readString(); - List<Integer> methodList = new ArrayList<>(); - in.readList(methodList, null); - Icon icon = (Icon) in.readParcelable(null); - return new OsuProvider(osuSsid, friendlyName, serviceDescription, serverUri, - nai, methodList, icon); - } + new Creator<OsuProvider>() { + @Override + public OsuProvider createFromParcel(Parcel in) { + WifiSsid osuSsid = in.readParcelable(null); + String serviceDescription = in.readString(); + Uri serverUri = in.readParcelable(null); + String nai = in.readString(); + List<Integer> methodList = new ArrayList<>(); + in.readList(methodList, null); + Icon icon = in.readParcelable(null); + Bundle bundle = in.readBundle(); + Map<String, String> friendlyNamesMap = (HashMap) bundle.getSerializable( + "friendlyNameMap"); + return new OsuProvider(osuSsid, friendlyNamesMap, serviceDescription, + serverUri, nai, methodList, icon); + } @Override public OsuProvider[] newArray(int size) { diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java index 26bdb181e4a1..f09d8647e40e 100644 --- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java +++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java @@ -20,6 +20,7 @@ import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSp; import android.net.wifi.hotspot2.pps.Policy; import android.net.wifi.hotspot2.pps.UpdateParameter; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -30,6 +31,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.Objects; @@ -324,6 +326,50 @@ public final class PasspointConfiguration implements Parcelable { } /** + * The map of OSU service provider names whose each element is presented in different + * languages for the service provider, which is used for finding a matching + * PasspointConfiguration with a given service provider name. + */ + private Map<String, String> mServiceFriendlyNames = null; + + /** + * @hide + */ + public void setServiceFriendlyNames(Map<String, String> serviceFriendlyNames) { + mServiceFriendlyNames = serviceFriendlyNames; + } + + /** + * @hide + */ + public Map<String, String> getServiceFriendlyNames() { + return mServiceFriendlyNames; + } + + /** + * Return the friendly Name for current language from the list of friendly names of OSU + * provider. + * The string matching the default locale will be returned if it is found, otherwise the + * first string in the list will be returned. A null will be returned if the list is empty. + * + * @return String matching the default locale, null otherwise + * @hide + */ + public String getServiceFriendlyName() { + if (mServiceFriendlyNames == null || mServiceFriendlyNames.isEmpty()) return null; + String lang = Locale.getDefault().getLanguage(); + String friendlyName = mServiceFriendlyNames.get(lang); + if (friendlyName != null) { + return friendlyName; + } + friendlyName = mServiceFriendlyNames.get("en"); + if (friendlyName != null) { + return friendlyName; + } + return mServiceFriendlyNames.get(mServiceFriendlyNames.keySet().stream().findFirst().get()); + } + + /** * Constructor for creating PasspointConfiguration with default values. */ public PasspointConfiguration() {} @@ -362,6 +408,7 @@ public final class PasspointConfiguration implements Parcelable { mUsageLimitStartTimeInMillis = source.mUsageLimitStartTimeInMillis; mUsageLimitTimeLimitInMinutes = source.mUsageLimitTimeLimitInMinutes; mUsageLimitUsageTimePeriodInMinutes = source.mUsageLimitUsageTimePeriodInMinutes; + mServiceFriendlyNames = source.mServiceFriendlyNames; } @Override @@ -385,6 +432,10 @@ public final class PasspointConfiguration implements Parcelable { dest.writeLong(mUsageLimitStartTimeInMillis); dest.writeLong(mUsageLimitDataLimit); dest.writeLong(mUsageLimitTimeLimitInMinutes); + Bundle bundle = new Bundle(); + bundle.putSerializable("serviceFriendlyNames", + (HashMap<String, String>) mServiceFriendlyNames); + dest.writeBundle(bundle); } @Override @@ -398,10 +449,10 @@ public final class PasspointConfiguration implements Parcelable { PasspointConfiguration that = (PasspointConfiguration) thatObject; return (mHomeSp == null ? that.mHomeSp == null : mHomeSp.equals(that.mHomeSp)) && (mCredential == null ? that.mCredential == null - : mCredential.equals(that.mCredential)) + : mCredential.equals(that.mCredential)) && (mPolicy == null ? that.mPolicy == null : mPolicy.equals(that.mPolicy)) && (mSubscriptionUpdate == null ? that.mSubscriptionUpdate == null - : mSubscriptionUpdate.equals(that.mSubscriptionUpdate)) + : mSubscriptionUpdate.equals(that.mSubscriptionUpdate)) && isTrustRootCertListEquals(mTrustRootCertList, that.mTrustRootCertList) && mUpdateIdentifier == that.mUpdateIdentifier && mCredentialPriority == that.mCredentialPriority @@ -411,7 +462,9 @@ public final class PasspointConfiguration implements Parcelable { && mUsageLimitUsageTimePeriodInMinutes == that.mUsageLimitUsageTimePeriodInMinutes && mUsageLimitStartTimeInMillis == that.mUsageLimitStartTimeInMillis && mUsageLimitDataLimit == that.mUsageLimitDataLimit - && mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes; + && mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes + && (mServiceFriendlyNames == null ? that.mServiceFriendlyNames == null + : mServiceFriendlyNames.equals(that.mServiceFriendlyNames)); } @Override @@ -419,7 +472,8 @@ public final class PasspointConfiguration implements Parcelable { return Objects.hash(mHomeSp, mCredential, mPolicy, mSubscriptionUpdate, mTrustRootCertList, mUpdateIdentifier, mCredentialPriority, mSubscriptionCreationTimeInMillis, mSubscriptionExpirationTimeInMillis, mUsageLimitUsageTimePeriodInMinutes, - mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes); + mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes, + mServiceFriendlyNames); } @Override @@ -463,6 +517,9 @@ public final class PasspointConfiguration implements Parcelable { builder.append("TrustRootCertServers: ").append(mTrustRootCertList.keySet()) .append("\n"); } + if (mServiceFriendlyNames != null) { + builder.append("ServiceFriendlyNames: ").append(mServiceFriendlyNames); + } return builder.toString(); } @@ -562,6 +619,10 @@ public final class PasspointConfiguration implements Parcelable { config.setUsageLimitStartTimeInMillis(in.readLong()); config.setUsageLimitDataLimit(in.readLong()); config.setUsageLimitTimeLimitInMinutes(in.readLong()); + Bundle bundle = in.readBundle(); + Map<String, String> friendlyNamesMap = (HashMap) bundle.getSerializable( + "serviceFriendlyNames"); + config.setServiceFriendlyNames(friendlyNamesMap); return config; } diff --git a/wifi/java/com/android/server/wifi/AbstractWifiService.java b/wifi/java/com/android/server/wifi/AbstractWifiService.java index 0f4e3a8ba20f..e82119fa3577 100644 --- a/wifi/java/com/android/server/wifi/AbstractWifiService.java +++ b/wifi/java/com/android/server/wifi/AbstractWifiService.java @@ -39,6 +39,7 @@ import android.os.ResultReceiver; import android.os.WorkSource; import java.util.List; +import java.util.Map; /** * Abstract class implementing IWifiManager with stub methods throwing runtime exceptions. @@ -127,6 +128,12 @@ public abstract class AbstractWifiService extends IWifiManager.Stub { } @Override + public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders( + List<OsuProvider> osuProviders) { + throw new UnsupportedOperationException(); + } + + @Override public int addOrUpdateNetwork(WifiConfiguration config, String packageName) { throw new UnsupportedOperationException(); } diff --git a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java index d3f91f06da61..89ecd0fd561b 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java @@ -28,9 +28,10 @@ import android.support.test.filters.SmallTest; import org.junit.Test; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Unit tests for {@link android.net.wifi.hotspot2.OsuProvider}. @@ -40,6 +41,15 @@ public class OsuProviderTest { private static final WifiSsid TEST_SSID = WifiSsid.createFromByteArray("TEST SSID".getBytes(StandardCharsets.UTF_8)); private static final String TEST_FRIENDLY_NAME = "Friendly Name"; + private static final Map<String, String> TEST_FRIENDLY_NAMES = + new HashMap<String, String>() { + { + put("en", TEST_FRIENDLY_NAME); + put("kr", TEST_FRIENDLY_NAME + 2); + put("jp", TEST_FRIENDLY_NAME + 3); + } + }; + private static final String TEST_SERVICE_DESCRIPTION = "Dummy Service"; private static final Uri TEST_SERVER_URI = Uri.parse("https://test.com"); private static final String TEST_NAI = "test.access.com"; @@ -59,7 +69,9 @@ public class OsuProviderTest { parcel.setDataPosition(0); // Rewind data position back to the beginning for read. OsuProvider readInfo = OsuProvider.CREATOR.createFromParcel(parcel); + assertEquals(writeInfo, readInfo); + assertEquals(writeInfo.hashCode(), readInfo.hashCode()); } /** @@ -79,8 +91,8 @@ public class OsuProviderTest { */ @Test public void verifyParcelWithFullProviderInfo() throws Exception { - verifyParcel(new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAME, TEST_SERVICE_DESCRIPTION, - TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON)); + verifyParcel(new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES, + TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON)); } /** @@ -100,8 +112,8 @@ public class OsuProviderTest { */ @Test public void verifyCopyConstructorWithValidSource() throws Exception { - OsuProvider source = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAME, TEST_SERVICE_DESCRIPTION, - TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON); + OsuProvider source = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES, + TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON); assertEquals(source, new OsuProvider(source)); } @@ -112,10 +124,12 @@ public class OsuProviderTest { */ @Test public void verifyGetters() throws Exception { - OsuProvider provider = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAME, + OsuProvider provider = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES, TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON); + assertTrue(TEST_SSID.equals(provider.getOsuSsid())); assertTrue(TEST_FRIENDLY_NAME.equals(provider.getFriendlyName())); + assertTrue(TEST_FRIENDLY_NAMES.equals(provider.getFriendlyNameList())); assertTrue(TEST_SERVICE_DESCRIPTION.equals(provider.getServiceDescription())); assertTrue(TEST_SERVER_URI.equals(provider.getServerUri())); assertTrue(TEST_NAI.equals(provider.getNetworkAccessIdentifier())); diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java index 775ce21656f7..ee5a75ebe1b8 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java @@ -166,6 +166,10 @@ public class PasspointConfigurationTest { config.setUsageLimitStartTimeInMillis(124214213); config.setUsageLimitDataLimit(14121); config.setUsageLimitTimeLimitInMinutes(78912); + Map<String, String> friendlyNames = new HashMap<>(); + friendlyNames.put("en", "ServiceName1"); + friendlyNames.put("kr", "ServiceName2"); + config.setServiceFriendlyNames(friendlyNames); return config; } @@ -206,6 +210,18 @@ public class PasspointConfigurationTest { } /** + * Verify parcel read/write for a configuration that doesn't contain a list of service names. + * + * @throws Exception + */ + @Test + public void verifyParcelWithoutServiceNames() throws Exception { + PasspointConfiguration config = createConfig(); + config.setServiceFriendlyNames(null); + verifyParcel(config); + } + + /** * Verify parcel read/write for a configuration that doesn't contain HomeSP. * * @throws Exception |