Merge "Indicate local and remote RX/TX capabilities for VT." into m-wireless-dev
diff --git a/Android.mk b/Android.mk
index 3b1991c..81113f7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -386,6 +386,7 @@
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
 	wifi/java/android/net/wifi/IWifiScanner.aidl \
 	wifi/java/android/net/wifi/IRttManager.aidl \
+	wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl \
 	packages/services/PacProcessor/com/android/net/IProxyService.aidl \
 	packages/services/Proxy/com/android/net/IProxyCallback.aidl \
 	packages/services/Proxy/com/android/net/IProxyPortListener.aidl \
diff --git a/api/current.txt b/api/current.txt
index a79b6e4..4663a0d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -17867,9 +17867,18 @@
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public java.lang.String BSSID;
+    field public static final int CHANNEL_WIDTH_160MHZ = 3; // 0x3
+    field public static final int CHANNEL_WIDTH_20MHZ = 0; // 0x0
+    field public static final int CHANNEL_WIDTH_40MHZ = 1; // 0x1
+    field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2
+    field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4
     field public java.lang.String SSID;
     field public java.lang.String capabilities;
+    field public int centerFreq0;
+    field public int centerFreq1;
+    field public int channelWidth;
     field public int frequency;
+    field public boolean is80211McRTTResponder;
     field public int level;
     field public long timestamp;
   }
@@ -17907,11 +17916,15 @@
     field public java.util.BitSet allowedKeyManagement;
     field public java.util.BitSet allowedPairwiseCiphers;
     field public java.util.BitSet allowedProtocols;
+    field public int apBand;
+    field public int apChannel;
     field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
     field public boolean hiddenSSID;
     field public int networkId;
     field public java.lang.String preSharedKey;
     field public int priority;
+    field public java.lang.String providerFriendlyName;
+    field public java.util.HashSet<java.lang.Long> roamingConsortiumIds;
     field public int status;
     field public java.lang.String[] wepKeys;
     field public int wepTxKeyIndex;
@@ -17969,6 +17982,7 @@
     ctor public WifiEnterpriseConfig();
     ctor public WifiEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
     method public int describeContents();
+    method public java.lang.String getAltSubjectMatch();
     method public java.lang.String getAnonymousIdentity();
     method public java.security.cert.X509Certificate getCaCertificate();
     method public java.security.cert.X509Certificate getClientCertificate();
@@ -17976,7 +17990,10 @@
     method public java.lang.String getIdentity();
     method public java.lang.String getPassword();
     method public int getPhase2Method();
-    method public java.lang.String getSubjectMatch();
+    method public java.lang.String getPlmn();
+    method public java.lang.String getRealm();
+    method public deprecated java.lang.String getSubjectMatch();
+    method public void setAltSubjectMatch(java.lang.String);
     method public void setAnonymousIdentity(java.lang.String);
     method public void setCaCertificate(java.security.cert.X509Certificate);
     method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
@@ -17984,7 +18001,9 @@
     method public void setIdentity(java.lang.String);
     method public void setPassword(java.lang.String);
     method public void setPhase2Method(int);
-    method public void setSubjectMatch(java.lang.String);
+    method public void setPlmn(java.lang.String);
+    method public void setRealm(java.lang.String);
+    method public deprecated void setSubjectMatch(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.wifi.WifiEnterpriseConfig> CREATOR;
   }
@@ -25862,6 +25881,7 @@
 
   public static final class VoicemailContract.Status implements android.provider.BaseColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
+    method public static void setStatus(android.content.Context, android.telecom.PhoneAccountHandle, int, int, int);
     field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
     field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
     field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
@@ -28327,22 +28347,6 @@
     method public android.telecom.Voicemail.Builder setUri(android.net.Uri);
   }
 
-  public class VvmSyncService extends android.app.Service {
-    ctor public VvmSyncService();
-    method public android.os.IBinder onBind(android.content.Intent);
-  }
-
-  public class VvmSyncService.VvmSyncAdapter extends android.content.AbstractThreadedSyncAdapter {
-    ctor public VvmSyncService.VvmSyncAdapter(android.content.Context, boolean);
-    method protected java.util.List<android.telecom.Voicemail> downloadVoicemails();
-    method public void onPerformSync(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.ContentProviderClient, android.content.SyncResult);
-    method protected void syncToServer();
-    field public static final java.lang.String NEW_VOICEMAIL_DATA = "extra_new_voicemail_data";
-    field public static final java.lang.String SYNC_EXTRA_CODE = "sync_extra_code";
-    field public static final int SYNC_EXTRA_MAILBOX_UPDATE = 2; // 0x2
-    field public static final int SYNC_EXTRA_NEW_VOICEMAIL = 1; // 0x1
-  }
-
 }
 
 package android.telephony {
diff --git a/api/system-current.txt b/api/system-current.txt
index 391ec37..ec0559f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -19294,9 +19294,18 @@
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public java.lang.String BSSID;
+    field public static final int CHANNEL_WIDTH_160MHZ = 3; // 0x3
+    field public static final int CHANNEL_WIDTH_20MHZ = 0; // 0x0
+    field public static final int CHANNEL_WIDTH_40MHZ = 1; // 0x1
+    field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2
+    field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4
     field public java.lang.String SSID;
     field public java.lang.String capabilities;
+    field public int centerFreq0;
+    field public int centerFreq1;
+    field public int channelWidth;
     field public int frequency;
+    field public boolean is80211McRTTResponder;
     field public int level;
     field public long timestamp;
   }
@@ -19334,6 +19343,8 @@
     field public java.util.BitSet allowedKeyManagement;
     field public java.util.BitSet allowedPairwiseCiphers;
     field public java.util.BitSet allowedProtocols;
+    field public int apBand;
+    field public int apChannel;
     field public int creatorUid;
     field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
     field public boolean hiddenSSID;
@@ -19344,6 +19355,8 @@
     field public int numScorerOverrideAndSwitchedNetwork;
     field public java.lang.String preSharedKey;
     field public int priority;
+    field public java.lang.String providerFriendlyName;
+    field public java.util.HashSet<java.lang.Long> roamingConsortiumIds;
     field public int status;
     field public java.lang.String[] wepKeys;
     field public int wepTxKeyIndex;
@@ -19416,6 +19429,7 @@
     ctor public WifiEnterpriseConfig();
     ctor public WifiEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
     method public int describeContents();
+    method public java.lang.String getAltSubjectMatch();
     method public java.lang.String getAnonymousIdentity();
     method public java.security.cert.X509Certificate getCaCertificate();
     method public java.security.cert.X509Certificate getClientCertificate();
@@ -19423,7 +19437,10 @@
     method public java.lang.String getIdentity();
     method public java.lang.String getPassword();
     method public int getPhase2Method();
-    method public java.lang.String getSubjectMatch();
+    method public java.lang.String getPlmn();
+    method public java.lang.String getRealm();
+    method public deprecated java.lang.String getSubjectMatch();
+    method public void setAltSubjectMatch(java.lang.String);
     method public void setAnonymousIdentity(java.lang.String);
     method public void setCaCertificate(java.security.cert.X509Certificate);
     method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
@@ -19431,7 +19448,9 @@
     method public void setIdentity(java.lang.String);
     method public void setPassword(java.lang.String);
     method public void setPhase2Method(int);
-    method public void setSubjectMatch(java.lang.String);
+    method public void setPlmn(java.lang.String);
+    method public void setRealm(java.lang.String);
+    method public deprecated void setSubjectMatch(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.wifi.WifiEnterpriseConfig> CREATOR;
   }
@@ -19595,9 +19614,11 @@
     method public void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings);
     method public android.net.wifi.ScanResult[] getScanResults();
     method public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
+    method public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
     method public void startTrackingBssids(android.net.wifi.WifiScanner.BssidInfo[], int, android.net.wifi.WifiScanner.BssidListener);
     method public void startTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
     method public void stopBackgroundScan(android.net.wifi.WifiScanner.ScanListener);
+    method public void stopScan(android.net.wifi.WifiScanner.ScanListener);
     method public void stopTrackingBssids(android.net.wifi.WifiScanner.BssidListener);
     method public void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
     field public static final int MAX_SCAN_PERIOD_MS = 1024000; // 0xfa000
@@ -19634,6 +19655,7 @@
 
   public static abstract interface WifiScanner.BssidListener implements android.net.wifi.WifiScanner.ActionListener {
     method public abstract void onFound(android.net.wifi.ScanResult[]);
+    method public abstract void onLost(android.net.wifi.ScanResult[]);
   }
 
   public static class WifiScanner.ChannelSpec {
@@ -19649,10 +19671,37 @@
     field public android.net.wifi.WifiScanner.BssidInfo[] bssidInfos;
   }
 
+  public static class WifiScanner.ParcelableScanData implements android.os.Parcelable {
+    ctor public WifiScanner.ParcelableScanData(android.net.wifi.WifiScanner.ScanData[]);
+    method public int describeContents();
+    method public android.net.wifi.WifiScanner.ScanData[] getResults();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public android.net.wifi.WifiScanner.ScanData[] mResults;
+  }
+
+  public static class WifiScanner.ParcelableScanResults implements android.os.Parcelable {
+    ctor public WifiScanner.ParcelableScanResults(android.net.wifi.ScanResult[]);
+    method public int describeContents();
+    method public android.net.wifi.ScanResult[] getResults();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public android.net.wifi.ScanResult[] mResults;
+  }
+
+  public static class WifiScanner.ScanData implements android.os.Parcelable {
+    ctor public WifiScanner.ScanData(int, int, android.net.wifi.ScanResult[]);
+    ctor public WifiScanner.ScanData(android.net.wifi.WifiScanner.ScanData);
+    method public int describeContents();
+    method public int getFlags();
+    method public int getId();
+    method public android.net.wifi.ScanResult[] getResults();
+    method public void writeToParcel(android.os.Parcel, int);
+  }
+
   public static abstract interface WifiScanner.ScanListener implements android.net.wifi.WifiScanner.ActionListener {
     method public abstract void onFullResult(android.net.wifi.ScanResult);
     method public abstract void onPeriodChanged(int);
-    method public abstract void onResults(android.net.wifi.ScanResult[]);
+    method public abstract deprecated void onResults(android.net.wifi.ScanResult[]);
+    method public abstract void onResults(android.net.wifi.WifiScanner.ScanData[]);
   }
 
   public static class WifiScanner.ScanSettings implements android.os.Parcelable {
@@ -19661,6 +19710,7 @@
     method public void writeToParcel(android.os.Parcel, int);
     field public int band;
     field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
+    field public int maxScansToCache;
     field public int numBssidsPerScan;
     field public int periodInMs;
     field public int reportEvents;
@@ -27454,6 +27504,7 @@
 
   public static final class VoicemailContract.Status implements android.provider.BaseColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
+    method public static void setStatus(android.content.Context, android.telecom.PhoneAccountHandle, int, int, int);
     field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
     field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
     field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
@@ -30472,22 +30523,6 @@
     method public android.telecom.Voicemail.Builder setUri(android.net.Uri);
   }
 
-  public class VvmSyncService extends android.app.Service {
-    ctor public VvmSyncService();
-    method public android.os.IBinder onBind(android.content.Intent);
-  }
-
-  public class VvmSyncService.VvmSyncAdapter extends android.content.AbstractThreadedSyncAdapter {
-    ctor public VvmSyncService.VvmSyncAdapter(android.content.Context, boolean);
-    method protected java.util.List<android.telecom.Voicemail> downloadVoicemails();
-    method public void onPerformSync(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.ContentProviderClient, android.content.SyncResult);
-    method protected void syncToServer();
-    field public static final java.lang.String NEW_VOICEMAIL_DATA = "extra_new_voicemail_data";
-    field public static final java.lang.String SYNC_EXTRA_CODE = "sync_extra_code";
-    field public static final int SYNC_EXTRA_MAILBOX_UPDATE = 2; // 0x2
-    field public static final int SYNC_EXTRA_NEW_VOICEMAIL = 1; // 0x1
-  }
-
 }
 
 package android.telephony {
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 03cf6e3..0da4fd5 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -24,8 +24,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.database.ContentObserver;
+import android.database.Cursor;
 import android.net.Uri;
 import android.provider.CallLog.Calls;
+import android.telecom.PhoneAccountHandle;
 import android.telecom.Voicemail;
 
 import java.util.List;
@@ -428,5 +430,50 @@
             return Status.CONTENT_URI.buildUpon()
                     .appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build();
         }
+
+        /**
+         * A helper method to set the status of a voicemail source.
+         *
+         * @param context The context from the package calling the method. This will be the source.
+         * @param accountHandle The handle for the account the source is associated with.
+         * @param configurationState See {@link Status#CONFIGURATION_STATE}
+         * @param dataChannelState See {@link Status#DATA_CHANNEL_STATE}
+         * @param notificationChannelState See {@link Status#NOTIFICATION_CHANNEL_STATE}
+         */
+        public static void setStatus(Context context, PhoneAccountHandle accountHandle,
+                int configurationState, int dataChannelState, int notificationChannelState) {
+            ContentResolver contentResolver = context.getContentResolver();
+            Uri statusUri = buildSourceUri(context.getPackageName());
+            ContentValues values = new ContentValues();
+            values.put(Status.PHONE_ACCOUNT_COMPONENT_NAME,
+                    accountHandle.getComponentName().toString());
+            values.put(Status.PHONE_ACCOUNT_ID, accountHandle.getId());
+            values.put(Status.CONFIGURATION_STATE, configurationState);
+            values.put(Status.DATA_CHANNEL_STATE, dataChannelState);
+            values.put(Status.NOTIFICATION_CHANNEL_STATE, notificationChannelState);
+
+            if (isStatusPresent(contentResolver, statusUri)) {
+                contentResolver.update(statusUri, values, null, null);
+            } else {
+                contentResolver.insert(statusUri, values);
+            }
+        }
+
+        /**
+         * Determines if a voicemail source exists in the status table.
+         *
+         * @param contentResolver A content resolver constructed from the appropriate context.
+         * @param statusUri The content uri for the source.
+         * @return {@code true} if a status entry for this source exists
+         */
+        private static boolean isStatusPresent(ContentResolver contentResolver, Uri statusUri) {
+            Cursor cursor = null;
+            try {
+                cursor = contentResolver.query(statusUri, null, null, null, null);
+                return cursor != null && cursor.getCount() != 0;
+            } finally {
+                if (cursor != null) cursor.close();
+            }
+        }
     }
 }
diff --git a/core/res/res/values-mcc310-mnc260/strings.xml b/core/res/res/values-mcc310-mnc260/strings.xml
new file mode 100644
index 0000000..5cadc2a
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc260/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- WFC Operator Error Codes -->
+    <string-array name="wfcOperatorErrorCodes" translatable="false">
+        <item>REG09</item>
+    </string-array>
+    <!-- WFC Operator Error Messages -->
+    <string-array name="wfcOperatorErrorMessages">
+        <item>Wi-Fi Calling isn\&apos;t available. Contact your carrier to enable Wi-Fi Calling.</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c849d2c..7633950 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -245,6 +245,12 @@
     <string name="roamingText12">Roaming Banner Off</string>
     <string name="roamingTextSearching">Searching for Service</string>
 
+    <!-- Displayed when WFC registration fails -->
+    <string name="wfcRegErrorTitle">Wi-Fi Calling</string>
+    <!-- WFC Operator Error Codes -->
+    <string-array name="wfcOperatorErrorCodes" translatable="false" />
+    <!-- WFC Operator Error Messages -->
+    <string-array name="wfcOperatorErrorMessages" />
 
     <!--
         {0} is one of "bearerServiceCode*"
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 747c054..b417968 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -745,6 +745,9 @@
   <java-symbol type="string" name="phoneTypeWork" />
   <java-symbol type="string" name="phoneTypeWorkMobile" />
   <java-symbol type="string" name="phoneTypeWorkPager" />
+  <java-symbol type="string" name="wfcRegErrorTitle" />
+  <java-symbol type="array" name="wfcOperatorErrorCodes" />
+  <java-symbol type="array" name="wfcOperatorErrorMessages" />
   <java-symbol type="string" name="policydesc_disableCamera" />
   <java-symbol type="string" name="policydesc_encryptedStorage" />
   <java-symbol type="string" name="policydesc_expirePassword" />
diff --git a/docs/html/auto/images/assets/landing/01.gif b/docs/html/auto/images/assets/landing/01.gif
index 34c9fa8..7a75f87 100644
--- a/docs/html/auto/images/assets/landing/01.gif
+++ b/docs/html/auto/images/assets/landing/01.gif
Binary files differ
diff --git a/docs/html/auto/images/assets/landing/02.gif b/docs/html/auto/images/assets/landing/02.gif
index d50e06b..655c5bc 100644
--- a/docs/html/auto/images/assets/landing/02.gif
+++ b/docs/html/auto/images/assets/landing/02.gif
Binary files differ
diff --git a/docs/html/auto/images/assets/landing/03.gif b/docs/html/auto/images/assets/landing/03.gif
index 7992021..195315a 100644
--- a/docs/html/auto/images/assets/landing/03.gif
+++ b/docs/html/auto/images/assets/landing/03.gif
Binary files differ
diff --git a/docs/html/auto/images/assets/landing/04.png b/docs/html/auto/images/assets/landing/04.png
index a0e75f3..aecdb58 100644
--- a/docs/html/auto/images/assets/landing/04.png
+++ b/docs/html/auto/images/assets/landing/04.png
Binary files differ
diff --git a/docs/html/auto/images/assets/landing/05.png b/docs/html/auto/images/assets/landing/05.png
index f3d2ab8..a3baba4 100644
--- a/docs/html/auto/images/assets/landing/05.png
+++ b/docs/html/auto/images/assets/landing/05.png
Binary files differ
diff --git a/docs/html/auto/images/assets/landing/06.png b/docs/html/auto/images/assets/landing/06.png
index b19a6bb..fe74a49 100644
--- a/docs/html/auto/images/assets/landing/06.png
+++ b/docs/html/auto/images/assets/landing/06.png
Binary files differ
diff --git a/docs/html/auto/images/assets/landing/07.png b/docs/html/auto/images/assets/landing/07.png
index 380e8da..f51d526 100644
--- a/docs/html/auto/images/assets/landing/07.png
+++ b/docs/html/auto/images/assets/landing/07.png
Binary files differ
diff --git a/docs/html/auto/images/assets/landing/08.png b/docs/html/auto/images/assets/landing/08.png
index 9889b39..cc65ff3 100644
--- a/docs/html/auto/images/assets/landing/08.png
+++ b/docs/html/auto/images/assets/landing/08.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/TextMe.png b/docs/html/auto/images/logos/apps/TextMe.png
deleted file mode 100644
index b96f81a..0000000
--- a/docs/html/auto/images/logos/apps/TextMe.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/contacts.png b/docs/html/auto/images/logos/apps/contacts.png
new file mode 100644
index 0000000..f1e1e30
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/contacts.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/icq.png b/docs/html/auto/images/logos/apps/icq.png
new file mode 100644
index 0000000..3e14bd4
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/icq.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/iheartradio.png b/docs/html/auto/images/logos/apps/iheartradio.png
index 8feb38d..da625df 100644
--- a/docs/html/auto/images/logos/apps/iheartradio.png
+++ b/docs/html/auto/images/logos/apps/iheartradio.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/joyride.png b/docs/html/auto/images/logos/apps/joyride.png
index 8c2897e..10ba931 100644
--- a/docs/html/auto/images/logos/apps/joyride.png
+++ b/docs/html/auto/images/logos/apps/joyride.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/kik.png b/docs/html/auto/images/logos/apps/kik.png
index 056ef7e..718b0ee 100644
--- a/docs/html/auto/images/logos/apps/kik.png
+++ b/docs/html/auto/images/logos/apps/kik.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/mlb.png b/docs/html/auto/images/logos/apps/mlb.png
deleted file mode 100644
index ddde4cd..0000000
--- a/docs/html/auto/images/logos/apps/mlb.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/npr.png b/docs/html/auto/images/logos/apps/npr.png
index 5234201..33de546 100644
--- a/docs/html/auto/images/logos/apps/npr.png
+++ b/docs/html/auto/images/logos/apps/npr.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/pandora.png b/docs/html/auto/images/logos/apps/pandora.png
deleted file mode 100644
index 13fa1d3..0000000
--- a/docs/html/auto/images/logos/apps/pandora.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/pocketcasts.png b/docs/html/auto/images/logos/apps/pocketcasts.png
index 5227937..44129f1 100644
--- a/docs/html/auto/images/logos/apps/pocketcasts.png
+++ b/docs/html/auto/images/logos/apps/pocketcasts.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/skype.png b/docs/html/auto/images/logos/apps/skype.png
new file mode 100644
index 0000000..0012b58
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/skype.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/songza.png b/docs/html/auto/images/logos/apps/songza.png
deleted file mode 100644
index 3bd7107..0000000
--- a/docs/html/auto/images/logos/apps/songza.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/soundcloud.png b/docs/html/auto/images/logos/apps/soundcloud.png
deleted file mode 100644
index a5bdbe3..0000000
--- a/docs/html/auto/images/logos/apps/soundcloud.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/spotify.png b/docs/html/auto/images/logos/apps/spotify.png
index d039fd3..8b55ff5 100644
--- a/docs/html/auto/images/logos/apps/spotify.png
+++ b/docs/html/auto/images/logos/apps/spotify.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/stitcher.png b/docs/html/auto/images/logos/apps/stitcher.png
index b77da12..c05cb3d 100644
--- a/docs/html/auto/images/logos/apps/stitcher.png
+++ b/docs/html/auto/images/logos/apps/stitcher.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/talkray.png b/docs/html/auto/images/logos/apps/talkray.png
new file mode 100644
index 0000000..0f170c7
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/talkray.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/textme.png b/docs/html/auto/images/logos/apps/textme.png
new file mode 100644
index 0000000..24efb85
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/textme.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/textplus.png b/docs/html/auto/images/logos/apps/textplus.png
index 2a640c4..3482181 100644
--- a/docs/html/auto/images/logos/apps/textplus.png
+++ b/docs/html/auto/images/logos/apps/textplus.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/threema.png b/docs/html/auto/images/logos/apps/threema.png
new file mode 100644
index 0000000..012cbdc
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/threema.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/tunein.png b/docs/html/auto/images/logos/apps/tunein.png
index 137ba81..db3b75c 100644
--- a/docs/html/auto/images/logos/apps/tunein.png
+++ b/docs/html/auto/images/logos/apps/tunein.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/umano.png b/docs/html/auto/images/logos/apps/umano.png
index 7b59f95..478e268 100644
--- a/docs/html/auto/images/logos/apps/umano.png
+++ b/docs/html/auto/images/logos/apps/umano.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/whatsapp.png b/docs/html/auto/images/logos/apps/whatsapp.png
deleted file mode 100644
index fb5866e..0000000
--- a/docs/html/auto/images/logos/apps/whatsapp.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/auto/images/ui/gearhead_custom_UI.png b/docs/html/auto/images/ui/gearhead_custom_UI.png
index 345db12..a3baba4 100644
--- a/docs/html/auto/images/ui/gearhead_custom_UI.png
+++ b/docs/html/auto/images/ui/gearhead_custom_UI.png
Binary files differ
diff --git a/docs/html/auto/images/ui/gearhead_custom_user_actions.png b/docs/html/auto/images/ui/gearhead_custom_user_actions.png
index 6cc0dcb..8e65ee04 100644
--- a/docs/html/auto/images/ui/gearhead_custom_user_actions.png
+++ b/docs/html/auto/images/ui/gearhead_custom_user_actions.png
Binary files differ
diff --git a/docs/html/auto/images/ui/gearhead_day.png b/docs/html/auto/images/ui/gearhead_day.png
index 81ead75..a3baba4 100644
--- a/docs/html/auto/images/ui/gearhead_day.png
+++ b/docs/html/auto/images/ui/gearhead_day.png
Binary files differ
diff --git a/docs/html/auto/images/ui/gearhead_drawer_generic.png b/docs/html/auto/images/ui/gearhead_drawer_generic.png
index d203aed..94dd305 100644
--- a/docs/html/auto/images/ui/gearhead_drawer_generic.png
+++ b/docs/html/auto/images/ui/gearhead_drawer_generic.png
Binary files differ
diff --git a/docs/html/auto/images/ui/gearhead_drawers_customized.png b/docs/html/auto/images/ui/gearhead_drawers_customized.png
index 44915b5..fe74a49 100644
--- a/docs/html/auto/images/ui/gearhead_drawers_customized.png
+++ b/docs/html/auto/images/ui/gearhead_drawers_customized.png
Binary files differ
diff --git a/docs/html/auto/images/ui/gearhead_generic_UI.png b/docs/html/auto/images/ui/gearhead_generic_UI.png
index beb0701..d7cd53d 100644
--- a/docs/html/auto/images/ui/gearhead_generic_UI.png
+++ b/docs/html/auto/images/ui/gearhead_generic_UI.png
Binary files differ
diff --git a/docs/html/auto/images/ui/gearhead_lens_switching.png b/docs/html/auto/images/ui/gearhead_lens_switching.png
index 9dbfe6c..9fb8b65 100644
--- a/docs/html/auto/images/ui/gearhead_lens_switching.png
+++ b/docs/html/auto/images/ui/gearhead_lens_switching.png
Binary files differ
diff --git a/docs/html/auto/images/ui/gearhead_night.png b/docs/html/auto/images/ui/gearhead_night.png
index 3f8c593..8f1ecdd 100644
--- a/docs/html/auto/images/ui/gearhead_night.png
+++ b/docs/html/auto/images/ui/gearhead_night.png
Binary files differ
diff --git a/docs/html/auto/images/ui/gearhead_overview.png b/docs/html/auto/images/ui/gearhead_overview.png
index 4332ddf3..00b35ce 100644
--- a/docs/html/auto/images/ui/gearhead_overview.png
+++ b/docs/html/auto/images/ui/gearhead_overview.png
Binary files differ
diff --git a/docs/html/auto/index.jd b/docs/html/auto/index.jd
index d113a7d..6d5d594 100644
--- a/docs/html/auto/index.jd
+++ b/docs/html/auto/index.jd
@@ -238,74 +238,72 @@
                    width="120" height="120" class="img-logo" style="margin-top:30px" />
             </div>
             <div class="col-4">
-              <img src="{@docRoot}auto/images/logos/apps/mlb.png"
-                   width="160" height="160" class="img-logo" />
+              <img src="{@docRoot}auto/images/logos/apps/tunein.png"
+                   width="160" height="160" class="img-logo"
+                   />
             </div>
           </div>
 
           <div class="cols">
             <div class="col-4">
-              <img src="{@docRoot}auto/images/logos/apps/pandora.png"
-                   width="160" height="160" class="img-logo" />
+              <img src="{@docRoot}auto/images/logos/apps/talkray.png"
+                   width="120" height="44" class="img-logo" style="margin-top:40px"
+                   />
             </div>
             <div class="col-4">
-              <img src="{@docRoot}auto/images/logos/apps/pocketcasts.png"
-                   width="160" height="160" class="img-logo" />
+              <img src="{@docRoot}auto/images/logos/apps/icq.png"
+                   width="150" height="53" class="img-logo" style="margin-top:40px"
+                   />
             </div>
             <div class="col-4">
-              <img src="{@docRoot}auto/images/logos/apps/songza.png"
-                   width="160" height="160" class="img-logo" />
+              <img src="{@docRoot}auto/images/logos/apps/stitcher.png"
+                   width="160" height="160" class="img-logo" style="margin-top:-20px"
+                   />
             </div>
             <div class="col-4">
-              <img src="/auto/images/logos/apps/soundcloud.png"
-                   width="100" height="100" class="img-logo"
-                   style="margin-top:30px" />
+              <img src="/auto/images/logos/apps/pocketcasts.png"
+                   width="160" height="160" class="img-logo" style="margin-top:-10px"
+                   />
             </div>
           </div>
 
           <div class="cols">
             <div class="col-4">
+              <img src="/auto/images/logos/apps/threema.png"
+                   width="100" height="91" class="img-logo" style="margin-top:30px"
+                   />
+            </div>
+            <div class="col-4">
+              <img src="{@docRoot}auto/images/logos/apps/umano.png"
+                   width="160" height="160" class="img-logo" />
+            </div>
+            <div class="col-4">
               <img src="/auto/images/logos/apps/spotify.png"
                    width="160" height="160" class="img-logo" />
             </div>
             <div class="col-4">
-              <img src="{@docRoot}auto/images/logos/apps/stitcher.png"
-                   width="160" height="160" class="img-logo" />
-            </div>
-            <div class="col-4">
-              <img src="/auto/images/logos/apps/TextMe.png"
-                   width="100" height="100" class="img-logo" style="margin-top:30px" />
-            </div>
-            <div class="col-4">
               <img src="/auto/images/logos/apps/textplus.png"
-                   width="120" height="24" class="img-logo" style="margin-top:70px" />
+                   width="120" height="24" class="img-logo" style="margin-top:60px"
+                   />
             </div>
           </div>
 
           <div class="cols">
             <div class="col-4">
-              <img src="{@docRoot}auto/images/logos/apps/tunein.png"
-                   width="160" height="160" class="img-logo" style="margin-left:160px" />
+              <img src="{@docRoot}auto/images/logos/apps/contacts.png"
+                   width="160" height="160" class="img-logo" style="margin-left:140px"
+                   />
             </div>
             <div class="col-4">
-              <img src="{@docRoot}auto/images/logos/apps/umano.png"
-                   width="160" height="160" class="img-logo" style="margin-left:370px" />
+              <img src="{@docRoot}auto/images/logos/apps/skype.png"
+                   width="160" height="70" class="img-logo" style="margin-top:40px; margin-left:160px"
+                   />
             </div>
-          </div>
-
-          <div class="cols" style="margin-top:40px">
-              <div class="col-4">
-                <img src="/auto/images/logos/apps/whatsapp.png"
-                     width="120" height="120" class="img-logo" />
-              </div>
-              <div class="col-8">
-                <p><em>
-                "We were able to get messaging functionality for text
-                implemented easily on Android Auto, with minimal development
-                effort. We're excited to participate in Android Auto which
-                provides a notification interface for the car that is both
-                user-friendly and highly safety-minded."</em></p>
-              </div>
+            <div class="col-4">
+              <img src="{@docRoot}auto/images/logos/apps/textme.png"
+                   width="80" height="80" class="img-logo" style="margin-top:30px;margin-left:200px"
+                   />
+            </div>
           </div>
 
           <div class="cols" style="margin-top:60px">
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index 0114848..5559d1a 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
 page.title=Installing the Eclipse Plugin
-adt.zip.version=23.0.4
-adt.zip.download=ADT-23.0.4.zip
-adt.zip.bytes=103336810
-adt.zip.checksum=91a43dcf686ab73dec2c08b77243492b
+adt.zip.version=23.0.6
+adt.zip.download=ADT-23.0.6.zip
+adt.zip.bytes=103344298
+adt.zip.checksum=f64b7e50c84799f41c642218c35f1bbe
 
 @jd:body
 
@@ -142,7 +142,7 @@
 
 <p>Note that there are features of ADT that require some optional
 Eclipse packages (for example, WST). If you encounter an error when
-installing ADT, your Eclipse installion might not include these packages.
+installing ADT, your Eclipse installation might not include these packages.
 For information about how to quickly add the necessary packages to your
 Eclipse installation, see the troubleshooting topic
 <a href="{@docRoot}resources/faq/troubleshooting.html#installeclipsecomponents">ADT
diff --git a/docs/html/tools/revisions/build-tools.jd b/docs/html/tools/revisions/build-tools.jd
index 593770a..b08fbcf 100644
--- a/docs/html/tools/revisions/build-tools.jd
+++ b/docs/html/tools/revisions/build-tools.jd
@@ -78,6 +78,28 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Build Tools, Revision 22.0.0</a> <em>(March 2015)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <p>Added support for Android 5.1 (API level 22).</p>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
+      alt=""/>Build Tools, Revision 21.1.2</a> <em>(February 2015)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <p>Fixed problem with building data layouts in 32-bit mode.</p>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Build Tools, Revision 21.1.1</a> <em>(November 2014)</em>
   </p>
   <div class="toggle-content-toggleme">
@@ -92,7 +114,7 @@
       alt=""/>Build Tools, Revision 21.1</a> <em>(October 2014)</em>
   </p>
   <div class="toggle-content-toggleme">
-    <p>Added multidex file support for APKs and Jack suppport to address the 64K method reference
+    <p>Added multidex file support for APKs and Jack support to address the 64K method reference
     limit.</p>
   </div>
 </div>
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index c3a4dea..08634da 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -53,6 +53,40 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>ADT 23.0.6</a> <em>(March 2015)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+<dl>
+  <dt>Dependencies:</dt>
+
+  <dd>
+    <ul>
+      <li>Java 7 or higher is required if you are targeting Android 5.0 and higher.</li>
+      <li>Java 1.6 or higher is required if you are targeting other releases.</li>
+      <li>Eclipse Indigo (Version 3.7.2) or higher is required.</li>
+      <li>This version of ADT is designed for use with
+        <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r24.1.2</a>.
+        If you haven't already installed SDK Tools r24.1.2 into your SDK, use the
+        Android SDK Manager to do so.</li>
+    </ul>
+  </dd>
+
+  <dt>General Notes:</dt>
+  <dd>
+    <ul>
+        <li>Fixed issues with the rendering library.</li>
+    </ul>
+  </dd>
+</dl>
+</div>
+</div>
+
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>ADT 23.0.4</a> <em>(October 2014)</em>
   </p>
 
@@ -62,12 +96,12 @@
 
   <dd>
     <ul>
-      <li>Java 7 or higher is required if you are targeting the L Developer Preview.</li>
+      <li>Java 7 or higher is required if you are targeting Android 5.0 and higher.</li>
       <li>Java 1.6 or higher is required if you are targeting other releases.</li>
       <li>Eclipse Indigo (Version 3.7.2) or higher is required.</li>
       <li>This version of ADT is designed for use with
-        <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r23.0.2</a>.
-        If you haven't already installed SDK Tools r23.0.2 into your SDK, use the
+        <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r23.0.4</a>.
+        If you haven't already installed SDK Tools r23.0.4 into your SDK, use the
         Android SDK Manager to do so.</li>
     </ul>
   </dd>
@@ -96,7 +130,7 @@
 
   <dd>
     <ul>
-      <li>Java 7 or higher is required if you are targeting the L Developer Preview.</li>
+      <li>Java 7 or higher is required if you are targeting Android 5.0 and higher.</li>
       <li>Java 1.6 or higher is required if you are targeting other releases.</li>
       <li>Eclipse Indigo (Version 3.7.2) or higher is required.</li>
       <li>This version of ADT is designed for use with
@@ -132,7 +166,7 @@
 
   <dd>
     <ul>
-      <li>Java 7 or higher is required if you are targeting the L Developer Preview.</li>
+      <li>Java 7 or higher is required if you are targeting Android 5.0 and higher.</li>
       <li>Java 1.6 or higher is required if you are targeting other releases.</li>
       <li>Eclipse Indigo (Version 3.7.2) or higher is required.</li>
       <li>This version of ADT is designed for use with
@@ -167,7 +201,7 @@
 
   <dd>
     <ul>
-      <li>Java 7 or higher is required if you are targeting the L Developer Preview.</li>
+      <li>Java 7 or higher is required if you are targeting Android 5.0 and higher.</li>
       <li>Java 1.6 or higher is required if you are targeting other releases.</li>
       <li>Eclipse Indigo (Version 3.7.2) or higher is required.</li>
       <li>This version of ADT is designed for use with
@@ -2274,7 +2308,7 @@
 <dt>DDMS integration:</dt>
 <dd>
 <ul>
-<li>Includes the improvements from the standlone DDMS, revision 3.</li>
+<li>Includes the improvements from the standalone DDMS, revision 3.</li>
 <li>Adds an option to open HPROF files into eclipse instead of writing them on
 disk. If a profiler such as MAT (<a href="http://eclipse.org/mat">Memory Analyzer
 Tool</a>) is installed, it'll open the file.</li>
diff --git a/docs/html/training/auto/messaging/index.jd b/docs/html/training/auto/messaging/index.jd
index 2405d83..70ac205 100644
--- a/docs/html/training/auto/messaging/index.jd
+++ b/docs/html/training/auto/messaging/index.jd
@@ -48,7 +48,7 @@
 </a>
 
 <p>
-  Staying connected through text messages is important to many drivers. Chat apps can let users
+  Staying connected through messages is important to many drivers. Chat apps can let users
   know if a child need to be picked up, or if a dinner location has been changed. Apps that provide
   sports information might tell the user who just won the big game, and let the user ask questions
   about other games being played. The Android framework enables messaging apps to extend their
@@ -95,6 +95,90 @@
     has read or replied to a message.
 </ul>
 
+<h3 id="#concepts">Concepts and Objects</h3>
+
+<p>Before you start designing your app, it's helpful to understand how Auto
+handles messaging.</p>
+
+<p>Each individual chunk of communication is a <em>message</em>. A message is a
+short length of text, suitable for the Auto device to read aloud. In a chat app,
+this might be a single message from one person to another: <code>"Fitzy -- Jane
+can't come to the ball, her youngest has the croup. :-( --Liz"</code> In a
+sports app, a message might be a single bit of news about a game: <code>"Granger
+scores for Harpies at 7 minutes in."</code></p>
+
+<p>A <em>conversation</em> is a group of messages that are all grouped together
+in some way. Auto uses the conversation information to group the messages
+together when presenting them to the user. In a chat app, a conversation might
+be all the messages between the user and another person (for example, all
+the messages back and forth between Darcy and Elizabeth). In a sports app, a
+conversation might be all the messages about a particular game. Every message
+belongs to a conversation, even if it's the only message in that conversation.
+Each conversation has a <em>conversation name</em>.
+The conversation name is used by Android Auto to
+present the messages; it's up to your app to choose an appropriate conversation
+name. In a chat app, the conversation name is usually the person your user is
+talking to.
+In a sports app, this might be the name of the teams playing in the game.</p>
+
+<p>The v4 support library defines an {@link
+android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation
+UnreadConversation} object. This object holds all messages in a conversation
+which have not yet been heard by the user. To give those messages to the user,
+you attach that {@link
+android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation
+UnreadConversation} to a notification. However, you do not attach messages to
+the {@link
+android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation
+UnreadConversation} directly. Instead, you must first set up an {@link
+android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder
+UnreadConversation.Builder} object for the conversation. The messages are added to the builder,
+then when you are ready to send the messages, you use the builder to create the
+actual {@link
+android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation
+UnreadConversation} and attach the {@link
+android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation
+UnreadConversation} to the notification.</p>
+
+<p class="note"><strong>Note:</strong> When Auto presents messages to the
+user, it uses the notification <em>tag</em> and <em>ID</em> to determine which conversation the
+messages belong to. It is important to use the same tag and ID for all messages in
+a conversation, and to not use that tag for other conversations.</p>
+
+<h3 id="#workflow">Workflow</h3>
+
+<p>This section describes how the mobile device interacts with Auto to present
+messages to the user.</p>
+
+<ol>
+
+<li>The app receives a message that it wants to pass on to the user. It attaches
+the message to an  {@link
+android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation
+UnreadConversation} object and attaches it to a notification. That notification
+is associated with a {@link
+android.support.v4.app.NotificationCompat.CarExtender CarExtender} object, which
+indicates that the notification can be handled by Android Auto.</li>
+
+<li>The app posts the notification. The Android notification framework passes the
+message to Auto. Auto uses the notification tag and ID to determine which conversation
+the message belongs to, and presents the message to the user in an appropriate
+way.</li>
+
+<li>When the user listens to the message, Auto triggers the app's message heard
+pending intent. The app should discard the {@link
+android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation
+UnreadConversation} object and its builder at this time, since the messages
+contained in those objects have been heard by the user.</li>
+
+<li>If the user sends a reply, Auto triggers the app's "message reply" intent and
+attaches a transcript of the user's response.  The app can take appropriate
+action, based on the app's logic. For example, a chat app might interpret the
+reply as a message to go to the other conversation participants, while a sports
+app might try to interpret the "reply" as a request for other information
+("What's the score in the Sharks game?").</li>
+
+</ol>
 
 <h2 id="#manifest">Configure Your Manifest</h2>
 
@@ -104,7 +188,6 @@
   section describes what changes to make to your manifest to support messaging for Auto devices.
 </p>
 
-
 <h3 id="manifest-messaging">Declare Auto messaging support</h3>
 
 <p>
@@ -159,26 +242,28 @@
 <pre>
 &lt;application&gt;
     ...
-    &lt;receiver android:name="<em>.MyMessageReadReceiver</em>"&gt;
+    &lt;receiver android:name=".MyMessageHeardReceiver"&gt;
         &lt;intent-filter&gt;
-          &lt;action android:name="<em>com.myapp.messagingservice.ACTION_MESSAGE_HEARD</em>"/&gt;
+          &lt;action android:name="com.myapp.messagingservice.MY_ACTION_MESSAGE_HEARD"/&gt;
         &lt;/intent-filter&gt;
     &lt;/receiver&gt;
 
-    &lt;receiver android:name="<em>.MyMessageReplyReceiver</em>"&gt;
+    &lt;receiver android:name=".MyMessageReplyReceiver"&gt;
         &lt;intent-filter&gt;
-          &lt;action android:name="<em>com.myapp.messagingservice.ACTION_MESSAGE_REPLY</em>"/&gt;
+          &lt;action android:name="com.myapp.messagingservice.MY_ACTION_MESSAGE_REPLY"/&gt;
         &lt;/intent-filter&gt;
     &lt;/receiver&gt;
     ...
 &lt;/application&gt;
 </pre>
 
-<p>
-  The definition of the {@link android.content.BroadcastReceiver} classes shown in this example
-  is discussed in <a href="#handle_actions">Handle User Actions</a>.
-</p>
-
+<p>   In this example, <code>"MyMessageReadReceiver"</code> and
+<code>"MyMessageReplyReceiver"</code> are the names of the {@link
+android.content.BroadcastReceiver} subclasses you define to handle the
+intents. You can choose whatever you like   as the action names, but it's best
+to prepend your package name to ensure that   the action names are unique. For
+more information about handling actions, see <a href="#handle_actions">Handle
+User Actions</a>. </p>
 
 <h2 id="support-lib">Import Support Library for Messaging</h3>
 
@@ -199,7 +284,7 @@
 <pre>
 dependencies {
     ...
-    compile 'com.android.support:support-v4:21.0.+'
+    compile 'com.android.support:support-v4:21.0.2'
 }
 </pre>
 
@@ -240,79 +325,6 @@
   provide the content of messages in those conversations.
 </p>
 
-
-<h3 id="build_conversation">Build message conversations</h4>
-
-<p>
-  Messaging notifications for Auto organize messages into conversations using the {@link
-  android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} class,
-  that represents an unread or new
-  portion of a conversation from a particular sender. It contains a list of messages from the
-  sender.
-</p>
-
-<p>
-  Use the {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder} class to create an unread conversation object,
-  as shown in the following example code:
-</p>
-
-<pre>
-// Build a RemoteInput for receiving voice input in a Car Notification
-RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
-        .setLabel(getApplicationContext().getString(R.string.notification_reply))
-        .build();
-
-// Create an unread conversation object to organize a group of messages
-// from a particular sender.
-UnreadConversation.Builder unreadConvBuilder =
-    new UnreadConversation.Builder(participantName)
-        .setReadPendingIntent(msgHeardPendingIntent)
-        .setReplyAction(replyPendingIntent, remoteInput);
-</pre>
-
-<p>
-  This conversation object includes a {@link android.app.PendingIntent}, which allows the Auto
-  device to signal your app that the conversation has been read by the Auto user. The construction
-  of this intent is discussed in the <a href="#conversation-intents">Creating conversation read and
-  reply intents</a> section.
-</p>
-
-<p>
-  If your app supports replying to a conversation, you must call the {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder#setReplyAction setReplyAction()}
-  method and provide a pending intent to pass that user action back to your app. The
-  {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation}
-  object you create must also include a {@link
-  android.support.v4.app.RemoteInput} object. When the Auto user
-  receiving this conversation speaks a reply, the remote input objects lets your app get a text
-  version of the voice reply.
-</p>
-
-
-<h4 id="conversation-messages">Associate messages with conversations</h4>
-
-<p>
-  Messages provided for Auto must be associated with a conversation using the
-  {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation}
-  class. The following code example shows how
-  to associate individual messages with a conversation object.
-</p>
-
-<pre>
-// Note: Add messages from oldest to newest to the UnreadConversation.Builder
-for (Iterator&lt;String&gt; messages = conversation.getMessages().iterator();
-     messages.hasNext(); ) {
-    String message = messages.next();
-    unreadConvBuilder.addMessage(message);
-}
-</pre>
-
-<p>
-  When a new message arrives in a particular conversation, your app should check if there is
-  already a conversation object for that particular conversation. If there is, associate the new
-  message with the existing conversation instead of building a new one.
-</p>
-
-
 <h4 id="conversation-intents">Create conversation read and reply intents</h4>
 
 <p>
@@ -323,28 +335,27 @@
 
 <p>
   The following example code demonstrates how to define a {@link android.app.PendingIntent} to let
-  your app know if a conversation was listened to by the Auto user:
+  your app know if a conversation was read to the Auto user:
 </p>
 
 <pre>
 Intent msgHeardIntent = new Intent()
     .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
-    .setAction(<em>com.myapp.messagingservice.ACTION_MESSAGE_HEARD</em>)
-    .putExtra("conversation_id", <em>conversationId</em>);
+    .setAction("com.myapp.messagingservice.MY_ACTION_MESSAGE_HEARD")
+    .putExtra("conversation_id", thisConversationId);
 
 PendingIntent msgHeardPendingIntent =
     PendingIntent.getBroadcast(getApplicationContext(),
-        <em>conversationId</em>,
+        thisConversationId,
         msgHeardIntent,
         PendingIntent.FLAG_UPDATE_CURRENT);
 </pre>
 
-<p>
-  In this example, {@code conversationId} is an integer that identifies the current conversation.
-  The value of {@link android.content.Intent#setAction setAction()} is an intent filter identifier for heard messages which is
-  defined in your app manifest, as shown in <a href="#manifest-intent">Define read and reply intent
-  filters</a>.
-</p>
+<p>In this example, {@code thisConversationId} is an integer that identifies the
+current conversation.   The value of {@link android.content.Intent#setAction
+Intent.setAction()} is the intent filter identifier for heard messages which you
+defined in your app manifest, as shown in <a href="#manifest-intent">Define read
+and reply intent filters</a>. </p>
 
 <p>
   If your app supports replying to conversations, you also create a {@link
@@ -356,22 +367,79 @@
 <pre>
 Intent msgReplyIntent = new Intent()
     .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
-    .setAction(<em>com.myapp.messagingservice.ACTION_MESSAGE_REPLY</em>)
-    .putExtra("conversation_id", <em>conversationId</em>);
+    .setAction("com.myapp.messagingservice.MY_ACTION_MESSAGE_REPLY")
+    .putExtra("conversation_id", thisConversationId);
 
 PendingIntent msgReplyPendingIntent = PendingIntent.getBroadcast(
     getApplicationContext(),
-    <em>conversationId</em>,
+    thisConversationId,
     msgReplyIntent,
     PendingIntent.FLAG_UPDATE_CURRENT);
 </pre>
 
+<p>   Once again, {@code thisConversationId} is an integer that uniquely identifies
+this conversation, and    the value you pass to {@link
+android.content.Intent#setAction Intent.setAction()} is the intent filter
+identifier you defined for replies in your   app manifest. </p>
+
+<h3 id="build_conversation">Set up the conversation builder</h4>
+
 <p>
-  Once again, {@code conversationId} is an integer that uniquely identifies this conversation. The
-  value of {@link android.content.Intent#setAction setAction()} is an intent filter identifier for replies which is defined in your
-  app manifest, as shown in <a href="#manifest-intent">Define read and reply intent filters</a>.
+  Messaging notifications for Auto organize messages into conversations using the {@link
+  android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} class,
+  that represents an unread or new
+  portion of a conversation from a particular sender. It contains a list of messages from the
+  sender.
 </p>
 
+<p>
+  You generally do not configure the {@link
+  android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation UnreadConversation}
+  directly. Instead, you configure an
+  {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder
+  UnreadConversation.Builder} with the information about the conversation,
+  as shown in the following example code.
+</p>
+
+<pre>
+// Build a RemoteInput for receiving voice input in a Car Notification
+RemoteInput remoteInput = new RemoteInput.Builder(MY_VOICE_REPLY_KEY)
+        .setLabel(getApplicationContext().getString(R.string.notification_reply))
+        .build();
+
+// Create an unread conversation object to organize a group of messages
+// from a particular sender.
+UnreadConversation.Builder unreadConvBuilder =
+    new UnreadConversation.Builder(conversationName)
+        .setReadPendingIntent(msgHeardPendingIntent)
+        .setReplyAction(msgReplyPendingIntent, remoteInput);
+</pre>
+
+<p class="note">
+  <strong>Note:</strong> You won't actually create the {@link
+  android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation
+  UnreadConversation} until you are almost ready to send the message.
+</p>
+
+<p>
+  This conversation object includes a {@link android.app.PendingIntent}, which allows the Auto
+  device to signal your app that the conversation has been read by the Auto user. The construction
+  of this intent is discussed in the <a href="#conversation-intents">Creating conversation read and
+  reply intents</a> section.
+</p>
+
+<p>
+  If your app supports replying to a conversation, you must call the
+  {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder#setReplyAction
+  UnreadConversation.Builder.setReplyAction()}
+  method and provide a pending intent to pass that user action back to your app. The
+  {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation
+  UnreadConversation}
+  object you create must also include a {@link
+  android.support.v4.app.RemoteInput} object. When the Auto user
+  receiving this conversation speaks a reply, the remote input objects lets your app get a text
+  version of the voice reply.
+</p>
 
 <h3 id="sending_messages">Sending Messages</h4>
 
@@ -381,49 +449,99 @@
 </p>
 
 <p>First, add the message to the {@link
-android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder}
-for this conversation, and update its timestamp:</p>
+android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder
+UnreadConversation.Builder} for this conversation, and update its timestamp:</p>
 
 <pre>
-unreadConvBuilder.addMessage(<em>messageString</em>)
-    .setLatestTimestamp(<em>currentTimestamp</em>);
+unreadConvBuilder.addMessage(messageString)
+    .setLatestTimestamp(currentTimestamp);
 </pre>
 
-<p>Then create a {@link android.support.v4.app.NotificationCompat.Builder}
-object that you'll use to build the actual notification. You'll need to use the
+<p class="note"><strong>Note:</strong> If you are sending several messages at
+once, add them to the {@link
+android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder
+UnreadConversation.Builder} in order, from oldest to newest.</p>
+
+<p>Then create the {@link android.support.v4.app.NotificationCompat.Builder
+NotificationCompat.Builder}
+object that builds the actual notification. You need to use the
 pending intents you created in the previous step.</p>
 
 <pre>
 NotificationCompat.Builder notificationBuilder =
     new NotificationCompat.Builder(getApplicationContext())
-        .setSmallIcon(R.drawable.<em>notification_icon</em>)
-        .setLargeIcon(<em>icon_bitmap</em>)
-        .setContentText(<em>messageString</em>)
-        .setWhen(<em>currentTimestamp</em>)
-        .setContentTitle(<em>participant_name</em>)
-        .setContentIntent(msgHeardPendingIntent);
-
+        .setSmallIcon(smallIconResourceID)
+        .setLargeIcon(largeIconBitmap);
 </pre>
 
+<dl>
+  <dt><code>smallIconResourceID</code></dt>
+  <dd>The resource ID of a small icon to use for the conversation. This is
+    typically a generic icon for the messaging app.</dd>
+
+  <dt><code>largeIconBitmap</code></dt>
+  <dd>A {@link android.graphics.Bitmap} of a large version of the icon. This
+    is typically a conversation-specific graphic. For example, if this is a
+    chat app, the large icon would be a picture of the person the user is
+    chatting with.</dd>
+
+  <dt><code>messageString</code></dt>
+  <dd>The text of the message you want to send. (If you are sending several
+    messages at once, concatenate them into a single string, with the oldest
+    message first.)</dd>
+
+  <dt><code>currentTimestamp</code></dt>
+  <dd>The message timestamp. (If you are sending several messages at once,
+    use the timestamp of the most recent message.)</dd>
+
+  <dt><code>conversationName</code></dt>
+
+  <dd>The name you chose for this conversation (for example, the name of the
+    person the user is chatting with). This should be the same conversation
+    name you used when you created the {@link
+android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder
+    UnreadConversation.Builder}.</dd>
+
+  <dt><code>msgHeardPendingIntent</code></dt>
+  <dd>The pending intent object you created in
+    <a href="#conversation-intents">Create conversation read and reply
+      intents</a>.</dd>
+</dl>
+
+
 <p>You'll also need to extend the  {@link
-android.support.v4.app.NotificationCompat.Builder} with the {@link
-android.support.v4.app.NotificationCompat.CarExtender}. This is where you
-actually create the {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} object using the builder you
+android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} with the {@link
+android.support.v4.app.NotificationCompat.CarExtender CarExtender}. This is where you
+actually create the
+{@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation
+UnreadConversation} object using the builder you
 just created, and attach it to the {@link
-android.support.v4.app.NotificationCompat.CarExtender}:</p>
+android.support.v4.app.NotificationCompat.CarExtender CarExtender}:</p>
 
 <pre>
 notificationBuilder.extend(new CarExtender()
     .setUnreadConversation(unreadConvBuilder.build());
 </pre>
 
+<p class="note"><strong>Note:</strong> If you wish, you can set an override icon
+or color for the {@link android.support.v4.app.NotificationCompat.CarExtender
+CarExtender} by calling {@link
+android.support.v4.app.NotificationCompat.CarExtender#setLargeIcon
+setLargeIcon()} or {@link
+android.support.v4.app.NotificationCompat.CarExtender#setColor setColor()}. The
+override icon or color is used when the notification is handled by a car, and
+has no effect if the notification is handled on the Android device. This is
+useful if the notification's default icon or color are not suitable for the
+car's display.</p>
+
 <p>Once you've done all this, you use your app's {@link
 android.support.v4.app.NotificationManagerCompat} to send the notification:</p>
 
 <pre>
 NotificationManagerCompat msgNotificationManager =
     NotificationManagerCompat.from(context);
-msgNotificationManager.notify(<em>notificationId</em>, notificationBuilder.build());
+msgNotificationManager.notify(notificationTag,
+    notificationId, notificationBuilder.build());
 </pre>
 
 <h2 id="handle_actions">Handle User Actions</h2>
@@ -431,7 +549,7 @@
 <p>
   When your create and dispatch a notification for messaging, you specify intents to be triggered
   when the Auto user hears the message and when the user dictates a reply. Your app indicates to
-  the Android framework that it handles these intends by registering them through it's manifest, as
+  the Android framework that it handles these intends by registering them through its manifest, as
   discussed in <a href="#manifest-intent">Define read and reply intent filters</a>.
 </p>
 
@@ -461,7 +579,7 @@
 </p>
 
 <pre>
-public class MessageHeardReceiver extends BroadcastReceiver {
+public class MyMessageHeardReceiver extends BroadcastReceiver {
 
     &#64;Override
     public void onReceive(Context context, Intent intent) {
@@ -469,7 +587,7 @@
         // If you set up the intent as described in
         // "Create conversation read and reply intents",
         // you can get the conversation ID by calling:
-        int conversationId = intent.getIntExtra("conversation_id", -1);
+        int thisConversationId = intent.getIntExtra("conversation_id", -1);
 
         // Remove the notification to indicate it has been read
         // and update the list of unread conversations in your app.
@@ -479,7 +597,8 @@
 
 <p>
   Once a notification is read, your app can remove it by calling
-  {@link android.support.v4.app.NotificationManagerCompat#cancel} with the notification ID.
+  {@link android.support.v4.app.NotificationManagerCompat#cancel
+  NotificationManagerCompat.cancel()} with the notification ID.
   Within your app, you should mark the messages provided in the notification as read.
 </p>
 
@@ -505,7 +624,7 @@
 </p>
 
 <pre>
-  public class MessageReplyReceiver extends BroadcastReceiver {
+  public class MyMessageReplyReceiver extends BroadcastReceiver {
 
 
     &#64;Override
@@ -513,7 +632,7 @@
         // If you set up the intent as described in
         // "Create conversation read and reply intents",
         // you can get the conversation ID by calling:
-        int conversationId = intent.getIntExtra("conversation_id", -1).
+        int thisConversationId = intent.getIntExtra("conversation_id", -1).
 
     }
 
@@ -527,7 +646,7 @@
         Bundle remoteInput =
             RemoteInput.getResultsFromIntent(intent);
         if (remoteInput != null) {
-            return remoteInput.getCharSequence("extra_voice_reply");
+            return remoteInput.getCharSequence(MY_VOICE_REPLY_KEY);
         }
         return null;
     }
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 8c56c8c..0437a2a 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1374,7 +1374,8 @@
                 mConnector.execute("softap", "set", wlanIface);
             } else {
                 mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
-                                   "broadcast", "6", getSecurityType(wifiConfig),
+                                   "broadcast", Integer.toString(wifiConfig.apChannel),
+                                   getSecurityType(wifiConfig),
                                    new SensitiveArg(wifiConfig.preSharedKey));
             }
             mConnector.execute("softap", "startap");
diff --git a/telecomm/java/android/telecom/VvmSyncService.java b/telecomm/java/android/telecom/VvmSyncService.java
deleted file mode 100644
index 2aaf348..0000000
--- a/telecomm/java/android/telecom/VvmSyncService.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-/**
- * A {@link Service} which runs the internal implementation of {@link AbstractThreadedSyncAdapter},
- * syncing voicemails to and from a visual voicemail server.
- */
-
-package android.telecom;
-
-import android.accounts.Account;
-import android.app.Service;
-import android.content.AbstractThreadedSyncAdapter;
-import android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SyncResult;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.provider.VoicemailContract;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A service to run the VvmSyncAdapter.
- */
-public class VvmSyncService extends Service {
-    // Storage for an instance of the sync adapter
-    private static VvmSyncAdapter sSyncAdapter = null;
-    // Object to use as a thread-safe lock
-    private static final Object sSyncAdapterLock = new Object();
-
-    @Override
-    public void onCreate() {
-        synchronized (sSyncAdapterLock) {
-            if (sSyncAdapter == null) {
-                sSyncAdapter = new VvmSyncAdapter(getApplicationContext(), true);
-            }
-        }
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return sSyncAdapter.getSyncAdapterBinder();
-    }
-
-    public class VvmSyncAdapter extends AbstractThreadedSyncAdapter {
-        /** The key to get the extra designating the type of sync action to perform. */
-        public final static String SYNC_EXTRA_CODE = "sync_extra_code";
-        /** The key to get the {@code Voicemail} object for a new voicemail. */
-        public final static String NEW_VOICEMAIL_DATA = "extra_new_voicemail_data";
-        /** Sync a new voicemail from the carrier to the device. */
-        public final static int SYNC_EXTRA_NEW_VOICEMAIL = 1;
-        /** Sync all voicemails because the mailbox was changed remotely. */
-        public final static int SYNC_EXTRA_MAILBOX_UPDATE = 2;
-
-        private final Context mContext;
-
-        public VvmSyncAdapter(Context context, boolean autoInitialize) {
-            super(context, autoInitialize);
-            mContext = context;
-        }
-
-        @Override
-        public void onPerformSync(Account account, Bundle extras, String authority,
-                ContentProviderClient provider, SyncResult syncResult) {
-            if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false)) {
-                // notify server that voicemail has been changed
-                syncToServer();
-            }
-
-            final int syncAction = extras.getInt(SYNC_EXTRA_CODE);
-            switch (syncAction) {
-                /** sync from carrier */
-                case SYNC_EXTRA_NEW_VOICEMAIL:
-                    // Log new voicemail in voicemail provider.
-                    Voicemail newVoicemail = extras.getParcelable(NEW_VOICEMAIL_DATA);
-                    VoicemailContract.Voicemails.insert(mContext, newVoicemail);
-                    break;
-                case SYNC_EXTRA_MAILBOX_UPDATE:
-                    // Clear and reload all voicemails because the mailbox was updated remotely.
-                    VoicemailContract.Voicemails.deleteAll(mContext);
-                    List<Voicemail> voicemails = downloadVoicemails();
-                    VoicemailContract.Voicemails.insert(mContext, voicemails);
-                    break;
-                 default:
-                     break;
-            }
-        }
-
-        /** Subclasses should implement this method to sync changes to server */
-        protected void syncToServer() { }
-
-        /** Subclasses should implement this method to download voicemails */
-        protected List<Voicemail> downloadVoicemails() {
-            return new ArrayList<Voicemail>();
-        }
-    }
-}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index b87a1e9..bc95a36 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -79,6 +79,8 @@
 
     void setCountryCode(String country, boolean persist);
 
+    String getCountryCode();
+
     void setFrequencyBand(int band, boolean persist);
 
     int getFrequencyBand();
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 9729c91..b4f4927 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -16,6 +16,8 @@
 
 package android.net.wifi;
 
+import android.net.wifi.passpoint.WifiPasspointInfo;
+import android.net.wifi.passpoint.WifiPasspointManager;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -53,11 +55,55 @@
      */
     public int level;
     /**
-     * The frequency in MHz of the channel over which the client is communicating
+     * The primary 20 MHz frequency (in MHz) of the channel over which the client is communicating
      * with the access point.
      */
     public int frequency;
 
+   /**
+    * AP Channel bandwidth is 20 MHZ
+    */
+    public static final int CHANNEL_WIDTH_20MHZ = 0;
+   /**
+    * AP Channel bandwidth is 40 MHZ
+    */
+    public static final int CHANNEL_WIDTH_40MHZ = 1;
+   /**
+    * AP Channel bandwidth is 80 MHZ
+    */
+    public static final int CHANNEL_WIDTH_80MHZ = 2;
+   /**
+    * AP Channel bandwidth is 160 MHZ
+    */
+    public static final int CHANNEL_WIDTH_160MHZ = 3;
+   /**
+    * AP Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ
+    */
+    public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4;
+
+   /**
+    * AP Channel bandwidth
+    */
+    public int channelWidth;
+
+    /**
+     * Not used if the AP bandwidth is 20 MHz
+     * If the AP use 40, 80 or 160 MHz, this is the center frequency
+     * if the AP use 80 + 80 MHz, this is the center frequency of the first segment
+     */
+    public int centerFreq0;
+
+    /**
+     * Only used if the AP bandwidth is 80 + 80 MHz
+     * if the AP use 80 + 80 MHz, this is the center frequency of the second segment
+     */
+    public int centerFreq1;
+
+    /**
+     * Whether the AP support 802.11mc Responder
+     */
+   public boolean is80211McRTTResponder;
+
     /**
      * timestamp in microseconds (since boot) when
      * this result was last seen.
@@ -169,6 +215,13 @@
     public int distanceSdCm;
 
     /**
+     * Passpoint ANQP information. This is not fetched automatically.
+     * Use {@link WifiPasspointManager#requestAnqpInfo} to request ANQP info.
+     * {@hide}
+     */
+    public WifiPasspointInfo passpoint;
+
+    /**
      * {@hide}
      */
     public final static int UNSPECIFIED = -1;
@@ -235,6 +288,10 @@
         this.timestamp = tsf;
         this.distanceCm = UNSPECIFIED;
         this.distanceSdCm = UNSPECIFIED;
+        this.channelWidth = UNSPECIFIED;
+        this.centerFreq0 = UNSPECIFIED;
+        this.centerFreq1 = UNSPECIFIED;
+        this.is80211McRTTResponder = false;
     }
 
     /** {@hide} */
@@ -249,6 +306,29 @@
         this.timestamp = tsf;
         this.distanceCm = distCm;
         this.distanceSdCm = distSdCm;
+        this.channelWidth = UNSPECIFIED;
+        this.centerFreq0 = UNSPECIFIED;
+        this.centerFreq1 = UNSPECIFIED;
+        this.is80211McRTTResponder = false;
+    }
+
+    /** {@hide} */
+    public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
+            long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1,
+            boolean is80211McRTTResponder) {
+        this.wifiSsid = wifiSsid;
+        this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
+        this.BSSID = BSSID;
+        this.capabilities = caps;
+        this.level = level;
+        this.frequency = frequency;
+        this.timestamp = tsf;
+        this.distanceCm = distCm;
+        this.distanceSdCm = distSdCm;
+        this.channelWidth = channelWidth;
+        this.centerFreq0 = centerFreq0;
+        this.centerFreq1 = centerFreq1;
+        this.is80211McRTTResponder = is80211McRTTResponder;
     }
 
     /** copy constructor {@hide} */
@@ -260,10 +340,15 @@
             capabilities = source.capabilities;
             level = source.level;
             frequency = source.frequency;
+            channelWidth = source.channelWidth;
+            centerFreq0 = source.centerFreq0;
+            centerFreq1 = source.centerFreq1;
+            is80211McRTTResponder = source.is80211McRTTResponder;
             timestamp = source.timestamp;
             distanceCm = source.distanceCm;
             distanceSdCm = source.distanceSdCm;
             seen = source.seen;
+            passpoint = source.passpoint;
             autoJoinStatus = source.autoJoinStatus;
             untrusted = source.untrusted;
             numConnection = source.numConnection;
@@ -303,9 +388,15 @@
         sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
                 append("(cm)");
 
+        sb.append(", passpoint: ").append(passpoint != null ? "yes" : "no");
         if (autoJoinStatus != 0) {
             sb.append(", status: ").append(autoJoinStatus);
         }
+        sb.append(", ChannelBandwidth: ").append(channelWidth);
+        sb.append(", centerFreq0: ").append(centerFreq0);
+        sb.append(", centerFreq1: ").append(centerFreq1);
+        sb.append(", 80211mcResponder: ").append(is80211McRTTResponder?
+                "is supported":"is not supported");
         return sb.toString();
     }
 
@@ -329,6 +420,10 @@
         dest.writeLong(timestamp);
         dest.writeInt(distanceCm);
         dest.writeInt(distanceSdCm);
+        dest.writeInt(channelWidth);
+        dest.writeInt(centerFreq0);
+        dest.writeInt(centerFreq1);
+        dest.writeInt(is80211McRTTResponder ? 1 : 0);
         dest.writeLong(seen);
         dest.writeInt(autoJoinStatus);
         dest.writeInt(untrusted ? 1 : 0);
@@ -336,6 +431,12 @@
         dest.writeInt(numUsage);
         dest.writeInt(numIpConfigFailures);
         dest.writeInt(isAutoJoinCandidate);
+        if (passpoint != null) {
+            dest.writeInt(1);
+            passpoint.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
         if (informationElements != null) {
             dest.writeInt(informationElements.length);
             for (int i = 0; i < informationElements.length; i++) {
@@ -364,7 +465,11 @@
                     in.readInt(),
                     in.readLong(),
                     in.readInt(),
-                    in.readInt()
+                    in.readInt(),
+                    in.readInt(),
+                    in.readInt(),
+                    in.readInt(),
+                    in.readInt() == 1
                 );
                 sr.seen = in.readLong();
                 sr.autoJoinStatus = in.readInt();
@@ -373,6 +478,9 @@
                 sr.numUsage = in.readInt();
                 sr.numIpConfigFailures = in.readInt();
                 sr.isAutoJoinCandidate = in.readInt();
+                if (in.readInt() == 1) {
+                    sr.passpoint = WifiPasspointInfo.CREATOR.createFromParcel(in);
+                }
                 int n = in.readInt();
                 if (n != 0) {
                     sr.informationElements = new InformationElement[n];
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 87db951..872eb6f 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -19,19 +19,18 @@
 import android.annotation.SystemApi;
 import android.net.IpConfiguration;
 import android.net.IpConfiguration.ProxySettings;
-import android.net.IpConfiguration.IpAssignment;
 import android.net.ProxyInfo;
 import android.net.StaticIpConfiguration;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
-import android.annotation.SystemApi;
 
 import java.util.HashMap;
 import java.util.BitSet;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashSet;
 
 /**
  * A class representing a configured Wi-Fi network, including the
@@ -59,6 +58,7 @@
     public static final String updateIdentiferVarName = "update_identifier";
     /** {@hide} */
     public static final int INVALID_NETWORK_ID = -1;
+
     /**
      * Recognized key management schemes.
      */
@@ -233,17 +233,21 @@
      * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit.
      */
     public String BSSID;
+
     /**
-     * Fully qualified domain name (FQDN) of AAA server or RADIUS server
-     * e.g. {@code "mail.example.com"}.
+     * The band which AP resides on
+     * 0-2G  1-5G
+     * By default, 2G is chosen
      */
-    public String FQDN;
+    public int apBand = 0;
+
     /**
-     * Network access identifier (NAI) realm, for Passpoint credential.
-     * e.g. {@code "myhost.example.com"}.
-     * @hide
+     * The channel which AP resides on,currently, US only
+     * 2G  1-11
+     * 5G  36,40,44,48,149,153,157,161,165
+     * 0 - find a random available channel according to the apBand
      */
-    public String naiRealm;
+    public int apChannel = 0;
 
     /**
      * Pre-shared key for use with WPA-PSK.
@@ -328,6 +332,21 @@
     public WifiEnterpriseConfig enterpriseConfig;
 
     /**
+     * Fully qualified domain name of a passpoint configuration
+     */
+    public String FQDN;
+
+    /**
+     * Service provider name, for Passpoint credential.
+     */
+    public String providerFriendlyName;
+
+    /**
+     * Roaming Consortium Id, for Passpoint credential.
+     */
+    public HashSet<Long> roamingConsortiumIds;
+
+    /**
      * @hide
      */
     private IpConfiguration mIpConfiguration;
@@ -862,7 +881,7 @@
         SSID = null;
         BSSID = null;
         FQDN = null;
-        naiRealm = null;
+        roamingConsortiumIds = new HashSet<Long>();
         priority = 0;
         hiddenSSID = false;
         disableReason = DISABLED_UNKNOWN_REASON;
@@ -907,6 +926,17 @@
             }
         }
 
+        if (FQDN != null) {
+            /* must have a providerFriendlyName */
+            if (providerFriendlyName == null) {
+                return false;
+            }
+            /* this is passpoint configuration; it must have enterprise config */
+            if (enterpriseConfig == null) {
+                return false;
+            }
+        }
+
         // TODO: Add more checks
         return true;
     }
@@ -1042,8 +1072,9 @@
             sbuf.append("- DSBLE ");
         }
         sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
+                append(" PROVIDER-NAME: ").append(this.providerFriendlyName).
                 append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN).
-                append(" REALM: ").append(this.naiRealm).append(" PRIO: ").append(this.priority).
+                append(" PRIO: ").append(this.priority).
                 append('\n');
         if (this.numConnectionFailures > 0) {
             sbuf.append(" numConnectFailures ").append(this.numConnectionFailures).append("\n");
@@ -1383,6 +1414,8 @@
         String key;
         if (allowCached && mCachedConfigKey != null) {
             key = mCachedConfigKey;
+        } else if (providerFriendlyName != null) {
+            key = FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
         } else {
             if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
                 key = SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK];
@@ -1498,9 +1531,17 @@
             SSID = source.SSID;
             BSSID = source.BSSID;
             FQDN = source.FQDN;
-            naiRealm = source.naiRealm;
+            roamingConsortiumIds = new HashSet<Long>();
+            for (Long roamingConsortiumId : source.roamingConsortiumIds) {
+                roamingConsortiumIds.add(roamingConsortiumId);
+            }
+
+            providerFriendlyName = source.providerFriendlyName;
             preSharedKey = source.preSharedKey;
 
+            apBand = source.apBand;
+            apChannel = source.apChannel;
+
             wepKeys = new String[4];
             for (int i = 0; i < wepKeys.length; i++) {
                 wepKeys[i] = source.wepKeys[i];
@@ -1593,9 +1634,15 @@
         dest.writeInt(disableReason);
         dest.writeString(SSID);
         dest.writeString(BSSID);
+        dest.writeInt(apBand);
+        dest.writeInt(apChannel);
         dest.writeString(autoJoinBSSID);
         dest.writeString(FQDN);
-        dest.writeString(naiRealm);
+        dest.writeString(providerFriendlyName);
+        dest.writeInt(roamingConsortiumIds.size());
+        for (Long roamingConsortiumId : roamingConsortiumIds) {
+            dest.writeLong(roamingConsortiumId);
+        }
         dest.writeString(preSharedKey);
         for (String wepKey : wepKeys) {
             dest.writeString(wepKey);
@@ -1658,9 +1705,15 @@
                 config.disableReason = in.readInt();
                 config.SSID = in.readString();
                 config.BSSID = in.readString();
+                config.apBand = in.readInt();
+                config.apChannel = in.readInt();
                 config.autoJoinBSSID = in.readString();
                 config.FQDN = in.readString();
-                config.naiRealm = in.readString();
+                config.providerFriendlyName = in.readString();
+                int numRoamingConsortiumIds = in.readInt();
+                for (int i = 0; i < numRoamingConsortiumIds; i++) {
+                    config.roamingConsortiumIds.add(in.readLong());
+                }
                 config.preSharedKey = in.readString();
                 for (int i = 0; i < config.wepKeys.length; i++) {
                     config.wepKeys[i] = in.readString();
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index cf3cba3..36fc96b 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -54,6 +54,8 @@
     /** @hide */
     public static final String SUBJECT_MATCH_KEY   = "subject_match";
     /** @hide */
+    public static final String ALTSUBJECT_MATCH_KEY = "altsubject_match";
+    /** @hide */
     public static final String OPP_KEY_CACHING     = "proactive_key_caching";
     /**
      * String representing the keystore OpenSSL ENGINE's ID.
@@ -93,6 +95,11 @@
     public static final String ENGINE_ID_KEY       = "engine_id";
     /** @hide */
     public static final String PRIVATE_KEY_ID_KEY  = "key_id";
+    /** @hide */
+    public static final String REALM_KEY           = "realm";
+    /** @hide */
+    public static final String PLMN_KEY            = "plmn";
+
 
     private HashMap<String, String> mFields = new HashMap<String, String>();
     private X509Certificate mCaCert;
@@ -530,22 +537,74 @@
     }
 
     /**
-     * Set subject match. This is the substring to be matched against the subject of the
-     * authentication server certificate.
+     * Set subject match (deprecated). This is the substring to be matched against the subject of
+     * the authentication server certificate.
      * @param subjectMatch substring to be matched
+     * @deprecated in favor of altSubjectMatch
      */
     public void setSubjectMatch(String subjectMatch) {
         setFieldValue(SUBJECT_MATCH_KEY, subjectMatch, "");
     }
 
     /**
-     * Get subject match
+     * Get subject match (deprecated)
      * @return the subject match string
+     * @deprecated in favor of altSubjectMatch
      */
     public String getSubjectMatch() {
         return getFieldValue(SUBJECT_MATCH_KEY, "");
     }
 
+    /**
+     * Set alternate subject match. This is the substring to be matched against the
+     * alternate subject of the authentication server certificate.
+     * @param altSubjectMatch substring to be matched, for example
+     *                     DNS:server.example.com;EMAIL:server@example.com
+     */
+    public void setAltSubjectMatch(String altSubjectMatch) {
+        setFieldValue(ALTSUBJECT_MATCH_KEY, altSubjectMatch, "");
+    }
+
+    /**
+     * Get alternate subject match
+     * @return the alternate subject match string
+     */
+    public String getAltSubjectMatch() {
+        return getFieldValue(ALTSUBJECT_MATCH_KEY, "");
+    }
+
+    /**
+     * Set realm for passpoint credential
+     * @param realm the realm
+     */
+    public void setRealm(String realm) {
+        setFieldValue(REALM_KEY, realm, "");
+    }
+
+    /**
+     * Get realm for passpoint credential
+     * @return the realm
+     */
+    public String getRealm() {
+        return getFieldValue(REALM_KEY, "");
+    }
+
+    /**
+     * Set plmn for passpoint credential
+     * @param plmn the plmn value derived from mcc & mnc
+     */
+    public void setPlmn(String plmn) {
+        setFieldValue(PLMN_KEY, plmn, "");
+    }
+
+    /**
+     * Set plmn for passpoint credential
+     * @return the plmn
+     */
+    public String getPlmn() {
+        return getFieldValue(PLMN_KEY, "");
+    }
+
     /** See {@link WifiConfiguration#getKeyIdForCredentials} @hide */
     String getKeyId(WifiEnterpriseConfig current) {
         String eap = mFields.get(EAP_KEY);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b001bb8..40d40bb 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1238,6 +1238,21 @@
     }
 
     /**
+    * get the country code.
+    * @return the country code in ISO 3166 format.
+    *
+    * @hide
+    */
+    public String getCountryCode() {
+       try {
+           String country = mService.getCountryCode();
+           return(country);
+       } catch (RemoteException e) {
+           return null;
+       }
+    }
+
+    /**
      * Set the operational frequency band.
      * @param band  One of
      *     {@link #WIFI_FREQUENCY_BAND_AUTO},
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index aaa2f98..fea934f 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -158,6 +158,11 @@
         public int reportEvents;
         /** defines number of bssids to cache from each scan */
         public int numBssidsPerScan;
+        /**
+         * defines number of scans to cache; use it with REPORT_EVENT_AFTER_BUFFER_FULL
+         * to wake up at fixed interval
+         */
+        public int maxScansToCache;
 
         /** Implement the Parcelable interface {@hide} */
         public int describeContents() {
@@ -170,6 +175,7 @@
             dest.writeInt(periodInMs);
             dest.writeInt(reportEvents);
             dest.writeInt(numBssidsPerScan);
+            dest.writeInt(maxScansToCache);
 
             if (channels != null) {
                 dest.writeInt(channels.length);
@@ -194,6 +200,7 @@
                         settings.periodInMs = in.readInt();
                         settings.reportEvents = in.readInt();
                         settings.numBssidsPerScan = in.readInt();
+                        settings.maxScansToCache = in.readInt();
                         int num_channels = in.readInt();
                         settings.channels = new ChannelSpec[num_channels];
                         for (int i = 0; i < num_channels; i++) {
@@ -215,8 +222,143 @@
 
     }
 
-    /** @hide */
+    /**
+     * all the information garnered from a single scan
+     */
+    public static class ScanData implements Parcelable {
+        /** scan identifier */
+        private int mId;
+        /** additional information about scan
+         * 0 => no special issues encountered in the scan
+         * non-zero => scan was truncated, so results may not be complete
+         */
+        private int mFlags;
+        /** all scan results discovered in this scan, sorted by timestamp in ascending order */
+        private ScanResult mResults[];
+
+        ScanData() {}
+
+        public ScanData(int id, int flags, ScanResult[] results) {
+            mId = id;
+            mFlags = flags;
+            mResults = results;
+        }
+
+        public ScanData(ScanData s) {
+            mId = s.mId;
+            mFlags = s.mFlags;
+            mResults = new ScanResult[s.mResults.length];
+            for (int i = 0; i < s.mResults.length; i++) {
+                ScanResult result = s.mResults[i];
+                WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(result.SSID);
+                ScanResult newResult = new ScanResult(result);
+                newResult.wifiSsid = wifiSsid;
+                mResults[i] = newResult;
+            }
+        }
+
+        public int getId() {
+            return mId;
+        }
+
+        public int getFlags() {
+            return mFlags;
+        }
+
+        public ScanResult[] getResults() {
+            return mResults;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            if (mResults != null) {
+                dest.writeInt(mId);
+                dest.writeInt(mFlags);
+                dest.writeInt(mResults.length);
+                for (int i = 0; i < mResults.length; i++) {
+                    ScanResult result = mResults[i];
+                    result.writeToParcel(dest, flags);
+                }
+            } else {
+                dest.writeInt(0);
+            }
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<ScanData> CREATOR =
+                new Creator<ScanData>() {
+                    public ScanData createFromParcel(Parcel in) {
+                        int id = in.readInt();
+                        int flags = in.readInt();
+                        int n = in.readInt();
+                        ScanResult results[] = new ScanResult[n];
+                        for (int i = 0; i < n; i++) {
+                            results[i] = ScanResult.CREATOR.createFromParcel(in);
+                        }
+                        return new ScanData(id, flags, results);
+                    }
+
+                    public ScanData[] newArray(int size) {
+                        return new ScanData[size];
+                    }
+                };
+    }
+
+    public static class ParcelableScanData implements Parcelable {
+
+        public ScanData mResults[];
+
+        public ParcelableScanData(ScanData[] results) {
+            mResults = results;
+        }
+
+        public ScanData[] getResults() {
+            return mResults;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            if (mResults != null) {
+                dest.writeInt(mResults.length);
+                for (int i = 0; i < mResults.length; i++) {
+                    ScanData result = mResults[i];
+                    result.writeToParcel(dest, flags);
+                }
+            } else {
+                dest.writeInt(0);
+            }
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<ParcelableScanData> CREATOR =
+                new Creator<ParcelableScanData>() {
+                    public ParcelableScanData createFromParcel(Parcel in) {
+                        int n = in.readInt();
+                        ScanData results[] = new ScanData[n];
+                        for (int i = 0; i < n; i++) {
+                            results[i] = ScanData.CREATOR.createFromParcel(in);
+                        }
+                        return new ParcelableScanData(results);
+                    }
+
+                    public ParcelableScanData[] newArray(int size) {
+                        return new ParcelableScanData[size];
+                    }
+                };
+    }
+
     public static class ParcelableScanResults implements Parcelable {
+
         public ScanResult mResults[];
 
         public ParcelableScanResults(ScanResult[] results) {
@@ -264,7 +406,8 @@
     }
 
     /**
-     * interface to get scan events on; specify this on {@link #startBackgroundScan}
+     * interface to get scan events on; specify this on {@link #startBackgroundScan} or
+     * {@link #startScan}
      */
     public interface ScanListener extends ActionListener {
         /**
@@ -273,10 +416,15 @@
          */
         public void onPeriodChanged(int periodInMs);
         /**
-         * reports results retrieved from background scan
+         * reports results retrieved from background scan and single shot scans
+         * @deprecated in favor of {@link #onResults(ScanData[])}
          */
         public void onResults(ScanResult[] results);
         /**
+         * reports results retrieved from background scan and single shot scans
+         */
+        public void onResults(ScanData[] results);
+        /**
          * reports full scan result for each access point found in scan
          */
         public void onFullResult(ScanResult fullScanResult);
@@ -303,13 +451,36 @@
         sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, removeListener(listener));
     }
     /**
-     * retrieves currently available scan results
+     * reports currently available scan results on appropriate listeners
      */
     public ScanResult[] getScanResults() {
         validateChannel();
         Message reply = sAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0);
-        ScanResult[] results = (ScanResult[]) reply.obj;
-        return results;
+        // return reply.what == CMD_OP_SUCCEEDED;
+        return null;
+    }
+
+    /**
+     * starts a single scan and reports results asynchronously
+     * @param settings specifies various parameters for the scan; for more information look at
+     * {@link ScanSettings}
+     * @param listener specifies the object to report events to. This object is also treated as a
+     *                 key for this scan, and must also be specified to cancel the scan. Multiple
+     *                 scans should also not share this object.
+     */
+    public void startScan(ScanSettings settings, ScanListener listener) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, putListener(listener), settings);
+    }
+
+    /**
+     * stops an ongoing single shot scan; only useful after {@link #startScan} if onResults()
+     * hasn't been called on the listener, ignored otherwise
+     * @param listener
+     */
+    public void stopScan(ScanListener listener) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, removeListener(listener));
     }
 
     /** specifies information about an access point of interest */
@@ -468,6 +639,10 @@
          * @param results list of scan results, one for each access point visible currently
          */
         public void onFound(ScanResult[] results);
+        /** indicates that access points were missed by on going scans
+         * @param results list of scan results, for each access point that is not visible anymore
+         */
+        public void onLost(ScanResult[] results);
     }
 
     /** @hide */
@@ -593,6 +768,12 @@
     public static final int CMD_PERIOD_CHANGED              = BASE + 19;
     /** @hide */
     public static final int CMD_FULL_SCAN_RESULT            = BASE + 20;
+    /** @hide */
+    public static final int CMD_START_SINGLE_SCAN           = BASE + 21;
+    /** @hide */
+    public static final int CMD_STOP_SINGLE_SCAN            = BASE + 22;
+    /** @hide */
+    public static final int CMD_SINGLE_SCAN_COMPLETED       = BASE + 23;
 
     private Context mContext;
     private IWifiScanner mService;
@@ -800,7 +981,7 @@
                     break;
                 case CMD_SCAN_RESULT :
                     ((ScanListener) listener).onResults(
-                            ((ParcelableScanResults) msg.obj).getResults());
+                            ((ParcelableScanData) msg.obj).getResults());
                     return;
                 case CMD_FULL_SCAN_RESULT :
                     ScanResult result = (ScanResult) msg.obj;
@@ -813,6 +994,10 @@
                     ((BssidListener) listener).onFound(
                             ((ParcelableScanResults) msg.obj).getResults());
                     return;
+                case CMD_AP_LOST:
+                    ((BssidListener) listener).onLost(
+                            ((ParcelableScanResults) msg.obj).getResults());
+                    return;
                 case CMD_WIFI_CHANGE_DETECTED:
                     ((WifiChangeListener) listener).onChanging(
                             ((ParcelableScanResults) msg.obj).getResults());
@@ -821,6 +1006,10 @@
                     ((WifiChangeListener) listener).onQuiescence(
                             ((ParcelableScanResults) msg.obj).getResults());
                     return;
+                case CMD_SINGLE_SCAN_COMPLETED:
+                    Log.d(TAG, "removing listener for single scan");
+                    removeListener(msg.arg2);
+                    break;
                 default:
                     if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
                     return;
diff --git a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
new file mode 100644
index 0000000..50bec33
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.passpoint;
+
+import android.net.wifi.ScanResult;
+import android.net.wifi.passpoint.WifiPasspointPolicy;
+import android.net.wifi.passpoint.WifiPasspointCredential;
+import android.os.Messenger;
+
+/**
+ * Interface that allows controlling and querying Wifi Passpoint connectivity.
+ *
+ * {@hide}
+ */
+interface IWifiPasspointManager
+{
+    Messenger getMessenger();
+
+    int getPasspointState();
+
+    List<WifiPasspointPolicy> requestCredentialMatch(in List<ScanResult> requested);
+
+    List<WifiPasspointCredential> getCredentials();
+
+    boolean addCredential(in WifiPasspointCredential cred);
+
+    boolean updateCredential(in WifiPasspointCredential cred);
+
+    boolean removeCredential(in WifiPasspointCredential cred);
+}
+
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.aidl
new file mode 100644
index 0000000..cfd3605
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.passpoint;
+
+parcelable WifiPasspointCredential;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
new file mode 100644
index 0000000..0a7230f
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
@@ -0,0 +1,667 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.passpoint;
+
+import android.net.wifi.WifiEnterpriseConfig;
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * A class representing a Wi-Fi Passpoint credential.
+ * @hide
+ */
+public class WifiPasspointCredential implements Parcelable {
+
+    private final static String TAG = "PasspointCredential";
+    private final static boolean DBG = true;
+
+    /** Wi-Fi nodes**/
+    private String mWifiSpFqdn;
+
+    /** PerProviderSubscription nodes **/
+    private String mCredentialName;
+
+    /** SubscriptionUpdate nodes **/
+    private String mSubscriptionUpdateInterval;
+    private String mSubscriptionUpdateMethod;
+    private String mSubscriptionUpdateRestriction;
+    private String mSubscriptionUpdateURI;
+    private String mSubscriptionUpdateUsername;
+    private String mSubscriptionUpdatePassword;
+
+    /** HomeSP nodes **/
+    private String mHomeSpFqdn;
+    private String mFriendlyName;
+    private Collection<WifiPasspointDmTree.HomeOIList> mHomeOIList;
+    private Collection<WifiPasspointDmTree.OtherHomePartners> mOtherHomePartnerList;
+
+    /** SubscriptionParameters nodes**/
+    private String mCreationDate;
+    private String mExpirationDate;
+
+    /** Credential nodes **/
+    private String mType;
+    private String mInnerMethod;
+    private String mCertType;
+    private String mCertSha256Fingerprint;
+    private String mUpdateIdentifier;
+    private String mUsername;
+    private String mPasswd;
+    private String mRealm;
+    private String mImsi;
+    private String mMcc;
+    private String mMnc;
+    private String mCaRootCert;
+    private String mClientCert;
+    private boolean mCheckAaaServerCertStatus;
+
+    /** Policy nodes **/
+    private String mPolicyUpdateUri;
+    private String mPolicyUpdateInterval;
+    private String mPolicyUpdateUsername;
+    private String mPolicyUpdatePassword;
+    private String mPolicyUpdateRestriction;
+    private String mPolicyUpdateMethod;
+    private Collection<WifiPasspointDmTree.PreferredRoamingPartnerList> mPreferredRoamingPartnerList;
+    private Collection<WifiPasspointDmTree.MinBackhaulThresholdNetwork> mMinBackhaulThresholdNetwork;
+    private Collection<WifiPasspointDmTree.SPExclusionList> mSpExclusionList;
+    private Collection<WifiPasspointDmTree.RequiredProtoPortTuple> mRequiredProtoPortTuple;
+    private String mMaxBssLoad;
+
+    /** CrednetialPriority node **/
+    private int mCrednetialPriority;
+
+    /** AAAServerTrustRoot nodes **/
+    private String mAaaCertUrl;
+    private String mAaaSha256Fingerprint;
+
+    /** Others **/
+    private boolean mIsMachineRemediation;
+    private boolean mUserPreferred = false;
+    private String mWifiTreePath;
+    private WifiEnterpriseConfig mEnterpriseConfig;
+
+    /** @hide */
+    public WifiPasspointCredential() {}
+
+    /**
+     * Constructor
+     * @param realm Realm of the passpoint credential
+     * @param fqdn Fully qualified domain name (FQDN) of the credential
+     * @param config Enterprise config, must be either EAP-TLS or EAP-TTLS
+     * @see WifiEnterpriseConfig
+     */
+    public WifiPasspointCredential(String realm, String fqdn, WifiEnterpriseConfig config) {
+        mRealm = realm;
+        switch (config.getEapMethod()) {
+            case WifiEnterpriseConfig.Eap.TLS:
+            case WifiEnterpriseConfig.Eap.TTLS:
+                mEnterpriseConfig = new WifiEnterpriseConfig(config);
+                break;
+            default:
+                // ignore
+        }
+    }
+
+    /** @hide */
+    public WifiPasspointCredential(String type,
+            String caroot,
+            String clientcert,
+            String mcc,
+            String mnc,
+            WifiPasspointDmTree.SpFqdn sp,
+            WifiPasspointDmTree.CredentialInfo credinfo) {
+
+        if (credinfo == null) {
+            return;
+        }
+
+        mType = type;
+        mCaRootCert = caroot;
+        mClientCert = clientcert;
+
+        mWifiSpFqdn = sp.nodeName;
+        mUpdateIdentifier = sp.perProviderSubscription.UpdateIdentifier;
+
+        mCredentialName = credinfo.nodeName;
+        mOtherHomePartnerList = credinfo.homeSP.otherHomePartners.values();
+
+        Set set = credinfo.aAAServerTrustRoot.entrySet();
+        Iterator i = set.iterator();
+        if (i.hasNext()) {
+            Map.Entry entry3 = (Map.Entry) i.next();
+            WifiPasspointDmTree.AAAServerTrustRoot aaa = (WifiPasspointDmTree.AAAServerTrustRoot) entry3.getValue();
+            mAaaCertUrl = aaa.CertURL;
+            mAaaSha256Fingerprint = aaa.CertSHA256Fingerprint;
+        }
+
+        mCertType = credinfo.credential.digitalCertificate.CertificateType;
+        mCertSha256Fingerprint = credinfo.credential.digitalCertificate.CertSHA256Fingerprint;
+        mUsername = credinfo.credential.usernamePassword.Username;
+        mPasswd = credinfo.credential.usernamePassword.Password;
+        mIsMachineRemediation = credinfo.credential.usernamePassword.MachineManaged;
+        mInnerMethod = credinfo.credential.usernamePassword.eAPMethod.InnerMethod;
+        mImsi = credinfo.credential.sim.IMSI;
+        mMcc = mcc;
+        mMnc = mnc;
+        mCreationDate = credinfo.credential.CreationDate;
+        mExpirationDate = credinfo.credential.ExpirationDate;
+        mRealm = credinfo.credential.Realm;
+
+        if (credinfo.credentialPriority == null) {
+            mCrednetialPriority = 128;
+        } else {
+            mCrednetialPriority = Integer.parseInt(credinfo.credentialPriority);
+        }
+
+        mHomeSpFqdn = credinfo.homeSP.FQDN;
+
+        mSubscriptionUpdateInterval = credinfo.subscriptionUpdate.UpdateInterval;
+        mSubscriptionUpdateMethod = credinfo.subscriptionUpdate.UpdateMethod;
+        mSubscriptionUpdateRestriction = credinfo.subscriptionUpdate.Restriction;
+        mSubscriptionUpdateURI = credinfo.subscriptionUpdate.URI;
+        mSubscriptionUpdateUsername = credinfo.subscriptionUpdate.usernamePassword.Username;
+        mSubscriptionUpdatePassword = credinfo.subscriptionUpdate.usernamePassword.Password;
+
+        mPolicyUpdateUri = credinfo.policy.policyUpdate.URI;
+        mPolicyUpdateInterval = credinfo.policy.policyUpdate.UpdateInterval;
+        mPolicyUpdateUsername = credinfo.policy.policyUpdate.usernamePassword.Username;
+        mPolicyUpdatePassword = credinfo.policy.policyUpdate.usernamePassword.Password;
+        mPolicyUpdateRestriction = credinfo.policy.policyUpdate.Restriction;
+        mPolicyUpdateMethod = credinfo.policy.policyUpdate.UpdateMethod;
+        mPreferredRoamingPartnerList = credinfo.policy.preferredRoamingPartnerList.values();
+        mMinBackhaulThresholdNetwork = credinfo.policy.minBackhaulThreshold.values();
+        mRequiredProtoPortTuple = credinfo.policy.requiredProtoPortTuple.values();
+        mMaxBssLoad = credinfo.policy.maximumBSSLoadValue;
+        mSpExclusionList = credinfo.policy.sPExclusionList.values();
+
+        mHomeOIList = credinfo.homeSP.homeOIList.values();
+        mFriendlyName = credinfo.homeSP.FriendlyName;
+        mCheckAaaServerCertStatus = credinfo.credential.CheckAAAServerCertStatus;
+    }
+
+    /** @hide */
+    public String getUpdateIdentifier() {
+        return mUpdateIdentifier;
+    }
+
+    /** @hide */
+    public String getUpdateMethod() {
+        return mSubscriptionUpdateMethod;
+    }
+
+    /** @hide */
+    public void setUpdateMethod(String method) {
+        mSubscriptionUpdateMethod = method;
+    }
+
+    /** @hide */
+    public String getWifiSpFqdn() {
+        return mWifiSpFqdn;
+    }
+
+    /** @hide */
+    public String getCredName() {
+        return mCredentialName;
+    }
+
+    /** @hide */
+    public String getType() {
+        return mType;
+    }
+
+    /**
+     * Get enterprise config of this Passpoint credential.
+     * @return Enterprise config
+     * @see WifiEnterpriseConfig
+     */
+    public WifiEnterpriseConfig getEnterpriseConfig() {
+        return new WifiEnterpriseConfig(mEnterpriseConfig);
+    }
+
+    /**
+     * Set enterprise config of this Passpoint credential.
+     * @param config Enterprise config, must be either EAP-TLS or EAP-TTLS
+     * @see WifiEnterpriseConfig
+     */
+    public void setEnterpriseConfig(WifiEnterpriseConfig config) {
+        // TODO
+    }
+
+    /** @hide */
+    public String getCertType() {
+        return mCertType;
+    }
+
+    /** @hide */
+    public String getCertSha256Fingerprint() {
+        return mCertSha256Fingerprint;
+    }
+
+    /** @hide */
+    public String getUserName() {
+        return mUsername;
+    }
+
+    /** @hide */
+    public String getPassword() {
+        // TODO: guarded by connectivity internal
+        return mPasswd;
+    }
+
+    /** @hide */
+    public String getImsi() {
+        return mImsi;
+    }
+
+    /** @hide */
+    public String getMcc() {
+        return mMcc;
+    }
+
+    /** @hide */
+    public String getMnc() {
+        return mMnc;
+    }
+
+    /** @hide */
+    public String getCaRootCertPath() {
+        return mCaRootCert;
+    }
+
+    /** @hide */
+    public String getClientCertPath() {
+        return mClientCert;
+    }
+
+    /**
+     * Get the realm of this Passpoint credential.
+     * @return Realm
+     */
+    public String getRealm() {
+        return mRealm;
+    }
+
+    /**
+     * Set the ream of this Passpoint credential.
+     * @param realm Realm
+     */
+    public void setRealm(String realm) {
+        mRealm = realm;
+    }
+
+    /** @hide */
+    public int getPriority() {
+        if (mUserPreferred) {
+            return 0;
+        }
+
+        return mCrednetialPriority;
+    }
+
+    /**
+     * Get the fully qualified domain name (FQDN) of this Passpoint credential.
+     * @return FQDN
+     */
+    public String getHomeSpFqdn() {
+        return mHomeSpFqdn;
+    }
+
+    /**
+     * Set the fully qualified domain name (FQDN) of this Passpoint credential.
+     * @param fqdn FQDN
+     */
+    public void setHomeFqdn(String fqdn) {
+        mHomeSpFqdn = fqdn;
+    }
+
+
+    /** @hide */
+    public Collection<WifiPasspointDmTree.OtherHomePartners> getOtherHomePartnerList() {
+        return mOtherHomePartnerList;
+    }
+
+    /** @hide */
+    public String getSubscriptionUpdateUsername() {
+        return mSubscriptionUpdateUsername;
+    }
+
+    /** @hide */
+    public String getSubscriptionUpdatePassword() {
+        return mSubscriptionUpdatePassword;
+    }
+
+    /** @hide */
+    public String getPolicyUpdateUri() {
+        return mPolicyUpdateUri;
+    }
+
+    /** @hide */
+    public String getPolicyUpdateInterval() {
+        return mPolicyUpdateInterval;
+    }
+
+    /** @hide */
+    public String getPolicyUpdateUsername() {
+        return mPolicyUpdateUsername;
+    }
+
+    /** @hide */
+    public String getPolicyUpdatePassword() {
+        return mPolicyUpdatePassword;
+    }
+
+    /** @hide */
+    public String getPolicyUpdateRestriction() {
+        return mPolicyUpdateRestriction;
+    }
+
+    /** @hide */
+    public String getPolicyUpdateMethod() {
+        return mPolicyUpdateMethod;
+    }
+
+    /** @hide */
+    public String getCreationDate() {
+        return mCreationDate;
+    }
+
+    /** @hide */
+    public String getExpirationDate() {
+        return mExpirationDate;
+    }
+
+    /** @hide */
+    public void setExpirationDate(String expirationdate) {
+        mExpirationDate = expirationdate;
+    }
+
+    /** @hide */
+    public Collection<WifiPasspointDmTree.PreferredRoamingPartnerList> getPreferredRoamingPartnerList() {
+        return mPreferredRoamingPartnerList;
+    }
+
+    /** @hide */
+    public Collection<WifiPasspointDmTree.HomeOIList> getHomeOiList() {
+        return mHomeOIList;
+    }
+
+    /** @hide */
+    public Collection<WifiPasspointDmTree.MinBackhaulThresholdNetwork> getBackhaulThresholdList() {
+        return mMinBackhaulThresholdNetwork;
+    }
+
+    /** @hide */
+    public Collection<WifiPasspointDmTree.RequiredProtoPortTuple> getRequiredProtoPortList() {
+        return mRequiredProtoPortTuple;
+    }
+
+    /** @hide */
+    public Collection<WifiPasspointDmTree.SPExclusionList> getSPExclusionList() {
+        return mSpExclusionList;
+    }
+
+    /** @hide */
+    public boolean getIsMachineRemediation() {
+        return mIsMachineRemediation;
+    }
+
+    /** @hide */
+    public String getAaaCertUrl() {
+        return mAaaCertUrl;
+    }
+
+    /** @hide */
+    public String getAaaSha256Fingerprint() {
+        return mAaaSha256Fingerprint;
+    }
+
+    /** @hide */
+    public String getSubscriptionUpdateRestriction() {
+        return mSubscriptionUpdateRestriction;
+    }
+
+    /** @hide */
+    public String getSubscriptionUpdateURI() {
+        return mSubscriptionUpdateURI;
+    }
+
+    /** @hide */
+    public String getSubscriptionUpdateInterval() {
+        return mSubscriptionUpdateInterval;
+    }
+
+    /** @hide */
+    public String getFriendlyName() {
+        return mFriendlyName;
+    }
+
+    /** @hide */
+    public String getMaxBssLoad() {
+        return mMaxBssLoad;
+    }
+
+    /** @hide */
+    public boolean getUserPreference() {
+        return mUserPreferred;
+    }
+
+    /** @hide */
+    public boolean getCheckAaaServerCertStatus() {
+        return mCheckAaaServerCertStatus;
+    }
+
+    /** @hide */
+    public void setUserPreference(boolean value) {
+        mUserPreferred = value;
+    }
+
+    @Override
+    /** @hide */
+    public boolean equals(Object obj) {
+        boolean result = false;
+        if (obj instanceof WifiPasspointCredential) {
+            final WifiPasspointCredential other = (WifiPasspointCredential) obj;
+            if (this.mType.equals(other.mType)) {
+                if (this.mType.equals("TTLS")) {
+                    result = this.mUsername.equals(other.mUsername) &&
+                            this.mPasswd.equals(other.mPasswd) &&
+                            this.mRealm.equals(other.mRealm) &&
+                            this.mHomeSpFqdn.equals(other.mHomeSpFqdn);
+                }
+                if (this.mType.equals("TLS")) {
+                    result = this.mRealm.equals(other.mRealm) &&
+                            this.mHomeSpFqdn.equals(other.mHomeSpFqdn) &&
+                            this.mClientCert.equals(other.mClientCert);
+                }
+                if (this.mType.equals("SIM")) {
+                    result = this.mMcc.equals(other.mMcc) &&
+                            this.mMnc.equals(other.mMnc) &&
+                            this.mImsi.equals(other.mImsi) &&
+                            this.mHomeSpFqdn.equals(other.mHomeSpFqdn);
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    /** @hide */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        String none = "<none>";
+
+        if (!DBG) {
+            sb.append(none);
+        } else {
+            sb.append(", UpdateIdentifier: ")
+            .append(mUpdateIdentifier == null ? none : mUpdateIdentifier)
+            .append(", SubscriptionUpdateMethod: ")
+            .append(mSubscriptionUpdateMethod == null ? none : mSubscriptionUpdateMethod)
+            .append(", Type: ").append(mType == null ? none : mType)
+            .append(", Username: ").append(mUsername == null ? none : mUsername)
+            .append(", Passwd: ").append(mPasswd == null ? none : mPasswd)
+            .append(", SubDMAccUsername: ")
+            .append(mSubscriptionUpdateUsername == null ? none : mSubscriptionUpdateUsername)
+            .append(", SubDMAccPassword: ")
+            .append(mSubscriptionUpdatePassword == null ? none : mSubscriptionUpdatePassword)
+            .append(", PolDMAccUsername: ")
+            .append(mPolicyUpdateUsername == null ? none : mPolicyUpdateUsername)
+            .append(", PolDMAccPassword: ")
+            .append(mPolicyUpdatePassword == null ? none : mPolicyUpdatePassword)
+            .append(", Imsi: ").append(mImsi == null ? none : mImsi)
+            .append(", Mcc: ").append(mMcc == null ? none : mMcc)
+            .append(", Mnc: ").append(mMnc == null ? none : mMnc)
+            .append(", CaRootCert: ").append(mCaRootCert == null ? none : mCaRootCert)
+            .append(", Realm: ").append(mRealm == null ? none : mRealm)
+            .append(", Priority: ").append(mCrednetialPriority)
+            .append(", Fqdn: ").append(mHomeSpFqdn == null ? none : mHomeSpFqdn)
+            .append(", Otherhomepartners: ")
+            .append(mOtherHomePartnerList == null ? none : mOtherHomePartnerList)
+            .append(", ExpirationDate: ")
+            .append(mExpirationDate == null ? none : mExpirationDate)
+            .append(", MaxBssLoad: ").append(mMaxBssLoad == null ? none : mMaxBssLoad)
+            .append(", SPExclusionList: ").append(mSpExclusionList);
+
+            if (mPreferredRoamingPartnerList != null) {
+                sb.append("PreferredRoamingPartnerList:");
+                for (WifiPasspointDmTree.PreferredRoamingPartnerList prpListItem : mPreferredRoamingPartnerList) {
+                    sb.append("[fqdnmatch:").append(prpListItem.FQDN_Match).
+                            append(", priority:").append(prpListItem.Priority).
+                            append(", country:").append(prpListItem.Country).append("]");
+                }
+            }
+
+            if (mHomeOIList != null) {
+                sb.append("HomeOIList:");
+                for (WifiPasspointDmTree.HomeOIList HomeOIListItem : mHomeOIList) {
+                    sb.append("[HomeOI:").append(HomeOIListItem.HomeOI).
+                            append(", HomeOIRequired:").append(HomeOIListItem.HomeOIRequired).
+                            append("]");
+                }
+            }
+
+            if (mMinBackhaulThresholdNetwork != null) {
+                sb.append("BackHaulThreshold:");
+                for (WifiPasspointDmTree.MinBackhaulThresholdNetwork BhtListItem : mMinBackhaulThresholdNetwork) {
+                    sb.append("[networkType:").append(BhtListItem.NetworkType).
+                            append(", dlBandwidth:").append(BhtListItem.DLBandwidth).
+                            append(", ulBandwidth:").append(BhtListItem.ULBandwidth).
+                            append("]");
+                }
+            }
+
+            if (mRequiredProtoPortTuple != null) {
+                sb.append("WifiMORequiredProtoPortTupleList:");
+                for (WifiPasspointDmTree.RequiredProtoPortTuple RpptListItem : mRequiredProtoPortTuple) {
+                    sb.append("[IPProtocol:").append(RpptListItem.IPProtocol).
+                            append(", PortNumber:").append(RpptListItem.PortNumber).
+                            append("]");
+                }
+            }
+        }
+        return sb.toString();
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mWifiSpFqdn);
+        dest.writeString(mCredentialName);
+        dest.writeString(mType);
+        dest.writeInt(mCrednetialPriority);
+        dest.writeString(mHomeSpFqdn);
+        dest.writeString(mRealm);
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public void readFromParcel(Parcel in) {
+        mWifiSpFqdn = in.readString();
+        mCredentialName = in.readString();
+        mType = in.readString();
+        mCrednetialPriority = in.readInt();
+        mHomeSpFqdn = in.readString();
+        mRealm = in.readString();
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public static final Creator<WifiPasspointCredential> CREATOR =
+            new Creator<WifiPasspointCredential>() {
+                public WifiPasspointCredential createFromParcel(Parcel in) {
+                    WifiPasspointCredential pc = new WifiPasspointCredential();
+                    pc.mWifiSpFqdn = in.readString();
+                    pc.mCredentialName = in.readString();
+                    pc.mType = in.readString();
+                    pc.mCrednetialPriority = in.readInt();
+                    pc.mHomeSpFqdn = in.readString();
+                    pc.mRealm = in.readString();
+                    return pc;
+                }
+
+                public WifiPasspointCredential[] newArray(int size) {
+                    return new WifiPasspointCredential[size];
+                }
+            };
+
+    /** @hide */
+    public int compareTo(WifiPasspointCredential another) {
+
+        //The smaller the higher
+        if (mCrednetialPriority < another.mCrednetialPriority) {
+            return -1;
+        } else if (mCrednetialPriority == another.mCrednetialPriority) {
+            return this.mType.compareTo(another.mType);
+        } else {
+            return 1;
+        }
+    }
+
+    @Override
+    /** @hide */
+    public int hashCode() {
+        int hash = 208;
+        if (mType != null) {
+            hash += mType.hashCode();
+        }
+        if (mRealm != null) {
+            hash += mRealm.hashCode();
+        }
+        if (mHomeSpFqdn != null) {
+            hash += mHomeSpFqdn.hashCode();
+        }
+        if (mUsername != null) {
+            hash += mUsername.hashCode();
+        }
+        if (mPasswd != null) {
+            hash += mPasswd.hashCode();
+        }
+
+        return hash;
+    }
+}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.aidl
new file mode 100644
index 0000000..6a88b2e
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.passpoint;
+
+parcelable WifiPasspointDmTree;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java
new file mode 100644
index 0000000..bbf5fc6
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java
@@ -0,0 +1,1377 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.passpoint;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.util.Log;
+
+import java.util.HashMap;
+
+/**
+ * Required Mobile Device Management Tree Structure
+ *
+ *                   +----------+
+ *                   | ./(Root) |
+ *                   +----+-----+
+ *                        |
+ *  +---------+           |         +---------+  +---------+
+ *  | DevInfo |-----------+---------|  Wi-Fi  |--|SP FQDN* |
+ *  +---------+           |         +---------+  +---------+
+ *  +---------+           |                           |
+ *  |DevDetail|-----------+                      +-----------------------+
+ *  +---------+                                  |PerproviderSubscription|--<X>+
+ *                                               +-----------------------+
+ *
+ * This class contains all nodes start from Wi-Fi
+ * @hide
+ **/
+public class WifiPasspointDmTree implements Parcelable {
+    private final static String TAG = "WifiTree";
+    public int PpsMoId;//plugfest used only
+    public HashMap<String, SpFqdn> spFqdn = new HashMap<String, SpFqdn>();//Maps.newHashMap();
+
+    public SpFqdn createSpFqdn(String name) {
+        SpFqdn obj = new SpFqdn(name);
+        spFqdn.put(name, obj);
+        return obj;
+    }
+
+    public static class SpFqdn implements Parcelable {
+        public String nodeName;
+        public PerProviderSubscription perProviderSubscription = new PerProviderSubscription();
+
+        public SpFqdn(String name) {
+            nodeName = name;
+        }
+
+        public SpFqdn() {
+        }
+
+        public SpFqdn(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(nodeName);
+            out.writeParcelable(perProviderSubscription, flags);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                nodeName = in.readString();
+                perProviderSubscription = in.readParcelable(PerProviderSubscription.class
+                        .getClassLoader());
+            }
+        }
+
+        public static final Parcelable.Creator<SpFqdn> CREATOR = new Parcelable.Creator<SpFqdn>() {
+            public SpFqdn createFromParcel(Parcel in) {
+                return new SpFqdn(in);
+            }
+
+            public SpFqdn[] newArray(int size) {
+                return new SpFqdn[size];
+            }
+        };
+    }
+
+    /**
+     * PerProviderSubscription
+     **/
+    public static class PerProviderSubscription implements Parcelable {
+        /**
+         * PerProviderSubscription/UpdateIdentifier
+         **/
+        public String UpdateIdentifier;
+        public HashMap<String, CredentialInfo> credentialInfo = new HashMap<String, CredentialInfo>();
+
+        public CredentialInfo createCredentialInfo(String name) {
+            CredentialInfo obj = new CredentialInfo(name);
+            credentialInfo.put(name, obj);
+            return obj;
+        }
+
+        public PerProviderSubscription() {
+        }
+
+        public PerProviderSubscription(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(UpdateIdentifier);
+            out.writeMap(credentialInfo);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                UpdateIdentifier = in.readString();
+                in.readMap(credentialInfo, CredentialInfo.class.getClassLoader());
+            }
+        }
+
+        public static final Parcelable.Creator<PerProviderSubscription> CREATOR = new Parcelable.Creator<PerProviderSubscription>() {
+            public PerProviderSubscription createFromParcel(Parcel in) {
+                return new PerProviderSubscription(in);
+            }
+
+            public PerProviderSubscription[] newArray(int size) {
+                return new PerProviderSubscription[size];
+            }
+        };
+
+    }
+
+    /**
+     * PerProviderSubscription/<X+>
+     * This interior node contains the Home SP information, subscription policy, management and credential information.
+     **/
+    public static class CredentialInfo implements Parcelable {
+        public String nodeName;
+        public Policy policy = new Policy();
+        public String credentialPriority;
+        public HashMap<String, AAAServerTrustRoot> aAAServerTrustRoot = new HashMap<String, AAAServerTrustRoot>();
+        public SubscriptionUpdate subscriptionUpdate = new SubscriptionUpdate();
+        public HomeSP homeSP = new HomeSP();
+        public SubscriptionParameters subscriptionParameters = new SubscriptionParameters();
+        public Credential credential = new Credential();
+        public Extension extension = new Extension();
+
+        public CredentialInfo(String nn) {
+            nodeName = nn;
+        }
+
+        public AAAServerTrustRoot createAAAServerTrustRoot(String name, String url, String fp) {
+            AAAServerTrustRoot obj = new AAAServerTrustRoot(name, url, fp);
+            aAAServerTrustRoot.put(name, obj);
+            return obj;
+        }
+
+        public CredentialInfo() {
+        }
+
+        public CredentialInfo(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(nodeName);
+            out.writeParcelable(policy, flags);
+            out.writeString(credentialPriority);
+            out.writeMap(aAAServerTrustRoot);
+            out.writeParcelable(subscriptionUpdate, flags);
+            out.writeParcelable(homeSP, flags);
+            out.writeParcelable(subscriptionParameters, flags);
+            out.writeParcelable(credential, flags);
+            //out.writeParcelable(extension, flags);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                nodeName = in.readString();
+                policy = in.readParcelable(Policy.class.getClassLoader());
+                credentialPriority = in.readString();
+                in.readMap(aAAServerTrustRoot, AAAServerTrustRoot.class.getClassLoader());
+                subscriptionUpdate = in.readParcelable(SubscriptionUpdate.class.getClassLoader());
+                homeSP = in.readParcelable(HomeSP.class.getClassLoader());
+                subscriptionParameters = in.readParcelable(SubscriptionParameters.class
+                        .getClassLoader());
+                credential = in.readParcelable(Credential.class.getClassLoader());
+                //extension = in.readParcelable(Extension.class.getClassLoader());
+            }
+        }
+
+        public static final Parcelable.Creator<CredentialInfo> CREATOR = new Parcelable.Creator<CredentialInfo>() {
+            public CredentialInfo createFromParcel(Parcel in) {
+                return new CredentialInfo(in);
+            }
+
+            public CredentialInfo[] newArray(int size) {
+                return new CredentialInfo[size];
+            }
+        };
+
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/Policy
+     **/
+    public static class Policy implements Parcelable {
+        public HashMap<String, PreferredRoamingPartnerList> preferredRoamingPartnerList = new HashMap<String, PreferredRoamingPartnerList>();
+        public HashMap<String, MinBackhaulThresholdNetwork> minBackhaulThreshold = new HashMap<String, MinBackhaulThresholdNetwork>();
+        public PolicyUpdate policyUpdate = new PolicyUpdate();
+        public HashMap<String, SPExclusionList> sPExclusionList = new HashMap<String, SPExclusionList>();
+        public HashMap<String, RequiredProtoPortTuple> requiredProtoPortTuple = new HashMap<String, RequiredProtoPortTuple>();
+        public String maximumBSSLoadValue;
+
+        public PreferredRoamingPartnerList createPreferredRoamingPartnerList(String name,
+                String fqdn, String priority, String country) {
+            PreferredRoamingPartnerList obj = new PreferredRoamingPartnerList(name, fqdn, priority,
+                    country);
+            preferredRoamingPartnerList.put(name, obj);
+            return obj;
+        }
+
+        public MinBackhaulThresholdNetwork createMinBackhaulThreshold(String name, String type,
+                String dl, String ul) {
+            MinBackhaulThresholdNetwork obj = new MinBackhaulThresholdNetwork(name, type, dl, ul);
+            minBackhaulThreshold.put(name, obj);
+            return obj;
+        }
+
+        public SPExclusionList createSPExclusionList(String name, String ssid) {
+            SPExclusionList obj = new SPExclusionList(name, ssid);
+            sPExclusionList.put(name, obj);
+            return obj;
+        }
+
+        public RequiredProtoPortTuple createRequiredProtoPortTuple(String name, String proto,
+                String port) {
+            RequiredProtoPortTuple obj = new RequiredProtoPortTuple(name, proto, port);
+            requiredProtoPortTuple.put(name, obj);
+            return obj;
+        }
+
+        public Policy() {
+        }
+
+        public Policy(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeMap(preferredRoamingPartnerList);
+            out.writeMap(minBackhaulThreshold);
+            out.writeParcelable(policyUpdate, flags);
+            out.writeMap(sPExclusionList);
+            out.writeMap(requiredProtoPortTuple);
+            out.writeString(maximumBSSLoadValue);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                in.readMap(preferredRoamingPartnerList,
+                        PreferredRoamingPartnerList.class.getClassLoader());
+                in.readMap(minBackhaulThreshold, MinBackhaulThresholdNetwork.class.getClassLoader());
+                policyUpdate = in.readParcelable(PolicyUpdate.class.getClassLoader());
+                in.readMap(sPExclusionList, SPExclusionList.class.getClassLoader());
+                in.readMap(requiredProtoPortTuple, RequiredProtoPortTuple.class.getClassLoader());
+                maximumBSSLoadValue = in.readString();
+
+            }
+        }
+
+        public static final Parcelable.Creator<Policy> CREATOR = new Parcelable.Creator<Policy>() {
+            public Policy createFromParcel(Parcel in) {
+                return new Policy(in);
+            }
+
+            public Policy[] newArray(int size) {
+                return new Policy[size];
+            }
+        };
+
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/Policy/PreferredRoamingPartnerList/<X+>
+     **/
+    public static class PreferredRoamingPartnerList implements Parcelable {
+        public String nodeName;
+        public String FQDN_Match; //maximum 255 + ",includeSubdomains", equals 273
+        public String Priority;
+        public String Country; // maximum 600 octets
+
+        public PreferredRoamingPartnerList(String nn, String f, String p, String c) {
+            nodeName = nn;
+            FQDN_Match = f;
+            Priority = p;
+            Country = c;
+        }
+
+        public PreferredRoamingPartnerList() {
+        }
+
+        public PreferredRoamingPartnerList(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(nodeName);
+            out.writeString(FQDN_Match);
+            out.writeString(Priority);
+            out.writeString(Country);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                nodeName = in.readString();
+                FQDN_Match = in.readString();
+                Priority = in.readString();
+                Country = in.readString();
+            }
+        }
+
+        public static final Parcelable.Creator<PreferredRoamingPartnerList> CREATOR = new Parcelable.Creator<PreferredRoamingPartnerList>() {
+            public PreferredRoamingPartnerList createFromParcel(Parcel in) {
+                return new PreferredRoamingPartnerList(in);
+            }
+
+            public PreferredRoamingPartnerList[] newArray(int size) {
+                return new PreferredRoamingPartnerList[size];
+            }
+        };
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/Policy/MinBackhaulThreshold
+     **/
+    public static class MinBackhaulThresholdNetwork implements Parcelable {
+        public String nodeName;
+        public String NetworkType;
+        public String DLBandwidth;
+        public String ULBandwidth;
+
+        public MinBackhaulThresholdNetwork(String nn, String nt, String d, String u) {
+            nodeName = nn;
+            NetworkType = nt;
+            DLBandwidth = d;
+            ULBandwidth = u;
+        }
+
+        public MinBackhaulThresholdNetwork() {
+        }
+
+        public MinBackhaulThresholdNetwork(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(nodeName);
+            out.writeString(NetworkType);
+            out.writeString(DLBandwidth);
+            out.writeString(ULBandwidth);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                nodeName = in.readString();
+                NetworkType = in.readString();
+                DLBandwidth = in.readString();
+                ULBandwidth = in.readString();
+            }
+        }
+
+        public static final Parcelable.Creator<MinBackhaulThresholdNetwork> CREATOR = new Parcelable.Creator<MinBackhaulThresholdNetwork>() {
+            public MinBackhaulThresholdNetwork createFromParcel(Parcel in) {
+                return new MinBackhaulThresholdNetwork(in);
+            }
+
+            public MinBackhaulThresholdNetwork[] newArray(int size) {
+                return new MinBackhaulThresholdNetwork[size];
+            }
+        };
+
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/Policy/PolicyUpdate
+     **/
+    public static class PolicyUpdate implements Parcelable {
+        public String UpdateInterval;
+        public String UpdateMethod;
+        public String Restriction;
+        public String URI;
+        public UsernamePassword usernamePassword = new UsernamePassword();
+        public String Other;
+        public TrustRoot trustRoot = new TrustRoot();
+
+        public PolicyUpdate() {
+        }
+
+        public PolicyUpdate(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(UpdateInterval);
+            out.writeString(UpdateMethod);
+            out.writeString(Restriction);
+            out.writeString(URI);
+            out.writeParcelable(usernamePassword, flags);
+            out.writeString(Other);
+            out.writeParcelable(trustRoot, flags);
+
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                UpdateInterval = in.readString();
+                UpdateMethod = in.readString();
+                Restriction = in.readString();
+                URI = in.readString();
+                usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
+                Other = in.readString();
+                trustRoot = in.readParcelable(TrustRoot.class.getClassLoader());
+            }
+        }
+
+        public static final Parcelable.Creator<PolicyUpdate> CREATOR = new Parcelable.Creator<PolicyUpdate>() {
+            public PolicyUpdate createFromParcel(Parcel in) {
+                return new PolicyUpdate(in);
+            }
+
+            public PolicyUpdate[] newArray(int size) {
+                return new PolicyUpdate[size];
+            }
+        };
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/Policy/SPExclusionList
+     **/
+    public static class SPExclusionList implements Parcelable {
+        public String nodeName;
+        public String SSID;
+
+        public SPExclusionList(String nn, String s) {
+            nodeName = nn;
+            SSID = s;
+        }
+
+        public SPExclusionList() {
+        }
+
+        public SPExclusionList(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(nodeName);
+            out.writeString(SSID);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                nodeName = in.readString();
+                SSID = in.readString();
+            }
+        }
+
+        public static final Parcelable.Creator<SPExclusionList> CREATOR = new Parcelable.Creator<SPExclusionList>() {
+            public SPExclusionList createFromParcel(Parcel in) {
+                return new SPExclusionList(in);
+            }
+
+            public SPExclusionList[] newArray(int size) {
+                return new SPExclusionList[size];
+            }
+        };
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/Policy/RequiredProtoPortTuple
+     **/
+    public static class RequiredProtoPortTuple implements Parcelable {
+        public String nodeName;
+        public String IPProtocol;
+        public String PortNumber;
+
+        public RequiredProtoPortTuple() {
+        }
+
+        public RequiredProtoPortTuple(String nn, String protocol, String port) {
+            nodeName = nn;
+            IPProtocol = protocol;
+            PortNumber = port;
+        }
+
+        public RequiredProtoPortTuple(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(nodeName);
+            out.writeString(IPProtocol);
+            out.writeString(PortNumber);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                nodeName = in.readString();
+                IPProtocol = in.readString();
+                PortNumber = in.readString();
+            }
+        }
+
+        public static final Parcelable.Creator<RequiredProtoPortTuple> CREATOR = new Parcelable.Creator<RequiredProtoPortTuple>() {
+            public RequiredProtoPortTuple createFromParcel(Parcel in) {
+                return new RequiredProtoPortTuple(in);
+            }
+
+            public RequiredProtoPortTuple[] newArray(int size) {
+                return new RequiredProtoPortTuple[size];
+            }
+        };
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/AAAServerTrustRoot
+     **/
+    public static class AAAServerTrustRoot implements Parcelable {
+        public String nodeName;
+        public String CertURL;
+        public String CertSHA256Fingerprint;
+
+        public AAAServerTrustRoot(String nn, String url, String fp) {
+            nodeName = nn;
+            CertURL = url;
+            CertSHA256Fingerprint = fp;
+        }
+
+        public AAAServerTrustRoot() {
+        }
+
+        public AAAServerTrustRoot(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(nodeName);
+            out.writeString(CertURL);
+            out.writeString(CertSHA256Fingerprint);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                nodeName = in.readString();
+                CertURL = in.readString();
+                CertSHA256Fingerprint = in.readString();
+            }
+        }
+
+        public static final Parcelable.Creator<AAAServerTrustRoot> CREATOR = new Parcelable.Creator<AAAServerTrustRoot>() {
+            public AAAServerTrustRoot createFromParcel(Parcel in) {
+                return new AAAServerTrustRoot(in);
+            }
+
+            public AAAServerTrustRoot[] newArray(int size) {
+                return new AAAServerTrustRoot[size];
+            }
+        };
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/SubscriptionUpdate
+     **/
+    public static class SubscriptionUpdate implements Parcelable {
+        public String UpdateInterval;
+        public String UpdateMethod;
+        public String Restriction;
+        public String URI;
+        public UsernamePassword usernamePassword = new UsernamePassword();
+        public String Other;
+        public TrustRoot trustRoot = new TrustRoot();
+
+        public SubscriptionUpdate() {
+        }
+
+        public SubscriptionUpdate(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(UpdateInterval);
+            out.writeString(UpdateMethod);
+            out.writeString(Restriction);
+            out.writeString(URI);
+            out.writeParcelable(usernamePassword, flags);
+            out.writeString(Other);
+            out.writeParcelable(trustRoot, flags);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                UpdateInterval = in.readString();
+                UpdateMethod = in.readString();
+                Restriction = in.readString();
+                URI = in.readString();
+                usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
+                Other = in.readString();
+                trustRoot = in.readParcelable(TrustRoot.class.getClassLoader());
+            }
+        }
+
+        public static final Parcelable.Creator<SubscriptionUpdate> CREATOR = new Parcelable.Creator<SubscriptionUpdate>() {
+            public SubscriptionUpdate createFromParcel(Parcel in) {
+                return new SubscriptionUpdate(in);
+            }
+
+            public SubscriptionUpdate[] newArray(int size) {
+                return new SubscriptionUpdate[size];
+            }
+        };
+
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/Policy/PolicyUpdate/TrustRoot
+     * PerProviderSubscription/<X+>/SubscriptionUpdate/TrustRoot
+     * PerProviderSubscription/<X+>/AAAServerTrustRoot/<X+>
+     **/
+    public static class TrustRoot implements Parcelable {
+        public String CertURL;
+        public String CertSHA256Fingerprint;
+
+        public TrustRoot() {
+        }
+
+        public TrustRoot(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(CertURL);
+            out.writeString(CertSHA256Fingerprint);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                CertURL = in.readString();
+                CertSHA256Fingerprint = in.readString();
+            }
+        }
+
+        public static final Parcelable.Creator<TrustRoot> CREATOR = new Parcelable.Creator<TrustRoot>() {
+            public TrustRoot createFromParcel(Parcel in) {
+                return new TrustRoot(in);
+            }
+
+            public TrustRoot[] newArray(int size) {
+                return new TrustRoot[size];
+            }
+        };
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/Policy/PolicyUpdate/UsernamePassword
+     * PerProviderSubscription/<X+>/SubscriptionUpdate/UsernamePassword
+     * PerProviderSubscription/<X+>/Credential/UsernamePassword
+     **/
+    public static class UsernamePassword implements Parcelable {
+        public String Username;
+        public String Password;
+        //following are Credential node used only
+        public boolean MachineManaged;
+        public String SoftTokenApp;
+        public String AbleToShare;
+        public EAPMethod eAPMethod = new EAPMethod();
+
+        public UsernamePassword() {
+        }
+
+        public UsernamePassword(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(Username);
+            out.writeString(Password);
+            out.writeInt(MachineManaged ? 1 : 0);
+            out.writeString(SoftTokenApp);
+            out.writeString(AbleToShare);
+            out.writeParcelable(eAPMethod, flags);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                Username = in.readString();
+                Password = in.readString();
+                MachineManaged = (in.readInt() == 1) ? true : false;
+                SoftTokenApp = in.readString();
+                AbleToShare = in.readString();
+                eAPMethod = in.readParcelable(EAPMethod.class.getClassLoader());
+            }
+        }
+
+        public static final Parcelable.Creator<UsernamePassword> CREATOR = new Parcelable.Creator<UsernamePassword>() {
+            public UsernamePassword createFromParcel(Parcel in) {
+                return new UsernamePassword(in);
+            }
+
+            public UsernamePassword[] newArray(int size) {
+                return new UsernamePassword[size];
+            }
+        };
+
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/Credential/UsernamePassword/EAPMethod
+     **/
+    public static class EAPMethod implements Parcelable {
+        public String EAPType;
+        public String VendorId;
+        public String VendorType;
+        public String InnerEAPType;
+        public String InnerVendorId;
+        public String InnerVendorType;
+        public String InnerMethod;
+
+        public EAPMethod() {
+        }
+
+        public EAPMethod(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(EAPType);
+            out.writeString(VendorId);
+            out.writeString(VendorType);
+            out.writeString(InnerEAPType);
+            out.writeString(InnerVendorId);
+            out.writeString(InnerVendorType);
+            out.writeString(InnerMethod);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                EAPType = in.readString();
+                VendorId = in.readString();
+                VendorType = in.readString();
+                InnerEAPType = in.readString();
+                InnerVendorId = in.readString();
+                InnerVendorType = in.readString();
+                InnerMethod = in.readString();
+            }
+        }
+
+        public static final Parcelable.Creator<EAPMethod> CREATOR = new Parcelable.Creator<EAPMethod>() {
+            public EAPMethod createFromParcel(Parcel in) {
+                return new EAPMethod(in);
+            }
+
+            public EAPMethod[] newArray(int size) {
+                return new EAPMethod[size];
+            }
+        };
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/HomeSP
+     **/
+    public static class HomeSP implements Parcelable {
+        public HashMap<String, NetworkID> networkID = new HashMap<String, NetworkID>();
+        public String FriendlyName;
+        public String IconURL;
+        public String FQDN;
+        public HashMap<String, HomeOIList> homeOIList = new HashMap<String, HomeOIList>();
+        public HashMap<String, OtherHomePartners> otherHomePartners = new HashMap<String, OtherHomePartners>();
+        public String RoamingConsortiumOI;
+
+        public NetworkID createNetworkID(String name, String ssid, String hessid) {
+            NetworkID obj = new NetworkID(name, ssid, hessid);
+            networkID.put(name, obj);
+            return obj;
+        }
+
+        public HomeOIList createHomeOIList(String name, String homeoi, boolean required) {
+            HomeOIList obj = new HomeOIList(name, homeoi, required);
+            homeOIList.put(name, obj);
+            return obj;
+        }
+
+        public OtherHomePartners createOtherHomePartners(String name, String fqdn) {
+            OtherHomePartners obj = new OtherHomePartners(name, fqdn);
+            otherHomePartners.put(name, obj);
+            return obj;
+        }
+
+        public HomeSP() {
+        }
+
+        public HomeSP(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeMap(networkID);
+            out.writeString(FriendlyName);
+            out.writeString(IconURL);
+            out.writeString(FQDN);
+            out.writeMap(homeOIList);
+            out.writeMap(otherHomePartners);
+            out.writeString(RoamingConsortiumOI);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                in.readMap(networkID, NetworkID.class.getClassLoader());
+                FriendlyName = in.readString();
+                IconURL = in.readString();
+                FQDN = in.readString();
+                in.readMap(homeOIList, HomeOIList.class.getClassLoader());
+                in.readMap(otherHomePartners, OtherHomePartners.class.getClassLoader());
+                RoamingConsortiumOI = in.readString();
+            }
+        }
+
+        public static final Parcelable.Creator<HomeSP> CREATOR = new Parcelable.Creator<HomeSP>() {
+            public HomeSP createFromParcel(Parcel in) {
+                return new HomeSP(in);
+            }
+
+            public HomeSP[] newArray(int size) {
+                return new HomeSP[size];
+            }
+        };
+
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/HomeSP/NetworkID
+     **/
+    public static class NetworkID implements Parcelable {
+        public String nodeName;
+        public String SSID;
+        public String HESSID;
+
+        public NetworkID(String nn, String s, String h) {
+            nodeName = nn;
+            SSID = s;
+            HESSID = h;
+        }
+
+        public NetworkID() {
+        }
+
+        public NetworkID(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(nodeName);
+            out.writeString(SSID);
+            out.writeString(HESSID);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                nodeName = in.readString();
+                SSID = in.readString();
+                HESSID = in.readString();
+            }
+        }
+
+        public static final Parcelable.Creator<NetworkID> CREATOR = new Parcelable.Creator<NetworkID>() {
+            public NetworkID createFromParcel(Parcel in) {
+                return new NetworkID(in);
+            }
+
+            public NetworkID[] newArray(int size) {
+                return new NetworkID[size];
+            }
+        };
+
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/HomeSP/HomeOIList
+     **/
+    public static class HomeOIList implements Parcelable {
+        public String nodeName;
+        public String HomeOI;
+        public boolean HomeOIRequired;
+
+        public HomeOIList(String nn, String h, boolean r) {
+            nodeName = nn;
+            HomeOI = h;
+            HomeOIRequired = r;
+        }
+
+        public HomeOIList() {
+        }
+
+        public HomeOIList(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(nodeName);
+            out.writeString(HomeOI);
+            out.writeInt(HomeOIRequired ? 1 : 0);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                nodeName = in.readString();
+                HomeOI = in.readString();
+                HomeOIRequired = (in.readInt() == 1) ? true : false;
+            }
+        }
+
+        public static final Parcelable.Creator<HomeOIList> CREATOR = new Parcelable.Creator<HomeOIList>() {
+            public HomeOIList createFromParcel(Parcel in) {
+                return new HomeOIList(in);
+            }
+
+            public HomeOIList[] newArray(int size) {
+                return new HomeOIList[size];
+            }
+        };
+
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/HomeSP/OtherHomePartners
+     **/
+    public static class OtherHomePartners implements Parcelable {
+        public String nodeName;
+        public String FQDN;
+
+        public OtherHomePartners(String nn, String f) {
+            nodeName = nn;
+            FQDN = f;
+        }
+
+        public OtherHomePartners() {
+        }
+
+        public OtherHomePartners(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(nodeName);
+            out.writeString(FQDN);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                nodeName = in.readString();
+                FQDN = in.readString();
+            }
+        }
+
+        public static final Parcelable.Creator<OtherHomePartners> CREATOR = new Parcelable.Creator<OtherHomePartners>() {
+            public OtherHomePartners createFromParcel(Parcel in) {
+                return new OtherHomePartners(in);
+            }
+
+            public OtherHomePartners[] newArray(int size) {
+                return new OtherHomePartners[size];
+            }
+        };
+
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/SubscriptionParameters
+     **/
+    public static class SubscriptionParameters implements Parcelable {
+        public String CreationDate;
+        public String ExpirationDate;
+        public String TypeOfSubscription;
+        public UsageLimits usageLimits = new UsageLimits();
+
+        public SubscriptionParameters() {
+        }
+
+        public SubscriptionParameters(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(CreationDate);
+            out.writeString(ExpirationDate);
+            out.writeString(TypeOfSubscription);
+            out.writeParcelable(usageLimits, flags);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                CreationDate = in.readString();
+                ExpirationDate = in.readString();
+                TypeOfSubscription = in.readString();
+                usageLimits = in.readParcelable(UsageLimits.class.getClassLoader());
+            }
+        }
+
+        public static final Parcelable.Creator<SubscriptionParameters> CREATOR = new Parcelable.Creator<SubscriptionParameters>() {
+            public SubscriptionParameters createFromParcel(Parcel in) {
+                return new SubscriptionParameters(in);
+            }
+
+            public SubscriptionParameters[] newArray(int size) {
+                return new SubscriptionParameters[size];
+            }
+        };
+
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/SubscriptionParameters/UsageLimits
+     **/
+    public static class UsageLimits implements Parcelable {
+        public String DataLimit;
+        public String StartDate;
+        public String TimeLimit;
+        public String UsageTimePeriod;
+
+        public UsageLimits() {
+        }
+
+        public UsageLimits(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(DataLimit);
+            out.writeString(StartDate);
+            out.writeString(TimeLimit);
+            out.writeString(UsageTimePeriod);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                DataLimit = in.readString();
+                StartDate = in.readString();
+                TimeLimit = in.readString();
+                UsageTimePeriod = in.readString();
+            }
+        }
+
+        public static final Parcelable.Creator<UsageLimits> CREATOR = new Parcelable.Creator<UsageLimits>() {
+            public UsageLimits createFromParcel(Parcel in) {
+                return new UsageLimits(in);
+            }
+
+            public UsageLimits[] newArray(int size) {
+                return new UsageLimits[size];
+            }
+        };
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/Credential
+     **/
+    public static class Credential implements Parcelable {
+        public String CreationDate;
+        public String ExpirationDate;
+        public UsernamePassword usernamePassword = new UsernamePassword();
+        public DigitalCertificate digitalCertificate = new DigitalCertificate();
+        public String Realm;
+        public boolean CheckAAAServerCertStatus;
+        public SIM sim = new SIM();
+
+        public Credential() {
+        }
+
+        public Credential(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(CreationDate);
+            out.writeString(ExpirationDate);
+            out.writeParcelable(usernamePassword, flags);
+            out.writeParcelable(digitalCertificate, flags);
+            out.writeString(Realm);
+            out.writeInt(CheckAAAServerCertStatus ? 1 : 0);
+            out.writeParcelable(sim, flags);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                CreationDate = in.readString();
+                ExpirationDate = in.readString();
+                usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
+                digitalCertificate = in.readParcelable(DigitalCertificate.class.getClassLoader());
+                Realm = in.readString();
+                CheckAAAServerCertStatus = (in.readInt() == 1) ? true : false;
+                sim = in.readParcelable(SIM.class.getClassLoader());
+            }
+        }
+
+        public static final Parcelable.Creator<Credential> CREATOR = new Parcelable.Creator<Credential>() {
+            public Credential createFromParcel(Parcel in) {
+                return new Credential(in);
+            }
+
+            public Credential[] newArray(int size) {
+                return new Credential[size];
+            }
+        };
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/Credential/DigitalCertificate
+     **/
+    public static class DigitalCertificate implements Parcelable {
+        public String CertificateType;
+        public String CertSHA256Fingerprint;
+
+        public DigitalCertificate() {
+        }
+
+        public DigitalCertificate(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(CertificateType);
+            out.writeString(CertSHA256Fingerprint);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                CertificateType = in.readString();
+                CertSHA256Fingerprint = in.readString();
+            }
+        }
+
+        public static final Parcelable.Creator<DigitalCertificate> CREATOR = new Parcelable.Creator<DigitalCertificate>() {
+            public DigitalCertificate createFromParcel(Parcel in) {
+                return new DigitalCertificate(in);
+            }
+
+            public DigitalCertificate[] newArray(int size) {
+                return new DigitalCertificate[size];
+            }
+        };
+
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/Credential/SIM
+     **/
+    public static class SIM implements Parcelable {
+        public String IMSI;
+        public String EAPType;
+
+        public SIM() {
+        }
+
+        public SIM(Parcel in) {
+            readFromParcel(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(IMSI);
+            out.writeString(EAPType);
+        }
+
+        public void readFromParcel(Parcel in) {
+            if (in == null) {
+                //log here
+            } else {
+                IMSI = in.readString();
+                EAPType = in.readString();
+            }
+        }
+
+        public static final Parcelable.Creator<SIM> CREATOR = new Parcelable.Creator<SIM>() {
+            public SIM createFromParcel(Parcel in) {
+                return new SIM(in);
+            }
+
+            public SIM[] newArray(int size) {
+                return new SIM[size];
+            }
+        };
+
+    }
+
+    /**
+     * PerProviderSubscription/<X+>/Extension
+     **/
+    public static class Extension {
+        public String empty;
+    }
+
+    public WifiPasspointDmTree() {
+    }
+
+    public WifiPasspointDmTree(Parcel in) {
+        readFromParcel(in);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeMap(spFqdn);
+    }
+
+    public void readFromParcel(Parcel in) {
+        if (in == null) {
+            //log here
+        } else {
+            in.readMap(spFqdn, SpFqdn.class.getClassLoader());
+        }
+    }
+
+    public static final Parcelable.Creator<WifiPasspointDmTree> CREATOR = new Parcelable.Creator<WifiPasspointDmTree>() {
+        public WifiPasspointDmTree createFromParcel(Parcel in) {
+            return new WifiPasspointDmTree(in);
+        }
+
+        public WifiPasspointDmTree[] newArray(int size) {
+            return new WifiPasspointDmTree[size];
+        }
+    };
+
+}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.aidl
new file mode 100644
index 0000000..27f23bc
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.passpoint;
+
+parcelable WifiPasspointInfo;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
new file mode 100644
index 0000000..33db3f5
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
@@ -0,0 +1,559 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.passpoint;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** @hide */
+public class WifiPasspointInfo implements Parcelable {
+
+    /** TODO doc */
+    public static final int ANQP_CAPABILITY = 1 << 0;
+
+    /** TODO doc */
+    public static final int VENUE_NAME = 1 << 1;
+
+    /** TODO doc */
+    public static final int NETWORK_AUTH_TYPE = 1 << 2;
+
+    /** TODO doc */
+    public static final int ROAMING_CONSORTIUM = 1 << 3;
+
+    /** TODO doc */
+    public static final int IP_ADDR_TYPE_AVAILABILITY = 1 << 4;
+
+    /** TODO doc */
+    public static final int NAI_REALM = 1 << 5;
+
+    /** TODO doc */
+    public static final int CELLULAR_NETWORK = 1 << 6;
+
+    /** TODO doc */
+    public static final int DOMAIN_NAME = 1 << 7;
+
+    /** TODO doc */
+    public static final int HOTSPOT_CAPABILITY = 1 << 8;
+
+    /** TODO doc */
+    public static final int OPERATOR_FRIENDLY_NAME = 1 << 9;
+
+    /** TODO doc */
+    public static final int WAN_METRICS = 1 << 10;
+
+    /** TODO doc */
+    public static final int CONNECTION_CAPABILITY = 1 << 11;
+
+    /** TODO doc */
+    public static final int OSU_PROVIDER = 1 << 12;
+
+    /** TODO doc */
+    public static final int PRESET_CRED_MATCH =
+            ANQP_CAPABILITY |
+                    HOTSPOT_CAPABILITY |
+                    NAI_REALM |
+                    CELLULAR_NETWORK |
+                    DOMAIN_NAME;
+
+    /** TODO doc */
+    public static final int PRESET_ALL =
+            ANQP_CAPABILITY |
+                    VENUE_NAME |
+                    NETWORK_AUTH_TYPE |
+                    ROAMING_CONSORTIUM |
+                    IP_ADDR_TYPE_AVAILABILITY |
+                    NAI_REALM |
+                    CELLULAR_NETWORK |
+                    DOMAIN_NAME |
+                    HOTSPOT_CAPABILITY |
+                    OPERATOR_FRIENDLY_NAME |
+                    WAN_METRICS |
+                    CONNECTION_CAPABILITY |
+                    OSU_PROVIDER;
+
+
+    public static class WanMetrics {
+        public static final int STATUS_RESERVED = 0;
+        public static final int STATUS_UP = 1;
+        public static final int STATUS_DOWN = 2;
+        public static final int STATUS_TEST = 3;
+
+        public int wanInfo;
+        public long downlinkSpeed;
+        public long uplinkSpeed;
+        public int downlinkLoad;
+        public int uplinkLoad;
+        public int lmd;
+
+        public int getLinkStatus() {
+            return wanInfo & 0x3;
+        }
+
+        public boolean getSymmetricLink() {
+            return (wanInfo & (1 << 2)) != 0;
+        }
+
+        public boolean getAtCapacity() {
+            return (wanInfo & (1 << 3)) != 0;
+        }
+
+        @Override
+        public String toString() {
+            return wanInfo + "," + downlinkSpeed + "," + uplinkSpeed + "," +
+                    downlinkLoad + "," + uplinkLoad + "," + lmd;
+        }
+    }
+
+    public static class IpProtoPort {
+        public static final int STATUS_CLOSED = 0;
+        public static final int STATUS_OPEN = 1;
+        public static final int STATUS_UNKNOWN = 2;
+
+        public int proto;
+        public int port;
+        public int status;
+
+        @Override
+        public String toString() {
+            return proto + "," + port + "," + status;
+        }
+    }
+
+    public static class NetworkAuthType {
+        public static final int TYPE_TERMS_AND_CONDITION = 0;
+        public static final int TYPE_ONLINE_ENROLLMENT = 1;
+        public static final int TYPE_HTTP_REDIRECTION = 2;
+        public static final int TYPE_DNS_REDIRECTION = 3;
+
+        public int type;
+        public String redirectUrl;
+
+        @Override
+        public String toString() {
+            return type + "," + redirectUrl;
+        }
+    }
+
+    public static class IpAddressType {
+        public static final int IPV6_NOT_AVAILABLE = 0;
+        public static final int IPV6_AVAILABLE = 1;
+        public static final int IPV6_UNKNOWN = 2;
+
+        public static final int IPV4_NOT_AVAILABLE = 0;
+        public static final int IPV4_PUBLIC = 1;
+        public static final int IPV4_PORT_RESTRICTED = 2;
+        public static final int IPV4_SINGLE_NAT = 3;
+        public static final int IPV4_DOUBLE_NAT = 4;
+        public static final int IPV4_PORT_RESTRICTED_SINGLE_NAT = 5;
+        public static final int IPV4_PORT_RESTRICTED_DOUBLE_NAT = 6;
+        public static final int IPV4_PORT_UNKNOWN = 7;
+
+        private static final int NULL_VALUE = -1;
+
+        public int availability;
+
+        public int getIpv6Availability() {
+            return availability & 0x3;
+        }
+
+        public int getIpv4Availability() {
+            return (availability & 0xFF) >> 2;
+        }
+
+        @Override
+        public String toString() {
+            return getIpv6Availability() + "," + getIpv4Availability();
+        }
+    }
+
+    public static class NaiRealm {
+        public static final int ENCODING_RFC4282 = 0;
+        public static final int ENCODING_UTF8 = 1;
+
+        public int encoding;
+        public String realm;
+
+        @Override
+        public String toString() {
+            return encoding + "," + realm;
+        }
+    }
+
+    public static class CellularNetwork {
+        public String mcc;
+        public String mnc;
+
+        @Override
+        public String toString() {
+            return mcc + "," + mnc;
+        }
+    }
+
+    /** BSSID */
+    public String bssid;
+
+    /** venue name */
+    public String venueName;
+
+    /** list of network authentication types */
+    public List<NetworkAuthType> networkAuthTypeList;
+
+    /** list of roaming consortium OIs */
+    public List<String> roamingConsortiumList;
+
+    /** IP address availability */
+    public IpAddressType ipAddrTypeAvailability;
+
+    /** list of NAI realm */
+    public List<NaiRealm> naiRealmList;
+
+    /** list of 3GPP cellular network */
+    public List<CellularNetwork> cellularNetworkList;
+
+    /** list of fully qualified domain name (FQDN) */
+    public List<String> domainNameList;
+
+    /** HS 2.0 operator friendly name */
+    public String operatorFriendlyName;
+
+    /** HS 2.0 wan metrics */
+    public WanMetrics wanMetrics;
+
+    /** list of HS 2.0 IP proto port */
+    public List<IpProtoPort> connectionCapabilityList;
+
+    /** list of HS 2.0 OSU providers */
+    public List<WifiPasspointOsuProvider> osuProviderList;
+
+    /**
+     * Convert mask to ANQP subtypes, for supplicant command use.
+     *
+     * @param mask The ANQP subtypes mask.
+     * @return String of ANQP subtypes, good for supplicant command use
+     * @hide
+     */
+    public static String toAnqpSubtypes(int mask) {
+        StringBuilder sb = new StringBuilder();
+        if ((mask & ANQP_CAPABILITY) != 0)
+            sb.append("257,");
+        if ((mask & VENUE_NAME) != 0)
+            sb.append("258,");
+        if ((mask & NETWORK_AUTH_TYPE) != 0)
+            sb.append("260,");
+        if ((mask & ROAMING_CONSORTIUM) != 0)
+            sb.append("261,");
+        if ((mask & IP_ADDR_TYPE_AVAILABILITY) != 0)
+            sb.append("262,");
+        if ((mask & NAI_REALM) != 0)
+            sb.append("263,");
+        if ((mask & CELLULAR_NETWORK) != 0)
+            sb.append("264,");
+        if ((mask & DOMAIN_NAME) != 0)
+            sb.append("268,");
+        if ((mask & HOTSPOT_CAPABILITY) != 0)
+            sb.append("hs20:2,");
+        if ((mask & OPERATOR_FRIENDLY_NAME) != 0)
+            sb.append("hs20:3,");
+        if ((mask & WAN_METRICS) != 0)
+            sb.append("hs20:4,");
+        if ((mask & CONNECTION_CAPABILITY) != 0)
+            sb.append("hs20:5,");
+        if ((mask & OSU_PROVIDER) != 0)
+            sb.append("hs20:8,");
+        if (sb.length() > 0)
+            sb.deleteCharAt(sb.length() - 1);
+        return sb.toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append("BSSID: ").append("(").append(bssid).append(")");
+
+        if (venueName != null)
+            sb.append(" venueName: ").append("(")
+              .append(venueName.replace("\n", "\\n")).append(")");
+
+        if (networkAuthTypeList != null) {
+            sb.append(" networkAuthType: ");
+            for (NetworkAuthType auth : networkAuthTypeList)
+                sb.append("(").append(auth.toString()).append(")");
+        }
+
+        if (roamingConsortiumList != null) {
+            sb.append(" roamingConsortium: ");
+            for (String oi : roamingConsortiumList)
+                sb.append("(").append(oi).append(")");
+        }
+
+        if (ipAddrTypeAvailability != null) {
+            sb.append(" ipAddrTypeAvaibility: ").append("(")
+              .append(ipAddrTypeAvailability.toString()).append(")");
+        }
+
+        if (naiRealmList != null) {
+            sb.append(" naiRealm: ");
+            for (NaiRealm realm : naiRealmList)
+                sb.append("(").append(realm.toString()).append(")");
+        }
+
+        if (cellularNetworkList != null) {
+            sb.append(" cellularNetwork: ");
+            for (CellularNetwork plmn : cellularNetworkList)
+                sb.append("(").append(plmn.toString()).append(")");
+        }
+
+        if (domainNameList != null) {
+            sb.append(" domainName: ");
+            for (String fqdn : domainNameList)
+                sb.append("(").append(fqdn).append(")");
+        }
+
+        if (operatorFriendlyName != null)
+            sb.append(" operatorFriendlyName: ").append("(")
+              .append(operatorFriendlyName).append(")");
+
+        if (wanMetrics != null)
+            sb.append(" wanMetrics: ").append("(")
+              .append(wanMetrics.toString()).append(")");
+
+        if (connectionCapabilityList != null) {
+            sb.append(" connectionCapability: ");
+            for (IpProtoPort ip : connectionCapabilityList)
+                sb.append("(").append(ip.toString()).append(")");
+        }
+
+        if (osuProviderList != null) {
+            sb.append(" osuProviderList: ");
+            for (WifiPasspointOsuProvider osu : osuProviderList)
+                sb.append("(").append(osu.toString()).append(")");
+        }
+
+        return sb.toString();
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(bssid);
+        out.writeString(venueName);
+
+        if (networkAuthTypeList == null) {
+            out.writeInt(0);
+        } else {
+            out.writeInt(networkAuthTypeList.size());
+            for (NetworkAuthType auth : networkAuthTypeList) {
+                out.writeInt(auth.type);
+                out.writeString(auth.redirectUrl);
+            }
+        }
+
+        if (roamingConsortiumList == null) {
+            out.writeInt(0);
+        } else {
+            out.writeInt(roamingConsortiumList.size());
+            for (String oi : roamingConsortiumList)
+                out.writeString(oi);
+        }
+
+        if (ipAddrTypeAvailability == null) {
+            out.writeInt(IpAddressType.NULL_VALUE);
+        } else {
+            out.writeInt(ipAddrTypeAvailability.availability);
+        }
+
+        if (naiRealmList == null) {
+            out.writeInt(0);
+        } else {
+            out.writeInt(naiRealmList.size());
+            for (NaiRealm realm : naiRealmList) {
+                out.writeInt(realm.encoding);
+                out.writeString(realm.realm);
+            }
+        }
+
+        if (cellularNetworkList == null) {
+            out.writeInt(0);
+        } else {
+            out.writeInt(cellularNetworkList.size());
+            for (CellularNetwork plmn : cellularNetworkList) {
+                out.writeString(plmn.mcc);
+                out.writeString(plmn.mnc);
+            }
+        }
+
+
+        if (domainNameList == null) {
+            out.writeInt(0);
+        } else {
+            out.writeInt(domainNameList.size());
+            for (String fqdn : domainNameList)
+                out.writeString(fqdn);
+        }
+
+        out.writeString(operatorFriendlyName);
+
+        if (wanMetrics == null) {
+            out.writeInt(0);
+        } else {
+            out.writeInt(1);
+            out.writeInt(wanMetrics.wanInfo);
+            out.writeLong(wanMetrics.downlinkSpeed);
+            out.writeLong(wanMetrics.uplinkSpeed);
+            out.writeInt(wanMetrics.downlinkLoad);
+            out.writeInt(wanMetrics.uplinkLoad);
+            out.writeInt(wanMetrics.lmd);
+        }
+
+        if (connectionCapabilityList == null) {
+            out.writeInt(0);
+        } else {
+            out.writeInt(connectionCapabilityList.size());
+            for (IpProtoPort ip : connectionCapabilityList) {
+                out.writeInt(ip.proto);
+                out.writeInt(ip.port);
+                out.writeInt(ip.status);
+            }
+        }
+
+        if (osuProviderList == null) {
+            out.writeInt(0);
+        } else {
+            out.writeInt(osuProviderList.size());
+            for (WifiPasspointOsuProvider osu : osuProviderList)
+                osu.writeToParcel(out, flags);
+        }
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public static final Parcelable.Creator<WifiPasspointInfo> CREATOR =
+            new Parcelable.Creator<WifiPasspointInfo>() {
+                @Override
+                public WifiPasspointInfo createFromParcel(Parcel in) {
+                    WifiPasspointInfo p = new WifiPasspointInfo();
+                    int n;
+
+                    p.bssid = in.readString();
+                    p.venueName = in.readString();
+
+                    n = in.readInt();
+                    if (n > 0) {
+                        p.networkAuthTypeList = new ArrayList<NetworkAuthType>();
+                        for (int i = 0; i < n; i++) {
+                            NetworkAuthType auth = new NetworkAuthType();
+                            auth.type = in.readInt();
+                            auth.redirectUrl = in.readString();
+                            p.networkAuthTypeList.add(auth);
+                        }
+                    }
+
+                    n = in.readInt();
+                    if (n > 0) {
+                        p.roamingConsortiumList = new ArrayList<String>();
+                        for (int i = 0; i < n; i++)
+                            p.roamingConsortiumList.add(in.readString());
+                    }
+
+                    n = in.readInt();
+                    if (n != IpAddressType.NULL_VALUE) {
+                        p.ipAddrTypeAvailability = new IpAddressType();
+                        p.ipAddrTypeAvailability.availability = n;
+                    }
+
+                    n = in.readInt();
+                    if (n > 0) {
+                        p.naiRealmList = new ArrayList<NaiRealm>();
+                        for (int i = 0; i < n; i++) {
+                            NaiRealm realm = new NaiRealm();
+                            realm.encoding = in.readInt();
+                            realm.realm = in.readString();
+                            p.naiRealmList.add(realm);
+                        }
+                    }
+
+                    n = in.readInt();
+                    if (n > 0) {
+                        p.cellularNetworkList = new ArrayList<CellularNetwork>();
+                        for (int i = 0; i < n; i++) {
+                            CellularNetwork plmn = new CellularNetwork();
+                            plmn.mcc = in.readString();
+                            plmn.mnc = in.readString();
+                            p.cellularNetworkList.add(plmn);
+                        }
+                    }
+
+                    n = in.readInt();
+                    if (n > 0) {
+                        p.domainNameList = new ArrayList<String>();
+                        for (int i = 0; i < n; i++)
+                            p.domainNameList.add(in.readString());
+                    }
+
+                    p.operatorFriendlyName = in.readString();
+
+                    n = in.readInt();
+                    if (n > 0) {
+                        p.wanMetrics = new WanMetrics();
+                        p.wanMetrics.wanInfo = in.readInt();
+                        p.wanMetrics.downlinkSpeed = in.readLong();
+                        p.wanMetrics.uplinkSpeed = in.readLong();
+                        p.wanMetrics.downlinkLoad = in.readInt();
+                        p.wanMetrics.uplinkLoad = in.readInt();
+                        p.wanMetrics.lmd = in.readInt();
+                    }
+
+                    n = in.readInt();
+                    if (n > 0) {
+                        p.connectionCapabilityList = new ArrayList<IpProtoPort>();
+                        for (int i = 0; i < n; i++) {
+                            IpProtoPort ip = new IpProtoPort();
+                            ip.proto = in.readInt();
+                            ip.port = in.readInt();
+                            ip.status = in.readInt();
+                            p.connectionCapabilityList.add(ip);
+                        }
+                    }
+
+                    n = in.readInt();
+                    if (n > 0) {
+                        p.osuProviderList = new ArrayList<WifiPasspointOsuProvider>();
+                        for (int i = 0; i < n; i++) {
+                            WifiPasspointOsuProvider osu = WifiPasspointOsuProvider.CREATOR
+                                    .createFromParcel(in);
+                            p.osuProviderList.add(osu);
+                        }
+                    }
+
+                    return p;
+                }
+
+                @Override
+                public WifiPasspointInfo[] newArray(int size) {
+                    return new WifiPasspointInfo[size];
+                }
+            };
+}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
new file mode 100644
index 0000000..b9b17eb
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
@@ -0,0 +1,567 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.passpoint;
+
+import android.content.Context;
+import android.net.wifi.ScanResult;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Provides APIs for managing Wifi Passpoint credentials.
+ * @hide
+ */
+public class WifiPasspointManager {
+
+    private static final String TAG = "PasspointManager";
+
+    private static final boolean DBG = true;
+
+    /* Passpoint states values */
+
+    /** Passpoint is in an unknown state. This should only occur in boot time */
+    public static final int PASSPOINT_STATE_UNKNOWN = 0;
+
+    /** Passpoint is disabled. This occurs when wifi is disabled */
+    public static final int PASSPOINT_STATE_DISABLED = 1;
+
+    /** Passpoint is enabled and in discovery state */
+    public static final int PASSPOINT_STATE_DISCOVERY = 2;
+
+    /** Passpoint is enabled and in access state */
+    public static final int PASSPOINT_STATE_ACCESS = 3;
+
+    /** Passpoint is enabled and in provisioning state */
+    public static final int PASSPOINT_STATE_PROVISION = 4;
+
+    /* Passpoint callback error codes */
+
+    /** Indicates that the operation failed due to an internal error */
+    public static final int REASON_ERROR = 0;
+
+    /** Indicates that the operation failed because wifi is disabled */
+    public static final int REASON_WIFI_DISABLED = 1;
+
+    /** Indicates that the operation failed because the framework is busy */
+    public static final int REASON_BUSY = 2;
+
+    /** Indicates that the operation failed because parameter is invalid */
+    public static final int REASON_INVALID_PARAMETER = 3;
+
+    /** Indicates that the operation failed because the server is not trusted */
+    public static final int REASON_NOT_TRUSTED = 4;
+
+    /**
+     * protocol supported for Passpoint
+     */
+    public static final String PROTOCOL_DM = "OMA-DM-ClientInitiated";
+
+    /**
+     * protocol supported for Passpoint
+     */
+    public static final String PROTOCOL_SOAP = "SPP-ClientInitiated";
+
+    /* Passpoint broadcasts */
+
+    /**
+     * Broadcast intent action indicating that the state of Passpoint
+     * connectivity has changed
+     */
+    public static final String PASSPOINT_STATE_CHANGED_ACTION =
+            "android.net.wifi.passpoint.STATE_CHANGE";
+
+    /**
+     * Broadcast intent action indicating that the saved Passpoint credential
+     * list has changed
+     */
+    public static final String PASSPOINT_CRED_CHANGED_ACTION =
+            "android.net.wifi.passpoint.CRED_CHANGE";
+
+    /**
+     * Broadcast intent action indicating that Passpoint online sign up is
+     * avaiable.
+     */
+    public static final String PASSPOINT_OSU_AVAILABLE_ACTION =
+            "android.net.wifi.passpoint.OSU_AVAILABLE";
+
+    /**
+     * Broadcast intent action indicating that user remediation is required
+     */
+    public static final String PASSPOINT_USER_REM_REQ_ACTION =
+            "android.net.wifi.passpoint.USER_REM_REQ";
+
+    /**
+     * Interface for callback invocation when framework channel is lost
+     */
+    public interface ChannelListener {
+        /**
+         * The channel to the framework has been disconnected. Application could
+         * try re-initializing using {@link #initialize}
+         */
+        public void onChannelDisconnected();
+    }
+
+    /**
+     * Interface for callback invocation on an application action
+     */
+    public interface ActionListener {
+        /** The operation succeeded */
+        public void onSuccess();
+
+        /**
+         * The operation failed
+         *
+         * @param reason The reason for failure could be one of
+         *            {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
+         */
+        public void onFailure(int reason);
+    }
+
+    /**
+     * Interface for callback invocation when doing OSU or user remediation
+     */
+    public interface OsuRemListener {
+        /** The operation succeeded */
+        public void onSuccess();
+
+        /**
+         * The operation failed
+         *
+         * @param reason The reason for failure could be one of
+         *            {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
+         */
+        public void onFailure(int reason);
+
+        /**
+         * Browser launch is requried for user interaction. When this callback
+         * is called, app should launch browser / webview to the given URI.
+         *
+         * @param uri URI for browser launch
+         */
+        public void onBrowserLaunch(String uri);
+
+        /**
+         * When this is called, app should dismiss the previously lanched browser.
+         */
+        public void onBrowserDismiss();
+    }
+
+    /**
+     * A channel that connects the application to the wifi passpoint framework.
+     * Most passpoint operations require a Channel as an argument.
+     * An instance of Channel is obtained by doing a call on {@link #initialize}
+     */
+    public static class Channel {
+        private final static int INVALID_LISTENER_KEY = 0;
+
+        private ChannelListener mChannelListener;
+
+        private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
+        private HashMap<Integer, Integer> mListenerMapCount = new HashMap<Integer, Integer>();
+        private Object mListenerMapLock = new Object();
+        private int mListenerKey = 0;
+
+        private List<ScanResult> mAnqpRequest = new LinkedList<ScanResult>();
+        private Object mAnqpRequestLock = new Object();
+
+        private AsyncChannel mAsyncChannel;
+        private PasspointHandler mHandler;
+        Context mContext;
+
+        Channel(Context context, Looper looper, ChannelListener l) {
+            mAsyncChannel = new AsyncChannel();
+            mHandler = new PasspointHandler(looper);
+            mChannelListener = l;
+            mContext = context;
+        }
+
+        private int putListener(Object listener) {
+            return putListener(listener, 1);
+        }
+
+        private int putListener(Object listener, int count) {
+            if (listener == null || count <= 0)
+                return INVALID_LISTENER_KEY;
+            int key;
+            synchronized (mListenerMapLock) {
+                do {
+                    key = mListenerKey++;
+                } while (key == INVALID_LISTENER_KEY);
+                mListenerMap.put(key, listener);
+                mListenerMapCount.put(key, count);
+            }
+            return key;
+        }
+
+        private Object peekListener(int key) {
+            Log.d(TAG, "peekListener() key=" + key);
+            if (key == INVALID_LISTENER_KEY)
+                return null;
+            synchronized (mListenerMapLock) {
+                return mListenerMap.get(key);
+            }
+        }
+
+
+        private Object getListener(int key, boolean forceRemove) {
+            Log.d(TAG, "getListener() key=" + key + " force=" + forceRemove);
+            if (key == INVALID_LISTENER_KEY)
+                return null;
+            synchronized (mListenerMapLock) {
+                if (!forceRemove) {
+                    int count = mListenerMapCount.get(key);
+                    Log.d(TAG, "count=" + count);
+                    mListenerMapCount.put(key, --count);
+                    if (count > 0)
+                        return null;
+                }
+                Log.d(TAG, "remove key");
+                mListenerMapCount.remove(key);
+                return mListenerMap.remove(key);
+            }
+        }
+
+        private void anqpRequestStart(ScanResult sr) {
+            Log.d(TAG, "anqpRequestStart sr.bssid=" + sr.BSSID);
+            synchronized (mAnqpRequestLock) {
+                mAnqpRequest.add(sr);
+            }
+        }
+
+        private void anqpRequestFinish(WifiPasspointInfo result) {
+            Log.d(TAG, "anqpRequestFinish pi.bssid=" + result.bssid);
+            synchronized (mAnqpRequestLock) {
+                for (ScanResult sr : mAnqpRequest)
+                    if (sr.BSSID.equals(result.bssid)) {
+                        Log.d(TAG, "find hit " + result.bssid);
+                        sr.passpoint = result;
+                        mAnqpRequest.remove(sr);
+                        Log.d(TAG, "mAnqpRequest.len=" + mAnqpRequest.size());
+                        break;
+                    }
+            }
+        }
+
+        private void anqpRequestFinish(ScanResult sr) {
+            Log.d(TAG, "anqpRequestFinish sr.bssid=" + sr.BSSID);
+            synchronized (mAnqpRequestLock) {
+                for (ScanResult sr1 : mAnqpRequest)
+                    if (sr1.BSSID.equals(sr.BSSID)) {
+                        mAnqpRequest.remove(sr1);
+                        break;
+                    }
+            }
+        }
+
+        class PasspointHandler extends Handler {
+            PasspointHandler(Looper looper) {
+                super(looper);
+            }
+
+            @Override
+            public void handleMessage(Message message) {
+                Object listener = null;
+
+                switch (message.what) {
+                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+                        if (mChannelListener != null) {
+                            mChannelListener.onChannelDisconnected();
+                            mChannelListener = null;
+                        }
+                        break;
+
+                    case REQUEST_ANQP_INFO_SUCCEEDED:
+                        WifiPasspointInfo result = (WifiPasspointInfo) message.obj;
+                        anqpRequestFinish(result);
+                        listener = getListener(message.arg2, false);
+                        if (listener != null) {
+                            ((ActionListener) listener).onSuccess();
+                        }
+                        break;
+
+                    case REQUEST_ANQP_INFO_FAILED:
+                        anqpRequestFinish((ScanResult) message.obj);
+                        listener = getListener(message.arg2, false);
+                        if (listener == null)
+                            getListener(message.arg2, true);
+                        if (listener != null) {
+                            ((ActionListener) listener).onFailure(message.arg1);
+                        }
+                        break;
+
+                    case START_OSU_SUCCEEDED:
+                        listener = getListener(message.arg2, true);
+                        if (listener != null) {
+                            ((OsuRemListener) listener).onSuccess();
+                        }
+                        break;
+
+                    case START_OSU_FAILED:
+                        listener = getListener(message.arg2, true);
+                        if (listener != null) {
+                            ((OsuRemListener) listener).onFailure(message.arg1);
+                        }
+                        break;
+
+                    case START_OSU_BROWSER:
+                        listener = peekListener(message.arg2);
+                        if (listener != null) {
+                            ParcelableString str = (ParcelableString) message.obj;
+                            if (str == null || str.string == null)
+                                ((OsuRemListener) listener).onBrowserDismiss();
+                            else
+                                ((OsuRemListener) listener).onBrowserLaunch(str.string);
+                        }
+                        break;
+
+                    default:
+                        Log.d(TAG, "Ignored " + message);
+                        break;
+                }
+            }
+        }
+
+    }
+
+    public static class ParcelableString implements Parcelable {
+        public String string;
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(string);
+        }
+
+        public static final Parcelable.Creator<ParcelableString> CREATOR =
+                new Parcelable.Creator<ParcelableString>() {
+                    @Override
+                    public ParcelableString createFromParcel(Parcel in) {
+                        ParcelableString ret = new ParcelableString();
+                        ret.string = in.readString();
+                        return ret;
+                    }
+                    @Override
+                    public ParcelableString[] newArray(int size) {
+                        return new ParcelableString[size];
+                    }
+        };
+    }
+
+    private static final int BASE = Protocol.BASE_WIFI_PASSPOINT_MANAGER;
+
+    public static final int REQUEST_ANQP_INFO                   = BASE + 1;
+    public static final int REQUEST_ANQP_INFO_FAILED            = BASE + 2;
+    public static final int REQUEST_ANQP_INFO_SUCCEEDED         = BASE + 3;
+    public static final int REQUEST_OSU_ICON                    = BASE + 4;
+    public static final int REQUEST_OSU_ICON_FAILED             = BASE + 5;
+    public static final int REQUEST_OSU_ICON_SUCCEEDED          = BASE + 6;
+    public static final int START_OSU                           = BASE + 7;
+    public static final int START_OSU_BROWSER                   = BASE + 8;
+    public static final int START_OSU_FAILED                    = BASE + 9;
+    public static final int START_OSU_SUCCEEDED                 = BASE + 10;
+
+    private Context mContext;
+    IWifiPasspointManager mService;
+
+    /**
+     * TODO: doc
+     * @param context
+     * @param service
+     */
+    public WifiPasspointManager(Context context, IWifiPasspointManager service) {
+        mContext = context;
+        mService = service;
+    }
+
+    /**
+     * Registers the application with the framework. This function must be the
+     * first to be called before any async passpoint operations are performed.
+     *
+     * @param srcContext is the context of the source
+     * @param srcLooper is the Looper on which the callbacks are receivied
+     * @param listener for callback at loss of framework communication. Can be
+     *            null.
+     * @return Channel instance that is necessary for performing any further
+     *         passpoint operations
+     *
+     */
+    public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
+        Messenger messenger = getMessenger();
+        if (messenger == null)
+            return null;
+
+        Channel c = new Channel(srcContext, srcLooper, listener);
+        if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
+                == AsyncChannel.STATUS_SUCCESSFUL) {
+            return c;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * STOPSHIP: temp solution, should use supplicant manager instead, check
+     * with b/13931972
+     */
+    public Messenger getMessenger() {
+        try {
+            return mService.getMessenger();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    public int getPasspointState() {
+        try {
+            return mService.getPasspointState();
+        } catch (RemoteException e) {
+            return PASSPOINT_STATE_UNKNOWN;
+        }
+    }
+
+    public void requestAnqpInfo(Channel c, List<ScanResult> requested, int mask,
+            ActionListener listener) {
+        Log.d(TAG, "requestAnqpInfo start");
+        Log.d(TAG, "requested.size=" + requested.size());
+        checkChannel(c);
+        List<ScanResult> list = new ArrayList<ScanResult>();
+        for (ScanResult sr : requested)
+            if (sr.capabilities.contains("[HS20]")) {
+                list.add(sr);
+                c.anqpRequestStart(sr);
+                Log.d(TAG, "adding " + sr.BSSID);
+            }
+        int count = list.size();
+        Log.d(TAG, "after filter, count=" + count);
+        if (count == 0) {
+            if (DBG)
+                Log.d(TAG, "ANQP info request contains no HS20 APs, skipped");
+            listener.onSuccess();
+            return;
+        }
+        int key = c.putListener(listener, count);
+        for (ScanResult sr : list)
+            c.mAsyncChannel.sendMessage(REQUEST_ANQP_INFO, mask, key, sr);
+        Log.d(TAG, "requestAnqpInfo end");
+    }
+
+    public void requestOsuIcons(Channel c, List<WifiPasspointOsuProvider> requested,
+            int resolution, ActionListener listener) {
+    }
+
+    public List<WifiPasspointPolicy> requestCredentialMatch(List<ScanResult> requested) {
+        try {
+            return mService.requestCredentialMatch(requested);
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Get a list of saved Passpoint credentials. Only those credentials owned
+     * by the caller will be returned.
+     *
+     * @return The list of credentials
+     */
+    public List<WifiPasspointCredential> getCredentials() {
+        try {
+            return mService.getCredentials();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Add a new Passpoint credential.
+     *
+     * @param cred The credential to be added
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
+    public boolean addCredential(WifiPasspointCredential cred) {
+        try {
+            return mService.addCredential(cred);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Update an existing Passpoint credential. Only system or the owner of this
+     * credential has the permission to do this.
+     *
+     * @param cred The credential to be updated
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
+    public boolean updateCredential(WifiPasspointCredential cred) {
+        try {
+            return mService.updateCredential(cred);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Remove an existing Passpoint credential. Only system or the owner of this
+     * credential has the permission to do this.
+     *
+     * @param cred The credential to be removed
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
+    public boolean removeCredential(WifiPasspointCredential cred) {
+        try {
+            return mService.removeCredential(cred);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    public void startOsu(Channel c, WifiPasspointOsuProvider osu, OsuRemListener listener) {
+        Log.d(TAG, "startOsu start");
+        checkChannel(c);
+        int key = c.putListener(listener);
+        c.mAsyncChannel.sendMessage(START_OSU, 0, key, osu);
+        Log.d(TAG, "startOsu end");
+    }
+
+    public void startRemediation(Channel c, OsuRemListener listener) {
+    }
+
+    public void connect(WifiPasspointPolicy policy) {
+    }
+
+    private static void checkChannel(Channel c) {
+        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+    }
+}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.aidl
new file mode 100644
index 0000000..088136f
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.passpoint;
+
+parcelable WifiPasspointOsuProvider;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
new file mode 100644
index 0000000..b54b70c
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.passpoint;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class WifiPasspointOsuProvider implements Parcelable {
+
+    /** TODO: doc
+     * @hide
+     */
+    public static final int OSU_METHOD_UNKNOWN = -1;
+
+    /** TODO: doc
+     * @hide
+     */
+    public static final int OSU_METHOD_OMADM = 0;
+
+    /** TODO: doc
+     * @hide
+     */
+    public static final int OSU_METHOD_SOAP = 1;
+
+    /** TODO: doc */
+    public String ssid;
+
+    /** TODO: doc */
+    public String friendlyName;
+
+    /** TODO: doc
+     * @hide
+     */
+    public String serverUri;
+
+    /** TODO: doc
+     * @hide
+     */
+    public int osuMethod = OSU_METHOD_UNKNOWN;
+
+    /** TODO: doc */
+    public int iconWidth;
+
+    /** TODO: doc */
+    public int iconHeight;
+
+    /** TODO: doc */
+    public String iconType;
+
+    /** TODO: doc */
+    public String iconFileName;
+
+    /** TODO: doc */
+    public Object icon; // TODO: should change to image format
+
+    /** TODO: doc */
+    public String osuNai;
+
+    /** TODO: doc */
+    public String osuService;
+
+    /** default constructor @hide */
+    public WifiPasspointOsuProvider() {
+        // TODO
+    }
+
+    /** copy constructor @hide */
+    public WifiPasspointOsuProvider(WifiPasspointOsuProvider source) {
+        // TODO
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("SSID: ").append("<").append(ssid).append(">");
+        if (friendlyName != null)
+            sb.append(" friendlyName: ").append("<").append(friendlyName).append(">");
+        if (serverUri != null)
+            sb.append(" serverUri: ").append("<").append(serverUri).append(">");
+        sb.append(" osuMethod: ").append("<").append(osuMethod).append(">");
+        if (iconFileName != null) {
+            sb.append(" icon: <").append(iconWidth).append("x")
+                    .append(iconHeight).append(" ")
+                    .append(iconType).append(" ")
+                    .append(iconFileName).append(">");
+        }
+        if (osuNai != null)
+            sb.append(" osuNai: ").append("<").append(osuNai).append(">");
+        if (osuService != null)
+            sb.append(" osuService: ").append("<").append(osuService).append(">");
+        return sb.toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(ssid);
+        out.writeString(friendlyName);
+        out.writeString(serverUri);
+        out.writeInt(osuMethod);
+        out.writeInt(iconWidth);
+        out.writeInt(iconHeight);
+        out.writeString(iconType);
+        out.writeString(iconFileName);
+        out.writeString(osuNai);
+        out.writeString(osuService);
+        // TODO: icon image?
+    }
+
+    public static final Parcelable.Creator<WifiPasspointOsuProvider> CREATOR =
+            new Parcelable.Creator<WifiPasspointOsuProvider>() {
+                @Override
+                public WifiPasspointOsuProvider createFromParcel(Parcel in) {
+                    WifiPasspointOsuProvider osu = new WifiPasspointOsuProvider();
+                    osu.ssid = in.readString();
+                    osu.friendlyName = in.readString();
+                    osu.serverUri = in.readString();
+                    osu.osuMethod = in.readInt();
+                    osu.iconWidth = in.readInt();
+                    osu.iconHeight = in.readInt();
+                    osu.iconType = in.readString();
+                    osu.iconFileName = in.readString();
+                    osu.osuNai = in.readString();
+                    osu.osuService = in.readString();
+                    return osu;
+                }
+
+                @Override
+                public WifiPasspointOsuProvider[] newArray(int size) {
+                    return new WifiPasspointOsuProvider[size];
+                }
+            };
+}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.aidl
new file mode 100644
index 0000000..1d61da0
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.passpoint;
+
+parcelable WifiPasspointPolicy;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
new file mode 100644
index 0000000..f84ac88
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.passpoint;
+
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.ScanResult;
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.security.Credentials;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+
+
+/** @hide */
+public class WifiPasspointPolicy implements Parcelable {
+
+    private final static String TAG = "PasspointPolicy";
+
+    /** @hide */
+    public static final int HOME_SP = 0;
+
+    /** @hide */
+    public static final int ROAMING_PARTNER = 1;
+
+    /** @hide */
+    public static final int UNRESTRICTED = 2;
+
+    private String mName;
+    private int mCredentialPriority;
+    private int mRoamingPriority;
+    private String mBssid;
+    private String mSsid;
+    private WifiPasspointCredential mCredential;
+    private int mRestriction;// Permitted values are "HomeSP", "RoamingPartner", or "Unrestricted"
+    private boolean mIsHomeSp;
+
+    private final String INT_PRIVATE_KEY = "private_key";
+    private final String INT_PHASE2 = "phase2";
+    private final String INT_PASSWORD = "password";
+    private final String INT_IDENTITY = "identity";
+    private final String INT_EAP = "eap";
+    private final String INT_CLIENT_CERT = "client_cert";
+    private final String INT_CA_CERT = "ca_cert";
+    private final String INT_ANONYMOUS_IDENTITY = "anonymous_identity";
+    private final String INT_SIM_SLOT = "sim_slot";
+    private final String INT_ENTERPRISEFIELD_NAME ="android.net.wifi.WifiConfiguration$EnterpriseField";
+    private final String ISO8601DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+    private final String ENTERPRISE_PHASE2_MSCHAPV2 = "auth=MSCHAPV2";
+    private final String ENTERPRISE_PHASE2_MSCHAP = "auth=MSCHAP";
+
+    /** @hide */
+    public WifiPasspointPolicy(String name, String ssid,
+            String bssid, WifiPasspointCredential pc,
+            int restriction, boolean ishomesp) {
+        mName = name;
+        if (pc != null) {
+            mCredentialPriority = pc.getPriority();
+        }
+        //PerProviderSubscription/<X+>/Policy/PreferredRoamingPartnerList/<X+>/Priority
+        mRoamingPriority = 128; //default priority value of 128
+        mSsid = ssid;
+        mCredential = pc;
+        mBssid = bssid;
+        mRestriction = restriction;
+        mIsHomeSp = ishomesp;
+    }
+
+    public String getSsid() {
+        return mSsid;
+    }
+
+    /** @hide */
+    public void setBssid(String bssid) {
+        mBssid = bssid;
+    }
+
+    public String getBssid() {
+        return mBssid;
+    }
+
+    /** @hide */
+    public void setRestriction(int r) {
+        mRestriction = r;
+    }
+
+    /** @hide */
+    public int getRestriction() {
+        return mRestriction;
+    }
+
+    /** @hide */
+    public void setHomeSp(boolean b) {
+        mIsHomeSp = b;
+    }
+
+    /** @hide */
+    public boolean isHomeSp() {
+        return mIsHomeSp;
+    }
+
+    /** @hide */
+    public void setCredential(WifiPasspointCredential newCredential) {
+        mCredential = newCredential;
+    }
+
+    public WifiPasspointCredential getCredential() {
+        // TODO: return a copy
+        return mCredential;
+    }
+
+    /** @hide */
+    public void setCredentialPriority(int priority) {
+        mCredentialPriority = priority;
+    }
+
+    /** @hide */
+    public void setRoamingPriority(int priority) {
+        mRoamingPriority = priority;
+    }
+
+    public int getCredentialPriority() {
+        return mCredentialPriority;
+    }
+
+    public int getRoamingPriority() {
+        return mRoamingPriority;
+    }
+
+    public WifiConfiguration createWifiConfiguration() {
+        WifiConfiguration wfg = new WifiConfiguration();
+        if (mBssid != null) {
+            Log.d(TAG, "create bssid:" + mBssid);
+            wfg.BSSID = mBssid;
+        }
+
+        if (mSsid != null) {
+            Log.d(TAG, "create ssid:" + mSsid);
+            wfg.SSID = mSsid;
+        }
+        //TODO: 1. add pmf configuration
+        //      2. add ocsp configuration
+        //      3. add eap-sim configuration
+        /*Key management*/
+        wfg.status = WifiConfiguration.Status.ENABLED;
+        wfg.allowedKeyManagement.clear();
+        wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+        wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+
+        /*Group Ciphers*/
+        wfg.allowedGroupCiphers.clear();
+        wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+        wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
+
+        /*Protocols*/
+        wfg.allowedProtocols.clear();
+        wfg.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+        wfg.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
+
+        Class[] enterpriseFieldArray  = WifiConfiguration.class.getClasses();
+        Class<?> enterpriseFieldClass = null;
+
+
+        for(Class<?> myClass : enterpriseFieldArray) {
+            if(myClass.getName().equals(INT_ENTERPRISEFIELD_NAME)) {
+                enterpriseFieldClass = myClass;
+                break;
+            }
+        }
+        Log.d(TAG, "class chosen " + enterpriseFieldClass.getName() );
+
+
+        Field anonymousId = null, caCert = null, clientCert = null,
+              eap = null, identity = null, password = null,
+              phase2 = null, privateKey =  null;
+
+        Field[] fields = WifiConfiguration.class.getFields();
+
+
+        for (Field tempField : fields) {
+            if (tempField.getName().trim().equals(INT_ANONYMOUS_IDENTITY)) {
+                anonymousId = tempField;
+                Log.d(TAG, "field " + anonymousId.getName() );
+            } else if (tempField.getName().trim().equals(INT_CA_CERT)) {
+                caCert = tempField;
+            } else if (tempField.getName().trim().equals(INT_CLIENT_CERT)) {
+                clientCert = tempField;
+                Log.d(TAG, "field " + clientCert.getName() );
+            } else if (tempField.getName().trim().equals(INT_EAP)) {
+                eap = tempField;
+                Log.d(TAG, "field " + eap.getName() );
+            } else if (tempField.getName().trim().equals(INT_IDENTITY)) {
+                identity = tempField;
+                Log.d(TAG, "field " + identity.getName() );
+            } else if (tempField.getName().trim().equals(INT_PASSWORD)) {
+                password = tempField;
+                Log.d(TAG, "field " + password.getName() );
+            } else if (tempField.getName().trim().equals(INT_PHASE2)) {
+                phase2 = tempField;
+                Log.d(TAG, "field " + phase2.getName() );
+
+            } else if (tempField.getName().trim().equals(INT_PRIVATE_KEY)) {
+                privateKey = tempField;
+            }
+        }
+
+
+        Method setValue = null;
+
+        for(Method m: enterpriseFieldClass.getMethods()) {
+            if(m.getName().trim().equals("setValue")) {
+                Log.d(TAG, "method " + m.getName() );
+                setValue = m;
+                break;
+            }
+        }
+
+        try {
+            // EAP
+            String eapmethod = mCredential.getType();
+            Log.d(TAG, "eapmethod:" + eapmethod);
+            setValue.invoke(eap.get(wfg), eapmethod);
+
+            // Username, password, EAP Phase 2
+            if ("TTLS".equals(eapmethod)) {
+                setValue.invoke(phase2.get(wfg), ENTERPRISE_PHASE2_MSCHAPV2);
+                setValue.invoke(identity.get(wfg), mCredential.getUserName());
+                setValue.invoke(password.get(wfg), mCredential.getPassword());
+                setValue.invoke(anonymousId.get(wfg), "anonymous@" + mCredential.getRealm());
+            }
+
+            // EAP CA Certificate
+            String cacertificate = null;
+            String rootCA = mCredential.getCaRootCertPath();
+            if (rootCA == null){
+                cacertificate = null;
+            } else {
+                cacertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.CA_CERTIFICATE + rootCA;
+            }
+            Log.d(TAG, "cacertificate:" + cacertificate);
+            setValue.invoke(caCert.get(wfg), cacertificate);
+
+            //User certificate
+            if ("TLS".equals(eapmethod)) {
+                String usercertificate = null;
+                String privatekey = null;
+                String clientCertPath = mCredential.getClientCertPath();
+                if (clientCertPath != null){
+                    privatekey = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_PRIVATE_KEY + clientCertPath;
+                    usercertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_CERTIFICATE + clientCertPath;
+                }
+                Log.d(TAG, "privatekey:" + privatekey);
+                Log.d(TAG, "usercertificate:" + usercertificate);
+                if (privatekey != null && usercertificate != null) {
+                    setValue.invoke(privateKey.get(wfg), privatekey);
+                    setValue.invoke(clientCert.get(wfg), usercertificate);
+                }
+            }
+        } catch (Exception e) {
+            Log.d(TAG, "createWifiConfiguration err:" + e);
+        }
+
+        return wfg;
+    }
+
+    /** {@inheritDoc} @hide */
+    public int compareTo(WifiPasspointPolicy another) {
+        Log.d(TAG, "this:" + this);
+        Log.d(TAG, "another:" + another);
+
+        if (another == null) {
+            return -1;
+        } else if (this.mIsHomeSp == true && another.isHomeSp() == false) {
+            //home sp priority is higher then roaming
+            Log.d(TAG, "compare HomeSP  first, this is HomeSP, another isn't");
+            return -1;
+        } else if ((this.mIsHomeSp == true && another.isHomeSp() == true)) {
+            Log.d(TAG, "both HomeSP");
+            //if both home sp, compare credential priority
+            if (this.mCredentialPriority < another.getCredentialPriority()) {
+                Log.d(TAG, "this priority is higher");
+                return -1;
+            } else if (this.mCredentialPriority == another.getCredentialPriority()) {
+                Log.d(TAG, "both priorities equal");
+                //if priority still the same, compare name(ssid)
+                if (this.mName.compareTo(another.mName) != 0) {
+                    Log.d(TAG, "compare mName return:" + this.mName.compareTo(another.mName));
+                    return this.mName.compareTo(another.mName);
+                }
+                /**
+                 *if name still the same, compare credential
+                 *the device may has two more credentials(TLS,SIM..etc)
+                 *it can associate to one AP(same ssid). so we should compare by credential
+                 */
+                if (this.mCredential != null && another.mCredential != null) {
+                    if (this.mCredential.compareTo(another.mCredential) != 0) {
+                        Log.d(TAG,
+                                "compare mCredential return:" + this.mName.compareTo(another.mName));
+                        return this.mCredential.compareTo(another.mCredential);
+                    }
+                }
+            } else {
+                return 1;
+            }
+        } else if ((this.mIsHomeSp == false && another.isHomeSp() == false)) {
+            Log.d(TAG, "both RoamingSp");
+            //if both roaming sp, compare roaming priority(preferredRoamingPartnerList/<X+>/priority)
+            if (this.mRoamingPriority < another.getRoamingPriority()) {
+                Log.d(TAG, "this priority is higher");
+                return -1;
+            } else if (this.mRoamingPriority == another.getRoamingPriority()) {//priority equals, compare name
+                Log.d(TAG, "both priorities equal");
+                //if priority still the same, compare name(ssid)
+                if (this.mName.compareTo(another.mName) != 0) {
+                    Log.d(TAG, "compare mName return:" + this.mName.compareTo(another.mName));
+                    return this.mName.compareTo(another.mName);
+                }
+                //if name still the same, compare credential
+                if (this.mCredential != null && another.mCredential != null) {
+                    if (this.mCredential.compareTo(another.mCredential) != 0) {
+                        Log.d(TAG,
+                                "compare mCredential return:"
+                                        + this.mCredential.compareTo(another.mCredential));
+                        return this.mCredential.compareTo(another.mCredential);
+                    }
+                }
+            } else {
+                return 1;
+            }
+        }
+
+        Log.d(TAG, "both policies equal");
+        return 0;
+    }
+
+    @Override
+    /** @hide */
+    public String toString() {
+        return "PasspointPolicy: name=" + mName + " CredentialPriority=" + mCredentialPriority +
+                " mRoamingPriority" + mRoamingPriority +
+                " ssid=" + mSsid + " restriction=" + mRestriction +
+                " ishomesp=" + mIsHomeSp + " Credential=" + mCredential;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        // TODO
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public static final Creator<WifiPasspointPolicy> CREATOR =
+            new Creator<WifiPasspointPolicy>() {
+                @Override
+                public WifiPasspointPolicy createFromParcel(Parcel in) {
+                    return null;
+                }
+
+                @Override
+                public WifiPasspointPolicy[] newArray(int size) {
+                    return new WifiPasspointPolicy[size];
+                }
+            };
+}