Merge "Fix a use-of-uninitialized-value warning."
diff --git a/api/current.txt b/api/current.txt
index 6e52af6..550e018 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -60704,6 +60704,9 @@
method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <K, V> java.util.NavigableMap<K, V> checkedNavigableMap(java.util.NavigableMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <E> java.util.NavigableSet<E> checkedNavigableSet(java.util.NavigableSet<E>, java.lang.Class<E>);
+ method public static <E> java.util.Queue<E> checkedQueue(java.util.Queue<E>, java.lang.Class<E>);
method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
@@ -60714,7 +60717,11 @@
method public static final <T> java.util.List<T> emptyList();
method public static <T> java.util.ListIterator<T> emptyListIterator();
method public static final <K, V> java.util.Map<K, V> emptyMap();
+ method public static final <K, V> java.util.NavigableMap<K, V> emptyNavigableMap();
+ method public static <E> java.util.NavigableSet<E> emptyNavigableSet();
method public static final <T> java.util.Set<T> emptySet();
+ method public static final <K, V> java.util.SortedMap<K, V> emptySortedMap();
+ method public static <E> java.util.SortedSet<E> emptySortedSet();
method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
method public static <T> void fill(java.util.List<? super T>, T);
method public static int frequency(java.util.Collection<?>, java.lang.Object);
@@ -60743,12 +60750,16 @@
method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
+ method public static <K, V> java.util.NavigableMap<K, V> synchronizedNavigableMap(java.util.NavigableMap<K, V>);
+ method public static <T> java.util.NavigableSet<T> synchronizedNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
+ method public static <K, V> java.util.NavigableMap<K, V> unmodifiableNavigableMap(java.util.NavigableMap<K, ? extends V>);
+ method public static <T> java.util.NavigableSet<T> unmodifiableNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
diff --git a/api/system-current.txt b/api/system-current.txt
index 17ec7a1..baf5d51 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -64315,6 +64315,9 @@
method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <K, V> java.util.NavigableMap<K, V> checkedNavigableMap(java.util.NavigableMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <E> java.util.NavigableSet<E> checkedNavigableSet(java.util.NavigableSet<E>, java.lang.Class<E>);
+ method public static <E> java.util.Queue<E> checkedQueue(java.util.Queue<E>, java.lang.Class<E>);
method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
@@ -64325,7 +64328,11 @@
method public static final <T> java.util.List<T> emptyList();
method public static <T> java.util.ListIterator<T> emptyListIterator();
method public static final <K, V> java.util.Map<K, V> emptyMap();
+ method public static final <K, V> java.util.NavigableMap<K, V> emptyNavigableMap();
+ method public static <E> java.util.NavigableSet<E> emptyNavigableSet();
method public static final <T> java.util.Set<T> emptySet();
+ method public static final <K, V> java.util.SortedMap<K, V> emptySortedMap();
+ method public static <E> java.util.SortedSet<E> emptySortedSet();
method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
method public static <T> void fill(java.util.List<? super T>, T);
method public static int frequency(java.util.Collection<?>, java.lang.Object);
@@ -64354,12 +64361,16 @@
method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
+ method public static <K, V> java.util.NavigableMap<K, V> synchronizedNavigableMap(java.util.NavigableMap<K, V>);
+ method public static <T> java.util.NavigableSet<T> synchronizedNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
+ method public static <K, V> java.util.NavigableMap<K, V> unmodifiableNavigableMap(java.util.NavigableMap<K, ? extends V>);
+ method public static <T> java.util.NavigableSet<T> unmodifiableNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
diff --git a/api/test-current.txt b/api/test-current.txt
index dc3ea99..87ebde5 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -60795,6 +60795,9 @@
method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <K, V> java.util.NavigableMap<K, V> checkedNavigableMap(java.util.NavigableMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <E> java.util.NavigableSet<E> checkedNavigableSet(java.util.NavigableSet<E>, java.lang.Class<E>);
+ method public static <E> java.util.Queue<E> checkedQueue(java.util.Queue<E>, java.lang.Class<E>);
method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
@@ -60805,7 +60808,11 @@
method public static final <T> java.util.List<T> emptyList();
method public static <T> java.util.ListIterator<T> emptyListIterator();
method public static final <K, V> java.util.Map<K, V> emptyMap();
+ method public static final <K, V> java.util.NavigableMap<K, V> emptyNavigableMap();
+ method public static <E> java.util.NavigableSet<E> emptyNavigableSet();
method public static final <T> java.util.Set<T> emptySet();
+ method public static final <K, V> java.util.SortedMap<K, V> emptySortedMap();
+ method public static <E> java.util.SortedSet<E> emptySortedSet();
method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
method public static <T> void fill(java.util.List<? super T>, T);
method public static int frequency(java.util.Collection<?>, java.lang.Object);
@@ -60834,12 +60841,16 @@
method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
+ method public static <K, V> java.util.NavigableMap<K, V> synchronizedNavigableMap(java.util.NavigableMap<K, V>);
+ method public static <T> java.util.NavigableSet<T> synchronizedNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
+ method public static <K, V> java.util.NavigableMap<K, V> unmodifiableNavigableMap(java.util.NavigableMap<K, ? extends V>);
+ method public static <T> java.util.NavigableSet<T> unmodifiableNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 83d17ba..bd32314 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -805,7 +805,7 @@
if (!mb && records.size() == 0 && !inChunk && !ignoreMbMe) {
throw new FormatException("expected MB flag");
- } else if (mb && records.size() != 0 && !ignoreMbMe) {
+ } else if (mb && (records.size() != 0 || inChunk) && !ignoreMbMe) {
throw new FormatException("unexpected MB flag");
} else if (inChunk && il) {
throw new FormatException("unexpected IL flag in non-leading chunk");
@@ -839,6 +839,9 @@
if (cf && !inChunk) {
// first chunk
+ if (typeLength == 0) {
+ throw new FormatException("expected non-zero type length in first chunk");
+ }
chunks.clear();
chunkTnf = tnf;
}
diff --git a/core/res/res/values-mcc214-mnc01/config.xml b/core/res/res/values-mcc214-mnc01/config.xml
index 895b770..24150a7 100644
--- a/core/res/res/values-mcc214-mnc01/config.xml
+++ b/core/res/res/values-mcc214-mnc01/config.xml
@@ -40,27 +40,4 @@
<item>INTERNET,airtelnet.es,,,vodafone,vodafone,,,,,214,01,1,DUN</item>
</string-array>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-
</resources>
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 4f43eac..6e578b9 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -2018,21 +2018,32 @@
writer.println(" time since enabled: " + onDurationString + "\n");
}
- writer.println("Enable log:");
- for (ActiveLog log : mActiveLogs) {
- writer.println(log);
+ if (mActiveLogs.size() == 0) {
+ writer.println("Bluetooth never enabled!");
+ } else {
+ writer.println("Enable log:");
+ for (ActiveLog log : mActiveLogs) {
+ writer.println(" " + log);
+ }
}
- writer.println("\n" + mBleApps.size() + " BLE Apps registered:");
+ String bleAppString = "No BLE Apps registered.";
+ if (mBleApps.size() == 1) {
+ bleAppString = "1 BLE App registered:";
+ } else if (mBleApps.size() > 1) {
+ bleAppString = mBleApps.size() + " BLE Apps registered:";
+ }
+ writer.println("\n" + bleAppString);
for (ClientDeathRecipient app : mBleApps.values()) {
- writer.println(app.getPackageName());
+ writer.println(" " + app.getPackageName());
}
+ writer.println("");
writer.flush();
if (args.length == 0) {
- // Add arg to produce output
- args = new String[1];
- args[0] = "--print";
+ // Add arg to produce output
+ args = new String[1];
+ args[0] = "--print";
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bc03901..a2963b8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17491,6 +17491,7 @@
// Not backing this app up any more; reset its OOM adjustment
final ProcessRecord proc = mBackupTarget.app;
updateOomAdjLocked(proc);
+ proc.inFullBackup = false;
// If the app crashed during backup, 'thread' will be null here
if (proc.thread != null) {
diff --git a/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java b/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java
index 65a49ea..98fd0f3 100644
--- a/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java
+++ b/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java
@@ -21,11 +21,17 @@
import android.net.wifi.hotspot2.pps.HomeSP;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import java.io.IOException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import org.xml.sax.SAXException;
@@ -131,16 +137,34 @@
private static final String NODE_FQDN = "FQDN";
private static final String NODE_FRIENDLY_NAME = "FriendlyName";
private static final String NODE_ROAMING_CONSORTIUM_OI = "RoamingConsortiumOI";
+ private static final String NODE_NETWORK_ID = "NetworkID";
+ private static final String NODE_SSID = "SSID";
+ private static final String NODE_HESSID = "HESSID";
+ private static final String NODE_ICON_URL = "IconURL";
+ private static final String NODE_HOME_OI_LIST = "HomeOIList";
+ private static final String NODE_HOME_OI = "HomeOI";
+ private static final String NODE_HOME_OI_REQUIRED = "HomeOIRequired";
+ private static final String NODE_OTHER_HOME_PARTNERS = "OtherHomePartners";
/**
* Fields under Credential subtree.
*/
private static final String NODE_CREDENTIAL = "Credential";
+ private static final String NODE_CREATION_DATE = "CreationDate";
+ private static final String NODE_EXPIRATION_DATE = "ExpirationDate";
private static final String NODE_USERNAME_PASSWORD = "UsernamePassword";
private static final String NODE_USERNAME = "Username";
private static final String NODE_PASSWORD = "Password";
+ private static final String NODE_MACHINE_MANAGED = "MachineManaged";
+ private static final String NODE_SOFT_TOKEN_APP = "SoftTokenApp";
+ private static final String NODE_ABLE_TO_SHARE = "AbleToShare";
private static final String NODE_EAP_METHOD = "EAPMethod";
private static final String NODE_EAP_TYPE = "EAPType";
+ private static final String NODE_VENDOR_ID = "VendorId";
+ private static final String NODE_VENDOR_TYPE = "VendorType";
+ private static final String NODE_INNER_EAP_TYPE = "InnerEAPType";
+ private static final String NODE_INNER_VENDOR_ID = "InnerVendorID";
+ private static final String NODE_INNER_VENDOR_TYPE = "InnerVendorType";
private static final String NODE_INNER_METHOD = "InnerMethod";
private static final String NODE_DIGITAL_CERTIFICATE = "DigitalCertificate";
private static final String NODE_CERTIFICATE_TYPE = "CertificateType";
@@ -148,6 +172,7 @@
private static final String NODE_REALM = "Realm";
private static final String NODE_SIM = "SIM";
private static final String NODE_SIM_IMSI = "IMSI";
+ private static final String NODE_CHECK_AAA_SERVER_CERT_STATUS = "CheckAAAServerCertStatus";
/**
* URN (Unique Resource Name) for PerProviderSubscription Management Object Tree.
@@ -558,6 +583,20 @@
homeSp.roamingConsortiumOIs =
parseRoamingConsortiumOI(getPpsNodeValue(child));
break;
+ case NODE_ICON_URL:
+ homeSp.iconUrl = getPpsNodeValue(child);
+ break;
+ case NODE_NETWORK_ID:
+ homeSp.homeNetworkIds = parseNetworkIds(child);
+ break;
+ case NODE_HOME_OI_LIST:
+ Pair<List<Long>, List<Long>> homeOIs = parseHomeOIList(child);
+ homeSp.matchAllOIs = convertFromLongList(homeOIs.first);
+ homeSp.matchAnyOIs = convertFromLongList(homeOIs.second);
+ break;
+ case NODE_OTHER_HOME_PARTNERS:
+ homeSp.otherHomePartners = parseOtherHomePartners(child);
+ break;
default:
throw new ParsingException("Unknown node under HomeSP: " + child.getName());
}
@@ -587,6 +626,192 @@
}
/**
+ * Parse configurations under PerProviderSubscription/HomeSP/NetworkID subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/HomeSP/NetworkID
+ * subtree
+ * @return HashMap<String, Long> representing list of <SSID, HESSID> pair.
+ * @throws ParsingException
+ */
+ static private Map<String, Long> parseNetworkIds(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for NetworkID");
+ }
+
+ Map<String, Long> networkIds = new HashMap<>();
+ for (PPSNode child : node.getChildren()) {
+ Pair<String, Long> networkId = parseNetworkIdInstance(child);
+ networkIds.put(networkId.first, networkId.second);
+ }
+ return networkIds;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/NetworkID/<X+> subtree.
+ * The instance name (<X+>) is irrelevant and must be unique for each instance, which
+ * is verified when the PPS tree is constructed {@link #buildPpsNode}.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/HomeSP/NetworkID/<X+> subtree
+ * @return Pair<String, Long> representing <SSID, HESSID> pair.
+ * @throws ParsingException
+ */
+ static private Pair<String, Long> parseNetworkIdInstance(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for NetworkID instance");
+ }
+
+ String ssid = null;
+ Long hessid = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_SSID:
+ ssid = getPpsNodeValue(child);
+ break;
+ case NODE_HESSID:
+ try {
+ hessid = Long.parseLong(getPpsNodeValue(child), 16);
+ } catch (NumberFormatException e) {
+ throw new ParsingException("Invalid HESSID: " + getPpsNodeValue(child));
+ }
+ break;
+ default:
+ throw new ParsingException("Unknown node under NetworkID instance: " +
+ child.getName());
+ }
+ }
+ if (ssid == null)
+ throw new ParsingException("NetworkID instance missing SSID");
+
+ return new Pair<String, Long>(ssid, hessid);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/HomeOIList subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/HomeSP/HomeOIList
+ * subtree
+ * @return Pair<List<Long>, List<Long>> containing both MatchAllOIs and MatchAnyOIs list.
+ * @throws ParsingException
+ */
+ private static Pair<List<Long>, List<Long>> parseHomeOIList(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for HomeOIList");
+ }
+
+ List<Long> matchAllOIs = new ArrayList<Long>();
+ List<Long> matchAnyOIs = new ArrayList<Long>();
+ for (PPSNode child : node.getChildren()) {
+ Pair<Long, Boolean> homeOI = parseHomeOIInstance(child);
+ if (homeOI.second.booleanValue()) {
+ matchAllOIs.add(homeOI.first);
+ } else {
+ matchAnyOIs.add(homeOI.first);
+ }
+ }
+ return new Pair<List<Long>, List<Long>>(matchAllOIs, matchAnyOIs);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/HomeOIList/<X+> subtree.
+ * The instance name (<X+>) is irrelevant and must be unique for each instance, which
+ * is verified when the PPS tree is constructed {@link #buildPpsNode}.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/HomeSP/HomeOIList/<X+> subtree
+ * @return Pair<Long, Boolean> containing a HomeOI and a HomeOIRequired flag
+ * @throws ParsingException
+ */
+ private static Pair<Long, Boolean> parseHomeOIInstance(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for HomeOI instance");
+ }
+
+ Long oi = null;
+ Boolean required = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_HOME_OI:
+ try {
+ oi = Long.valueOf(getPpsNodeValue(child), 16);
+ } catch (NumberFormatException e) {
+ throw new ParsingException("Invalid HomeOI: " + getPpsNodeValue(child));
+ }
+ break;
+ case NODE_HOME_OI_REQUIRED:
+ required = Boolean.valueOf(getPpsNodeValue(child));
+ break;
+ default:
+ throw new ParsingException("Unknown node under NetworkID instance: " +
+ child.getName());
+ }
+ }
+ if (oi == null) {
+ throw new ParsingException("HomeOI instance missing OI field");
+ }
+ if (required == null) {
+ throw new ParsingException("HomeOI instance missing required field");
+ }
+ return new Pair<Long, Boolean>(oi, required);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/OtherHomePartners subtree.
+ * This contains a list of FQDN (Fully Qualified Domain Name) that are considered
+ * home partners.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/HomeSP/OtherHomePartners subtree
+ * @return String[] list of partner's FQDN
+ * @throws ParsingException
+ */
+ private static String[] parseOtherHomePartners(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for OtherHomePartners");
+ }
+ List<String> otherHomePartners = new ArrayList<String>();
+ for (PPSNode child : node.getChildren()) {
+ String fqdn = parseOtherHomePartnerInstance(child);
+ otherHomePartners.add(fqdn);
+ }
+ return otherHomePartners.toArray(new String[otherHomePartners.size()]);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/OtherHomePartners/<X+> subtree.
+ * The instance name (<X+>) is irrelevant and must be unique for each instance, which
+ * is verified when the PPS tree is constructed {@link #buildPpsNode}.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/HomeSP/OtherHomePartners/<X+> subtree
+ * @return String FQDN of the partner
+ * @throws ParsingException
+ */
+ private static String parseOtherHomePartnerInstance(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for OtherHomePartner instance");
+ }
+ String fqdn = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_FQDN:
+ fqdn = getPpsNodeValue(child);
+ break;
+ default:
+ throw new ParsingException(
+ "Unknown node under OtherHomePartner instance: " + child.getName());
+ }
+ }
+ if (fqdn == null) {
+ throw new ParsingException("OtherHomePartner instance missing FQDN field");
+ }
+ return fqdn;
+ }
+
+ /**
* Parse configurations under PerProviderSubscription/Credential subtree.
*
* @param node PPSNode representing the root of the PerProviderSubscription/Credential subtree
@@ -601,6 +826,12 @@
Credential credential = new Credential();
for (PPSNode child: node.getChildren()) {
switch (child.getName()) {
+ case NODE_CREATION_DATE:
+ credential.creationTimeInMs = parseDate(getPpsNodeValue(child));
+ break;
+ case NODE_EXPIRATION_DATE:
+ credential.expirationTimeInMs = parseDate(getPpsNodeValue(child));
+ break;
case NODE_USERNAME_PASSWORD:
credential.userCredential = parseUserCredential(child);
break;
@@ -610,6 +841,10 @@
case NODE_REALM:
credential.realm = getPpsNodeValue(child);
break;
+ case NODE_CHECK_AAA_SERVER_CERT_STATUS:
+ credential.checkAAAServerCertStatus =
+ Boolean.parseBoolean(getPpsNodeValue(child));
+ break;
case NODE_SIM:
credential.simCredential = parseSimCredential(child);
break;
@@ -644,6 +879,15 @@
case NODE_PASSWORD:
userCred.password = getPpsNodeValue(child);
break;
+ case NODE_MACHINE_MANAGED:
+ userCred.machineManaged = Boolean.parseBoolean(getPpsNodeValue(child));
+ break;
+ case NODE_SOFT_TOKEN_APP:
+ userCred.softTokenApp = getPpsNodeValue(child);
+ break;
+ case NODE_ABLE_TO_SHARE:
+ userCred.ableToShare = Boolean.parseBoolean(getPpsNodeValue(child));
+ break;
case NODE_EAP_METHOD:
parseEAPMethod(child, userCred);
break;
@@ -678,6 +922,15 @@
case NODE_INNER_METHOD:
userCred.nonEapInnerMethod = getPpsNodeValue(child);
break;
+ case NODE_VENDOR_ID:
+ case NODE_VENDOR_TYPE:
+ case NODE_INNER_EAP_TYPE:
+ case NODE_INNER_VENDOR_ID:
+ case NODE_INNER_VENDOR_TYPE:
+ // Only EAP-TTLS is currently supported for user credential, which doesn't
+ // use any of these parameters.
+ Log.d(TAG, "Ignore unsupported EAP method parameter: " + child.getName());
+ break;
default:
throw new ParsingException("Unknown node under EAPMethod: " + child.getName());
}
@@ -770,6 +1023,22 @@
}
/**
+ * Convert a date string to the number of milliseconds since January 1, 1970, 00:00:00 GMT.
+ *
+ * @param dateStr String in the format of yyyy-MM-dd'T'HH:mm:ss'Z'
+ * @return number of milliseconds
+ * @throws ParsingException
+ */
+ private static long parseDate(String dateStr) throws ParsingException {
+ try {
+ DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ return format.parse(dateStr).getTime();
+ } catch (ParseException pe) {
+ throw new ParsingException("Badly formatted time: " + dateStr);
+ }
+ }
+
+ /**
* Parse an integer string.
*
* @param value String of integer value
@@ -783,4 +1052,19 @@
throw new ParsingException("Invalid integer value: " + value);
}
}
+
+ /**
+ * Convert a List<Long> to a primitive long array long[].
+ *
+ * @param list List to be converted
+ * @return long[]
+ */
+ private static long[] convertFromLongList(List<Long> list) {
+ Long[] objectArray = list.toArray(new Long[list.size()]);
+ long[] primitiveArray = new long[objectArray.length];
+ for (int i = 0; i < objectArray.length; i++) {
+ primitiveArray[i] = objectArray[i].longValue();
+ }
+ return primitiveArray;
+ }
}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index 790dfaf..3374f42d 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -23,6 +23,7 @@
import android.text.TextUtils;
import android.util.Log;
+import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
@@ -41,8 +42,6 @@
* In addition to the fields in the Credential subtree, this will also maintain necessary
* information for the private key and certificates associated with this credential.
*
- * Currently we only support the nodes that are used by Hotspot 2.0 Release 1.
- *
* @hide
*/
public final class Credential implements Parcelable {
@@ -52,7 +51,21 @@
* Max string length for realm. Refer to Credential/Realm node in Hotspot 2.0 Release 2
* Technical Specification Section 9.1 for more info.
*/
- private static final int MAX_REALM_LENGTH = 253;
+ private static final int MAX_REALM_BYTES = 253;
+
+ /**
+ * The time this credential is created. It is in the format of number
+ * of milliseconds since January 1, 1970, 00:00:00 GMT.
+ * Using Long.MIN_VALUE to indicate unset value.
+ */
+ public long creationTimeInMs = Long.MIN_VALUE;
+
+ /**
+ * The time this credential will expire. It is in the format of number
+ * of milliseconds since January 1, 1970, 00:00:00 GMT.
+ * Using Long.MIN_VALUE to indicate unset value.
+ */
+ public long expirationTimeInMs = Long.MIN_VALUE;
/**
* The realm associated with this credential. It will be used to determine
@@ -62,6 +75,13 @@
public String realm = null;
/**
+ * When set to true, the device should check AAA (Authentication, Authorization,
+ * and Accounting) server's certificate during EAP (Extensible Authentication
+ * Protocol) authentication.
+ */
+ public boolean checkAAAServerCertStatus = false;
+
+ /**
* Username-password based credential.
* Contains the fields under PerProviderSubscription/Credential/UsernamePassword subtree.
*/
@@ -70,13 +90,13 @@
* Maximum string length for username. Refer to Credential/UsernamePassword/Username
* node in Hotspot 2.0 Release 2 Technical Specification Section 9.1 for more info.
*/
- private static final int MAX_USERNAME_LENGTH = 63;
+ private static final int MAX_USERNAME_BYTES = 63;
/**
* Maximum string length for password. Refer to Credential/UsernamePassword/Password
* in Hotspot 2.0 Release 2 Technical Specification Section 9.1 for more info.
*/
- private static final int MAX_PASSWORD_LENGTH = 255;
+ private static final int MAX_PASSWORD_BYTES = 255;
/**
* Supported Non-EAP inner methods. Refer to
@@ -97,6 +117,21 @@
public String password = null;
/**
+ * Flag indicating if the password is machine managed.
+ */
+ public boolean machineManaged = false;
+
+ /**
+ * The name of the application used to generate the password.
+ */
+ public String softTokenApp = null;
+
+ /**
+ * Flag indicating if this credential is usable on other mobile devices as well.
+ */
+ public boolean ableToShare = false;
+
+ /**
* EAP (Extensible Authentication Protocol) method type.
* Refer to http://www.iana.org/assignments/eap-numbers/eap-numbers.xml#eap-numbers-4
* for valid values.
@@ -123,6 +158,9 @@
if (source != null) {
username = source.username;
password = source.password;
+ machineManaged = source.machineManaged;
+ softTokenApp = source.softTokenApp;
+ ableToShare = source.ableToShare;
eapType = source.eapType;
nonEapInnerMethod = source.nonEapInnerMethod;
}
@@ -137,6 +175,9 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(username);
dest.writeString(password);
+ dest.writeInt(machineManaged ? 1 : 0);
+ dest.writeString(softTokenApp);
+ dest.writeInt(ableToShare ? 1 : 0);
dest.writeInt(eapType);
dest.writeString(nonEapInnerMethod);
}
@@ -151,10 +192,13 @@
}
UserCredential that = (UserCredential) thatObject;
- return TextUtils.equals(username, that.username) &&
- TextUtils.equals(password, that.password) &&
- eapType == that.eapType &&
- TextUtils.equals(nonEapInnerMethod, that.nonEapInnerMethod);
+ return TextUtils.equals(username, that.username)
+ && TextUtils.equals(password, that.password)
+ && machineManaged == that.machineManaged
+ && TextUtils.equals(softTokenApp, that.softTokenApp)
+ && ableToShare == that.ableToShare
+ && eapType == that.eapType
+ && TextUtils.equals(nonEapInnerMethod, that.nonEapInnerMethod);
}
/**
@@ -167,8 +211,9 @@
Log.d(TAG, "Missing username");
return false;
}
- if (username.length() > MAX_USERNAME_LENGTH) {
- Log.d(TAG, "username exceeding maximum length: " + username.length());
+ if (username.getBytes(StandardCharsets.UTF_8).length > MAX_USERNAME_BYTES) {
+ Log.d(TAG, "username exceeding maximum length: "
+ + username.getBytes(StandardCharsets.UTF_8).length);
return false;
}
@@ -176,8 +221,9 @@
Log.d(TAG, "Missing password");
return false;
}
- if (password.length() > MAX_PASSWORD_LENGTH) {
- Log.d(TAG, "password exceeding maximum length: " + password.length());
+ if (password.getBytes(StandardCharsets.UTF_8).length > MAX_PASSWORD_BYTES) {
+ Log.d(TAG, "password exceeding maximum length: "
+ + password.getBytes(StandardCharsets.UTF_8).length);
return false;
}
@@ -202,6 +248,9 @@
UserCredential userCredential = new UserCredential();
userCredential.username = in.readString();
userCredential.password = in.readString();
+ userCredential.machineManaged = in.readInt() != 0;
+ userCredential.softTokenApp = in.readString();
+ userCredential.ableToShare = in.readInt() != 0;
userCredential.eapType = in.readInt();
userCredential.nonEapInnerMethod = in.readString();
return userCredential;
@@ -281,8 +330,8 @@
}
CertificateCredential that = (CertificateCredential) thatObject;
- return TextUtils.equals(certType, that.certType) &&
- Arrays.equals(certSha256FingerPrint, that.certSha256FingerPrint);
+ return TextUtils.equals(certType, that.certType)
+ && Arrays.equals(certSha256FingerPrint, that.certSha256FingerPrint);
}
/**
@@ -295,8 +344,8 @@
Log.d(TAG, "Unsupported certificate type: " + certType);
return false;
}
- if (certSha256FingerPrint == null ||
- certSha256FingerPrint.length != CERT_SHA256_FINGER_PRINT_LENGTH) {
+ if (certSha256FingerPrint == null
+ || certSha256FingerPrint.length != CERT_SHA256_FINGER_PRINT_LENGTH) {
Log.d(TAG, "Invalid SHA-256 fingerprint");
return false;
}
@@ -378,8 +427,8 @@
}
SimCredential that = (SimCredential) thatObject;
- return TextUtils.equals(imsi, that.imsi) &&
- eapType == that.eapType;
+ return TextUtils.equals(imsi, that.imsi)
+ && eapType == that.eapType;
}
@Override
@@ -400,8 +449,8 @@
if (!verifyImsi()) {
return false;
}
- if (eapType != EAPConstants.EAP_SIM && eapType != EAPConstants.EAP_AKA &&
- eapType != EAPConstants.EAP_AKA_PRIME) {
+ if (eapType != EAPConstants.EAP_SIM && eapType != EAPConstants.EAP_AKA
+ && eapType != EAPConstants.EAP_AKA_PRIME) {
Log.d(TAG, "Invalid EAP Type for SIM credential: " + eapType);
return false;
}
@@ -490,7 +539,10 @@
*/
public Credential(Credential source) {
if (source != null) {
+ creationTimeInMs = source.creationTimeInMs;
+ expirationTimeInMs = source.expirationTimeInMs;
realm = source.realm;
+ checkAAAServerCertStatus = source.checkAAAServerCertStatus;
if (source.userCredential != null) {
userCredential = new UserCredential(source.userCredential);
}
@@ -516,7 +568,10 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(creationTimeInMs);
+ dest.writeLong(expirationTimeInMs);
dest.writeString(realm);
+ dest.writeInt(checkAAAServerCertStatus ? 1 : 0);
dest.writeParcelable(userCredential, flags);
dest.writeParcelable(certCredential, flags);
dest.writeParcelable(simCredential, flags);
@@ -535,16 +590,19 @@
}
Credential that = (Credential) thatObject;
- return TextUtils.equals(realm, that.realm) &&
- (userCredential == null ? that.userCredential == null :
- userCredential.equals(that.userCredential)) &&
- (certCredential == null ? that.certCredential == null :
- certCredential.equals(that.certCredential)) &&
- (simCredential == null ? that.simCredential == null :
- simCredential.equals(that.simCredential)) &&
- isX509CertificateEquals(caCertificate, that.caCertificate) &&
- isX509CertificatesEquals(clientCertificateChain, that.clientCertificateChain) &&
- isPrivateKeyEquals(clientPrivateKey, that.clientPrivateKey);
+ return TextUtils.equals(realm, that.realm)
+ && creationTimeInMs == that.creationTimeInMs
+ && expirationTimeInMs == that.expirationTimeInMs
+ && checkAAAServerCertStatus == that.checkAAAServerCertStatus
+ && (userCredential == null ? that.userCredential == null
+ : userCredential.equals(that.userCredential))
+ && (certCredential == null ? that.certCredential == null
+ : certCredential.equals(that.certCredential))
+ && (simCredential == null ? that.simCredential == null
+ : simCredential.equals(that.simCredential))
+ && isX509CertificateEquals(caCertificate, that.caCertificate)
+ && isX509CertificatesEquals(clientCertificateChain, that.clientCertificateChain)
+ && isPrivateKeyEquals(clientPrivateKey, that.clientPrivateKey);
}
/**
@@ -557,8 +615,9 @@
Log.d(TAG, "Missing realm");
return false;
}
- if (realm.length() > MAX_REALM_LENGTH) {
- Log.d(TAG, "realm exceeding maximum length: " + realm.length());
+ if (realm.getBytes(StandardCharsets.UTF_8).length > MAX_REALM_BYTES) {
+ Log.d(TAG, "realm exceeding maximum length: "
+ + realm.getBytes(StandardCharsets.UTF_8).length);
return false;
}
@@ -588,7 +647,10 @@
@Override
public Credential createFromParcel(Parcel in) {
Credential credential = new Credential();
+ credential.creationTimeInMs = in.readLong();
+ credential.expirationTimeInMs = in.readLong();
credential.realm = in.readString();
+ credential.checkAAAServerCertStatus = in.readInt() != 0;
credential.userCredential = in.readParcelable(null);
credential.certCredential = in.readParcelable(null);
credential.simCredential = in.readParcelable(null);
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
index d4a5792..4ddf210 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
@@ -21,7 +21,11 @@
import android.text.TextUtils;
import android.util.Log;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
/**
* Class representing HomeSP subtree in PerProviderSubscription (PPS)
@@ -30,14 +34,22 @@
* For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
* Release 2 Technical Specification.
*
- * Currently we only support the nodes that are used by Hotspot 2.0 Release 1.
- *
* @hide
*/
public final class HomeSP implements Parcelable {
private static final String TAG = "HomeSP";
/**
+ * Maximum number of bytes allowed for a SSID.
+ */
+ private static final int MAX_SSID_BYTES = 32;
+
+ /**
+ * Integer value used for indicating null value in the Parcel.
+ */
+ private static final int NULL_VALUE = -1;
+
+ /**
* FQDN (Fully Qualified Domain Name) of this home service provider.
*/
public String fqdn = null;
@@ -48,6 +60,55 @@
public String friendlyName = null;
/**
+ * Icon URL of this home service provider.
+ */
+ public String iconUrl = null;
+
+ /**
+ * <SSID, HESSID> duple of the networks that are consider home networks.
+ *
+ * According to the Section 9.1.2 of the Hotspot 2.0 Release 2 Technical Specification,
+ * all nodes in the PSS MO are encoded using UTF-8 unless stated otherwise. Thus, the SSID
+ * string is assumed to be encoded using UTF-8.
+ */
+ public Map<String, Long> homeNetworkIds = null;
+
+ /**
+ * Used for determining if this provider is a member of a given Hotspot provider.
+ * Every Organization Identifiers (OIs) in this list are required to match an OI in the
+ * the Roaming Consortium advertised by a Hotspot, in order to consider this provider
+ * as a member of that Hotspot provider (e.g. successful authentication with such Hotspot
+ * is possible).
+ *
+ * Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object
+ * (MO) tree for more detail.
+ */
+ public long[] matchAllOIs = null;
+
+ /**
+ * Used for determining if this provider is a member of a given Hotspot provider.
+ * Matching of any Organization Identifiers (OIs) in this list with an OI in the
+ * Roaming Consortium advertised by a Hotspot, will consider this provider as a member
+ * of that Hotspot provider (e.g. successful authentication with such Hotspot
+ * is possible).
+ *
+ * {@link #matchAllOIs} will have precedence over this one, meaning this list will
+ * only be used for matching if {@link #matchAllOIs} is null or empty.
+ *
+ * Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object
+ * (MO) tree for more detail.
+ */
+ public long[] matchAnyOIs = null;
+
+ /**
+ * List of FQDN (Fully Qualified Domain Name) of partner providers.
+ * These providers should also be regarded as home Hotspot operators.
+ * This relationship is most likely achieved via a commercial agreement or
+ * operator merges between the providers.
+ */
+ public String[] otherHomePartners = null;
+
+ /**
* List of Organization Identifiers (OIs) identifying a roaming consortium of
* which this provider is a member.
*/
@@ -64,13 +125,28 @@
* @param source The source to copy from
*/
public HomeSP(HomeSP source) {
- if (source != null) {
- fqdn = source.fqdn;
- friendlyName = source.friendlyName;
- if (source.roamingConsortiumOIs != null) {
- roamingConsortiumOIs = Arrays.copyOf(source.roamingConsortiumOIs,
- source.roamingConsortiumOIs.length);
- }
+ if (source == null) {
+ return;
+ }
+ fqdn = source.fqdn;
+ friendlyName = source.friendlyName;
+ iconUrl = source.iconUrl;
+ if (source.homeNetworkIds != null) {
+ homeNetworkIds = Collections.unmodifiableMap(source.homeNetworkIds);
+ }
+ if (source.matchAllOIs != null) {
+ matchAllOIs = Arrays.copyOf(source.matchAllOIs, source.matchAllOIs.length);
+ }
+ if (source.matchAnyOIs != null) {
+ matchAnyOIs = Arrays.copyOf(source.matchAnyOIs, source.matchAnyOIs.length);
+ }
+ if (source.otherHomePartners != null) {
+ otherHomePartners = Arrays.copyOf(source.otherHomePartners,
+ source.otherHomePartners.length);
+ }
+ if (source.roamingConsortiumOIs != null) {
+ roamingConsortiumOIs = Arrays.copyOf(source.roamingConsortiumOIs,
+ source.roamingConsortiumOIs.length);
}
}
@@ -83,6 +159,11 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(fqdn);
dest.writeString(friendlyName);
+ dest.writeString(iconUrl);
+ writeHomeNetworkIds(dest, homeNetworkIds);
+ dest.writeLongArray(matchAllOIs);
+ dest.writeLongArray(matchAnyOIs);
+ dest.writeStringArray(otherHomePartners);
dest.writeLongArray(roamingConsortiumOIs);
}
@@ -96,9 +177,15 @@
}
HomeSP that = (HomeSP) thatObject;
- return TextUtils.equals(fqdn, that.fqdn) &&
- TextUtils.equals(friendlyName, that.friendlyName) &&
- Arrays.equals(roamingConsortiumOIs, that.roamingConsortiumOIs);
+ return TextUtils.equals(fqdn, that.fqdn)
+ && TextUtils.equals(friendlyName, that.friendlyName)
+ && TextUtils.equals(iconUrl, that.iconUrl)
+ && (homeNetworkIds == null ? that.homeNetworkIds == null
+ : homeNetworkIds.equals(that.homeNetworkIds))
+ && Arrays.equals(matchAllOIs, that.matchAllOIs)
+ && Arrays.equals(matchAnyOIs, that.matchAnyOIs)
+ && Arrays.equals(otherHomePartners, that.otherHomePartners)
+ && Arrays.equals(roamingConsortiumOIs, that.roamingConsortiumOIs);
}
/**
@@ -115,6 +202,16 @@
Log.d(TAG, "Missing friendly name");
return false;
}
+ // Verify SSIDs specified in the NetworkID
+ if (homeNetworkIds != null) {
+ for (Map.Entry<String, Long> entry : homeNetworkIds.entrySet()) {
+ if (entry.getKey() == null ||
+ entry.getKey().getBytes(StandardCharsets.UTF_8).length > MAX_SSID_BYTES) {
+ Log.d(TAG, "Invalid SSID in HomeNetworkIDs");
+ return false;
+ }
+ }
+ }
return true;
}
@@ -125,6 +222,11 @@
HomeSP homeSp = new HomeSP();
homeSp.fqdn = in.readString();
homeSp.friendlyName = in.readString();
+ homeSp.iconUrl = in.readString();
+ homeSp.homeNetworkIds = readHomeNetworkIds(in);
+ homeSp.matchAllOIs = in.createLongArray();
+ homeSp.matchAnyOIs = in.createLongArray();
+ homeSp.otherHomePartners = in.createStringArray();
homeSp.roamingConsortiumOIs = in.createLongArray();
return homeSp;
}
@@ -133,5 +235,51 @@
public HomeSP[] newArray(int size) {
return new HomeSP[size];
}
+
+ /**
+ * Helper function for reading a Home Network IDs map from a Parcel.
+ *
+ * @param in The Parcel to read from
+ * @return Map of home network IDs
+ */
+ private Map<String, Long> readHomeNetworkIds(Parcel in) {
+ int size = in.readInt();
+ if (size == NULL_VALUE) {
+ return null;
+ }
+ Map<String, Long> networkIds = new HashMap<>(size);
+ for (int i = 0; i < size; i++) {
+ String key = in.readString();
+ Long value = null;
+ long readValue = in.readLong();
+ if (readValue != NULL_VALUE) {
+ value = Long.valueOf(readValue);
+ }
+ networkIds.put(key, value);
+ }
+ return networkIds;
+ }
};
+
+ /**
+ * Helper function for writing Home Network IDs map to a Parcel.
+ *
+ * @param dest The Parcel to write to
+ * @param networkIds The map of home network IDs
+ */
+ private static void writeHomeNetworkIds(Parcel dest, Map<String, Long> networkIds) {
+ if (networkIds == null) {
+ dest.writeInt(NULL_VALUE);
+ return;
+ }
+ dest.writeInt(networkIds.size());
+ for (Map.Entry<String, Long> entry : networkIds.entrySet()) {
+ dest.writeString(entry.getKey());
+ if (entry.getValue() == null) {
+ dest.writeLong(NULL_VALUE);
+ } else {
+ dest.writeLong(entry.getValue());
+ }
+ }
+ }
}
diff --git a/wifi/tests/assets/pps/PerProviderSubscription.xml b/wifi/tests/assets/pps/PerProviderSubscription.xml
index 53d38ad..3969f69 100644
--- a/wifi/tests/assets/pps/PerProviderSubscription.xml
+++ b/wifi/tests/assets/pps/PerProviderSubscription.xml
@@ -23,14 +23,86 @@
<NodeName>RoamingConsortiumOI</NodeName>
<Value>112233,445566</Value>
</Node>
+ <Node>
+ <NodeName>IconURL</NodeName>
+ <Value>icon.test.com</Value>
+ </Node>
+ <Node>
+ <NodeName>NetworkID</NodeName>
+ <Node>
+ <NodeName>n001</NodeName>
+ <Node>
+ <NodeName>SSID</NodeName>
+ <Value>TestSSID</Value>
+ </Node>
+ <Node>
+ <NodeName>HESSID</NodeName>
+ <Value>12345678</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>n002</NodeName>
+ <Node>
+ <NodeName>SSID</NodeName>
+ <Value>NullHESSID</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>HomeOIList</NodeName>
+ <Node>
+ <NodeName>h001</NodeName>
+ <Node>
+ <NodeName>HomeOI</NodeName>
+ <Value>11223344</Value>
+ </Node>
+ <Node>
+ <NodeName>HomeOIRequired</NodeName>
+ <Value>true</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>h002</NodeName>
+ <Node>
+ <NodeName>HomeOI</NodeName>
+ <Value>55667788</Value>
+ </Node>
+ <Node>
+ <NodeName>HomeOIRequired</NodeName>
+ <Value>false</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>OtherHomePartners</NodeName>
+ <Node>
+ <NodeName>o001</NodeName>
+ <Node>
+ <NodeName>FQDN</NodeName>
+ <Value>other.fqdn.com</Value>
+ </Node>
+ </Node>
+ </Node>
</Node>
<Node>
<NodeName>Credential</NodeName>
<Node>
+ <NodeName>CreationDate</NodeName>
+ <Value>2016-01-01T10:00:00Z</Value>
+ </Node>
+ <Node>
+ <NodeName>ExpirationDate</NodeName>
+ <Value>2016-02-01T10:00:00Z</Value>
+ </Node>
+ <Node>
<NodeName>Realm</NodeName>
<Value>shaken.stirred.com</Value>
</Node>
<Node>
+ <NodeName>CheckAAAServerCertStatus</NodeName>
+ <Value>true</Value>
+ </Node>
+ <Node>
<NodeName>UsernamePassword</NodeName>
<Node>
<NodeName>Username</NodeName>
@@ -41,6 +113,18 @@
<Value>Ym9uZDAwNw==</Value>
</Node>
<Node>
+ <NodeName>MachineManaged</NodeName>
+ <Value>true</Value>
+ </Node>
+ <Node>
+ <NodeName>SoftTokenApp</NodeName>
+ <Value>TestApp</Value>
+ </Node>
+ <Node>
+ <NodeName>AbleToShare</NodeName>
+ <Value>true</Value>
+ </Node>
+ <Node>
<NodeName>EAPMethod</NodeName>
<Node>
<NodeName>EAPType</NodeName>
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java
index 10b0267..1c7508e 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java
@@ -31,7 +31,10 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
import java.util.Arrays;
+import java.util.HashMap;
/**
* Unit tests for {@link android.net.wifi.hotspot2.omadm.PPSMOParser}.
@@ -77,7 +80,7 @@
*
* @return {@link PasspointConfiguration}
*/
- private PasspointConfiguration generateConfigurationFromPPSMOTree() {
+ private PasspointConfiguration generateConfigurationFromPPSMOTree() throws Exception {
PasspointConfiguration config = new PasspointConfiguration();
// HomeSP configuration.
@@ -85,13 +88,27 @@
config.homeSp.friendlyName = "Century House";
config.homeSp.fqdn = "mi6.co.uk";
config.homeSp.roamingConsortiumOIs = new long[] {0x112233L, 0x445566L};
+ config.homeSp.iconUrl = "icon.test.com";
+ config.homeSp.homeNetworkIds = new HashMap<>();
+ config.homeSp.homeNetworkIds.put("TestSSID", 0x12345678L);
+ config.homeSp.homeNetworkIds.put("NullHESSID", null);
+ config.homeSp.matchAllOIs = new long[] {0x11223344};
+ config.homeSp.matchAnyOIs = new long[] {0x55667788};
+ config.homeSp.otherHomePartners = new String[] {"other.fqdn.com"};
// Credential configuration.
+ DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
config.credential = new Credential();
+ config.credential.creationTimeInMs = format.parse("2016-01-01T10:00:00Z").getTime();
+ config.credential.expirationTimeInMs = format.parse("2016-02-01T10:00:00Z").getTime();
config.credential.realm = "shaken.stirred.com";
+ config.credential.checkAAAServerCertStatus = true;
config.credential.userCredential = new Credential.UserCredential();
config.credential.userCredential.username = "james";
config.credential.userCredential.password = "Ym9uZDAwNw==";
+ config.credential.userCredential.machineManaged = true;
+ config.credential.userCredential.softTokenApp = "TestApp";
+ config.credential.userCredential.ableToShare = true;
config.credential.userCredential.eapType = 21;
config.credential.userCredential.nonEapInnerMethod = "MS-CHAP-V2";
config.credential.certCredential = new Credential.CertificateCredential();
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
index 9c8b749..f571c7f 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
@@ -37,6 +37,17 @@
*/
@SmallTest
public class CredentialTest {
+ /**
+ * Helper function for generating Credential for testing.
+ *
+ * @param userCred Instance of UserCredential
+ * @param certCred Instance of CertificateCredential
+ * @param simCred Instance of SimCredential
+ * @param caCert CA certificate
+ * @param clientCertificateChain Chain of client certificates
+ * @param clientPrivateKey Client private key
+ * @return {@link Credential}
+ */
private static Credential createCredential(Credential.UserCredential userCred,
Credential.CertificateCredential certCred,
Credential.SimCredential simCred,
@@ -44,7 +55,10 @@
X509Certificate[] clientCertificateChain,
PrivateKey clientPrivateKey) {
Credential cred = new Credential();
+ cred.creationTimeInMs = 123455L;
+ cred.expirationTimeInMs = 2310093L;
cred.realm = "realm";
+ cred.checkAAAServerCertStatus = true;
cred.userCredential = userCred;
cred.certCredential = certCred;
cred.simCredential = simCred;
@@ -54,6 +68,11 @@
return cred;
}
+ /**
+ * Helper function for generating certificate credential for testing.
+ *
+ * @return {@link Credential}
+ */
private static Credential createCredentialWithCertificateCredential() {
Credential.CertificateCredential certCred = new Credential.CertificateCredential();
certCred.certType = "x509v3";
@@ -62,6 +81,11 @@
new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1);
}
+ /**
+ * Helper function for generating SIM credential for testing.
+ *
+ * @return {@link Credential}
+ */
private static Credential createCredentialWithSimCredential() {
Credential.SimCredential simCred = new Credential.SimCredential();
simCred.imsi = "1234*";
@@ -69,10 +93,18 @@
return createCredential(null, null, simCred, null, null, null);
}
+ /**
+ * Helper function for generating user credential for testing.
+ *
+ * @return {@link Credential}
+ */
private static Credential createCredentialWithUserCredential() {
Credential.UserCredential userCred = new Credential.UserCredential();
userCred.username = "username";
userCred.password = "password";
+ userCred.machineManaged = true;
+ userCred.ableToShare = true;
+ userCred.softTokenApp = "TestApp";
userCred.eapType = EAPConstants.EAP_TTLS;
userCred.nonEapInnerMethod = "MS-CHAP";
return createCredential(userCred, null, null, FakeKeys.CA_CERT0,
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
index c707993..45fdbea 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
@@ -24,19 +24,71 @@
import org.junit.Test;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* Unit tests for {@link android.net.wifi.hotspot2.pps.HomeSP}.
*/
@SmallTest
public class HomeSPTest {
- private static HomeSP createHomeSp() {
+
+ /**
+ * Helper function for creating a map of home network IDs for testing.
+ *
+ * @return Map of home network IDs
+ */
+ private static Map<String, Long> createHomeNetworkIds() {
+ Map<String, Long> homeNetworkIds = new HashMap<>();
+ homeNetworkIds.put("ssid", 0x1234L);
+ homeNetworkIds.put("nullhessid", null);
+ return homeNetworkIds;
+ }
+
+ /**
+ * Helper function for creating a HomeSP for testing.
+ *
+ * @param homeNetworkIds The map of home network IDs associated with HomeSP
+ * @return {@link HomeSP}
+ */
+ private static HomeSP createHomeSp(Map<String, Long> homeNetworkIds) {
HomeSP homeSp = new HomeSP();
homeSp.fqdn = "fqdn";
homeSp.friendlyName = "friendly name";
+ homeSp.iconUrl = "icon.url";
+ homeSp.homeNetworkIds = homeNetworkIds;
+ homeSp.matchAllOIs = new long[] {0x11L, 0x22L};
+ homeSp.matchAnyOIs = new long[] {0x33L, 0x44L};
+ homeSp.otherHomePartners = new String[] {"partner1", "partner2"};
homeSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
return homeSp;
}
+ /**
+ * Helper function for creating a HomeSP with home network IDs for testing.
+ *
+ * @return {@link HomeSP}
+ */
+ private static HomeSP createHomeSpWithHomeNetworkIds() {
+ return createHomeSp(createHomeNetworkIds());
+ }
+
+ /**
+ * Helper function for creating a HomeSP without home network IDs for testing.
+ *
+ * @return {@link HomeSP}
+ */
+ private static HomeSP createHomeSpWithoutHomeNetworkIds() {
+ return createHomeSp(null);
+ }
+
+ /**
+ * Helper function for verifying HomeSP after parcel write then read.
+ * @param writeHomeSp
+ * @throws Exception
+ */
private static void verifyParcel(HomeSP writeHomeSp) throws Exception {
Parcel parcel = Parcel.obtain();
writeHomeSp.writeToParcel(parcel, 0);
@@ -57,13 +109,23 @@
}
/**
- * Verify parcel read/write for a valid HomeSP.
+ * Verify parcel read/write for a HomeSP containing Home Network IDs.
*
* @throws Exception
*/
@Test
- public void verifyParcelWithValidHomeSP() throws Exception {
- verifyParcel(createHomeSp());
+ public void verifyParcelWithHomeNetworkIds() throws Exception {
+ verifyParcel(createHomeSpWithHomeNetworkIds());
+ }
+
+ /**
+ * Verify parcel read/write for a HomeSP without Home Network IDs.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutHomeNetworkIds() throws Exception {
+ verifyParcel(createHomeSpWithoutHomeNetworkIds());
}
/**
@@ -120,6 +182,49 @@
}
/**
+ * Verify that a HomeSP is valid when the optional Home Network IDs are
+ * provided.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateHomeSpWithHomeNetworkIds() throws Exception {
+ HomeSP homeSp = createHomeSpWithHomeNetworkIds();
+ assertTrue(homeSp.validate());
+ }
+
+ /**
+ * Verify that a HomeSP is valid when the optional Home Network IDs are
+ * not provided.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateHomeSpWithoutHomeNetworkIds() throws Exception {
+ HomeSP homeSp = createHomeSpWithoutHomeNetworkIds();
+ assertTrue(homeSp.validate());
+ }
+
+ /**
+ * Verify that a HomeSP is invalid when the optional Home Network IDs
+ * contained an invalid SSID (exceeding maximum number of bytes).
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateHomeSpWithInvalidHomeNetworkIds() throws Exception {
+ HomeSP homeSp = new HomeSP();
+ homeSp.fqdn = "fqdn";
+ homeSp.friendlyName = "friendly name";
+ homeSp.homeNetworkIds = new HashMap<>();
+ byte[] rawSsidBytes = new byte[33];
+ Arrays.fill(rawSsidBytes, (byte) 'a');
+ homeSp.homeNetworkIds.put(
+ StringFactory.newStringFromBytes(rawSsidBytes, StandardCharsets.UTF_8), 0x1234L);
+ assertFalse(homeSp.validate());
+ }
+
+ /**
* Verify that copy constructor works when pass in a null source.
*
* @throws Exception
@@ -138,10 +243,7 @@
*/
@Test
public void validateCopyConstructorFromValidSource() throws Exception {
- HomeSP sourceSp = new HomeSP();
- sourceSp.fqdn = "fqdn";
- sourceSp.friendlyName = "friendlyName";
- sourceSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
+ HomeSP sourceSp = createHomeSpWithHomeNetworkIds();
HomeSP copySp = new HomeSP(sourceSp);
assertTrue(copySp.equals(sourceSp));
}