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));
     }