Merge "Use the new refined DexOptNeeded codes."
diff --git a/api/current.txt b/api/current.txt
index 21ff787..f736bc0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -37222,6 +37222,7 @@
     method public int getCallState();
     method public android.telephony.CellLocation getCellLocation();
     method public int getDataActivity();
+    method public boolean getDataEnabled();
     method public int getDataNetworkType();
     method public int getDataState();
     method public java.lang.String getDeviceId();
@@ -37266,6 +37267,7 @@
     method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
+    method public void setDataEnabled(boolean);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
     method public boolean setPreferredNetworkTypeToGlobal();
@@ -37273,6 +37275,7 @@
     field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
     field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
+    field public static final java.lang.String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
     field public static final int APPTYPE_CSIM = 4; // 0x4
     field public static final int APPTYPE_ISIM = 5; // 0x5
     field public static final int APPTYPE_RUIM = 3; // 0x3
@@ -37292,11 +37295,15 @@
     field public static final int DATA_CONNECTING = 1; // 0x1
     field public static final int DATA_DISCONNECTED = 0; // 0x0
     field public static final int DATA_SUSPENDED = 3; // 0x3
+    field public static final java.lang.String EXTRA_CALL_VOICEMAIL_INTENT = "android.telephony.extra.CALL_VOICEMAIL_INTENT";
     field public static final java.lang.String EXTRA_INCOMING_NUMBER = "incoming_number";
+    field public static final java.lang.String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
+    field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT";
     field public static final java.lang.String EXTRA_STATE = "state";
     field public static final java.lang.String EXTRA_STATE_IDLE;
     field public static final java.lang.String EXTRA_STATE_OFFHOOK;
     field public static final java.lang.String EXTRA_STATE_RINGING;
+    field public static final java.lang.String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
     field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
     field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
     field public static final int NETWORK_TYPE_EDGE = 2; // 0x2
diff --git a/api/test-current.txt b/api/test-current.txt
index 5301443..4af0615 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -37299,6 +37299,7 @@
     method public int getCallState();
     method public android.telephony.CellLocation getCellLocation();
     method public int getDataActivity();
+    method public boolean getDataEnabled();
     method public int getDataNetworkType();
     method public int getDataState();
     method public java.lang.String getDeviceId();
@@ -37343,6 +37344,7 @@
     method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
+    method public void setDataEnabled(boolean);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
     method public boolean setPreferredNetworkTypeToGlobal();
@@ -37350,6 +37352,7 @@
     field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
     field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
+    field public static final java.lang.String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
     field public static final int APPTYPE_CSIM = 4; // 0x4
     field public static final int APPTYPE_ISIM = 5; // 0x5
     field public static final int APPTYPE_RUIM = 3; // 0x3
@@ -37369,11 +37372,15 @@
     field public static final int DATA_CONNECTING = 1; // 0x1
     field public static final int DATA_DISCONNECTED = 0; // 0x0
     field public static final int DATA_SUSPENDED = 3; // 0x3
+    field public static final java.lang.String EXTRA_CALL_VOICEMAIL_INTENT = "android.telephony.extra.CALL_VOICEMAIL_INTENT";
     field public static final java.lang.String EXTRA_INCOMING_NUMBER = "incoming_number";
+    field public static final java.lang.String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
+    field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT";
     field public static final java.lang.String EXTRA_STATE = "state";
     field public static final java.lang.String EXTRA_STATE_IDLE;
     field public static final java.lang.String EXTRA_STATE_OFFHOOK;
     field public static final java.lang.String EXTRA_STATE_RINGING;
+    field public static final java.lang.String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
     field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
     field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
     field public static final int NETWORK_TYPE_EDGE = 2; // 0x2
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index 6a73829..ef2db4a 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -16,17 +16,19 @@
 
 package android.app;
 
+import android.os.Build;
 import android.os.Trace;
 import android.util.ArrayMap;
 import com.android.internal.os.PathClassLoaderFactory;
 import dalvik.system.PathClassLoader;
 
-class ApplicationLoaders {
+/** @hide */
+public class ApplicationLoaders {
     public static ApplicationLoaders getDefault() {
         return gApplicationLoaders;
     }
 
-    public ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
+    ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
                                       String librarySearchPath, String libraryPermittedPath,
                                       ClassLoader parent) {
         /*
@@ -80,6 +82,19 @@
         }
     }
 
+    /**
+     * Creates a classloader for the WebView APK and places it in the cache of loaders maintained
+     * by this class. This is used in the WebView zygote, where its presence in the cache speeds up
+     * startup and enables memory sharing.
+     */
+    public ClassLoader createAndCacheWebViewClassLoader(String packagePath, String libsPath) {
+      // The correct paths are calculated by WebViewZygote in the system server and passed to
+      // us here. We hardcode the other parameters: WebView always targets the current SDK,
+      // does not need to use non-public system libraries, and uses the base classloader as its
+      // parent to permit usage of the cache.
+      return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null);
+    }
+
     private static native void setupVulkanLayerPath(ClassLoader classLoader, String librarySearchPath);
 
     /**
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index b889c8f..8824c981 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -339,39 +339,43 @@
          * concatenation of both apps' shared library lists.
          */
 
-        String instrumentationPackageName = activityThread.mInstrumentationPackageName;
-        String instrumentationAppDir = activityThread.mInstrumentationAppDir;
-        String[] instrumentationSplitAppDirs = activityThread.mInstrumentationSplitAppDirs;
-        String instrumentationLibDir = activityThread.mInstrumentationLibDir;
-
-        String instrumentedAppDir = activityThread.mInstrumentedAppDir;
-        String[] instrumentedSplitAppDirs = activityThread.mInstrumentedSplitAppDirs;
-        String instrumentedLibDir = activityThread.mInstrumentedLibDir;
         String[] instrumentationLibs = null;
+        // activityThread will be null when called from the WebView zygote; just assume
+        // no instrumentation applies in this case.
+        if (activityThread != null) {
+            String instrumentationPackageName = activityThread.mInstrumentationPackageName;
+            String instrumentationAppDir = activityThread.mInstrumentationAppDir;
+            String[] instrumentationSplitAppDirs = activityThread.mInstrumentationSplitAppDirs;
+            String instrumentationLibDir = activityThread.mInstrumentationLibDir;
 
-        if (appDir.equals(instrumentationAppDir)
-                || appDir.equals(instrumentedAppDir)) {
-            outZipPaths.clear();
-            outZipPaths.add(instrumentationAppDir);
-            if (instrumentationSplitAppDirs != null) {
-                Collections.addAll(outZipPaths, instrumentationSplitAppDirs);
-            }
-            if (!instrumentationAppDir.equals(instrumentedAppDir)) {
-                outZipPaths.add(instrumentedAppDir);
-                if (instrumentedSplitAppDirs != null) {
-                    Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
+            String instrumentedAppDir = activityThread.mInstrumentedAppDir;
+            String[] instrumentedSplitAppDirs = activityThread.mInstrumentedSplitAppDirs;
+            String instrumentedLibDir = activityThread.mInstrumentedLibDir;
+
+            if (appDir.equals(instrumentationAppDir)
+                    || appDir.equals(instrumentedAppDir)) {
+                outZipPaths.clear();
+                outZipPaths.add(instrumentationAppDir);
+                if (instrumentationSplitAppDirs != null) {
+                    Collections.addAll(outZipPaths, instrumentationSplitAppDirs);
                 }
-            }
-
-            if (outLibPaths != null) {
-                outLibPaths.add(instrumentationLibDir);
-                if (!instrumentationLibDir.equals(instrumentedLibDir)) {
-                    outLibPaths.add(instrumentedLibDir);
+                if (!instrumentationAppDir.equals(instrumentedAppDir)) {
+                    outZipPaths.add(instrumentedAppDir);
+                    if (instrumentedSplitAppDirs != null) {
+                        Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
+                    }
                 }
-            }
 
-            if (!instrumentedAppDir.equals(instrumentationAppDir)) {
-                instrumentationLibs = getLibrariesFor(instrumentationPackageName);
+                if (outLibPaths != null) {
+                    outLibPaths.add(instrumentationLibDir);
+                    if (!instrumentationLibDir.equals(instrumentedLibDir)) {
+                        outLibPaths.add(instrumentedLibDir);
+                    }
+                }
+
+                if (!instrumentedAppDir.equals(instrumentationAppDir)) {
+                    instrumentationLibs = getLibrariesFor(instrumentationPackageName);
+                }
             }
         }
 
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 5d27662..94d03e5 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -235,6 +235,7 @@
         // >=0: registered and advertising started
         private int mAdvertiserId;
         private boolean mIsAdvertising = false;
+        private int registrationError = AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR;
 
         public AdvertiseCallbackWrapper(AdvertiseCallback advertiseCallback,
                 AdvertiseData advertiseData, AdvertiseData scanResponse,
@@ -262,12 +263,11 @@
                     mLeAdvertisers.put(mAdvertiseCallback, this);
                 } else if (mAdvertiserId < 0) {
 
-                    // Registration timeout, reset mClientIf to -1 so no subsequent operations can
+                    // Registration timeout, reset mClientIf to -2 so no subsequent operations can
                     // proceed.
-                    if (mAdvertiserId == 0) mAdvertiserId = -2;
+                    if (mAdvertiserId == -1) mAdvertiserId = -2;
                     // Post internal error if registration failed.
-                    postStartFailure(mAdvertiseCallback,
-                            AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
+                    postStartFailure(mAdvertiseCallback, registrationError);
                 } else {
                     // Unregister application if it's already registered but advertise failed.
                     try {
@@ -318,6 +318,8 @@
                     } catch (RemoteException e) {
                         Log.e(TAG, "failed to start advertising", e);
                     }
+                } else if (status == AdvertiseCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS) {
+                    registrationError = status;
                 }
                 // Registration failed.
                 mAdvertiserId = -2;
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 1ac9fca..e7436be 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -108,6 +108,26 @@
      */
     public static final int TAG_SYSTEM_RESTORE = 0xFFFFFF04;
 
+    /** @hide */
+    public static final int TAG_SYSTEM_DHCP = 0xFFFFFF05;
+    /** @hide */
+    public static final int TAG_SYSTEM_NTP = 0xFFFFFF06;
+    /** @hide */
+    public static final int TAG_SYSTEM_PROBE = 0xFFFFFF07;
+    /** @hide */
+    public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFF08;
+    /** @hide */
+    public static final int TAG_SYSTEM_GPS = 0xFFFFFF09;
+    /** @hide */
+    public static final int TAG_SYSTEM_PAC = 0xFFFFFF0A;
+
+    /**
+     * Sockets that are strictly local on device; never hits network.
+     *
+     * @hide
+     */
+    public static final int TAG_SYSTEM_LOCAL = 0xFFFFFFAA;
+
     private static INetworkStatsService sStatsService;
 
     private synchronized static INetworkStatsService getStatsService() {
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index ea8ba2f..50a3f4c 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -129,6 +129,17 @@
         return sTransactionTracker;
     }
 
+    /** @hide */
+    public static IBinder allowBlocking(IBinder binder) {
+        // NOTE: real implementation on internal branch
+        return binder;
+    }
+
+    /** @hide */
+    public static void copyAllowBlocking(IBinder fromBinder, IBinder toBinder) {
+        // NOTE: real implementation on internal branch
+    }
+
     /* mObject is used by native code, do not remove or rename */
     private long mObject;
     private IInterface mOwner;
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index 1479035..e47c238 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -39,6 +39,7 @@
     private static native boolean native_get_boolean(String key, boolean def);
     private static native void native_set(String key, String def);
     private static native void native_add_change_callback();
+    private static native void native_report_sysprop_change();
 
     /**
      * Get the value for the given key.
@@ -151,4 +152,11 @@
             }
         }
     }
+
+    /*
+     * Notifies listeners that a system property has changed
+     */
+    public static void reportSyspropChanged() {
+        native_report_sysprop_change();
+    }
 }
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index f41a838..f1e8fc2d 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -56,7 +56,9 @@
 @SystemApi
 public final class WebViewFactory {
 
-    private static final String CHROMIUM_WEBVIEW_FACTORY =
+    // visible for WebViewZygoteInit to look up the class by reflection and call preloadInZygote.
+    /** @hide */
+    public static final String CHROMIUM_WEBVIEW_FACTORY =
             "com.android.webview.chromium.WebViewChromiumFactoryProvider";
 
     private static final String NULL_WEBVIEW_FACTORY =
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index bc6e7b4..c206974 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -16,14 +16,19 @@
 
 package android.webkit;
 
+import android.app.LoadedApk;
 import android.content.pm.PackageInfo;
 import android.os.Build;
 import android.os.SystemService;
 import android.os.ZygoteProcess;
+import android.text.TextUtils;
 import android.util.Log;
 
+import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.concurrent.TimeoutException;
 
 /** @hide */
@@ -122,11 +127,21 @@
         try {
             sZygote = new ZygoteProcess("webview_zygote", null);
 
-            String packagePath = sPackage.applicationInfo.sourceDir;
-            String libsPath = sPackage.applicationInfo.nativeLibraryDir;
+            // All the work below is usually done by LoadedApk, but the zygote can't talk to
+            // PackageManager or construct a LoadedApk since it's single-threaded pre-fork, so
+            // doesn't have an ActivityThread and can't use Binder.
+            // Instead, figure out the paths here, in the system server where we have access to
+            // the package manager. Reuse the logic from LoadedApk to determine the correct
+            // paths and pass them to the zygote as strings.
+            final List<String> zipPaths = new ArrayList<>(10);
+            final List<String> libPaths = new ArrayList<>(10);
+            LoadedApk.makePaths(null, sPackage.applicationInfo, zipPaths, libPaths);
+            final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
+            final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
+                    TextUtils.join(File.pathSeparator, zipPaths);
 
-            Log.d(LOGTAG, "Preloading package " + packagePath + " " + libsPath);
-            sZygote.preloadPackageForAbi(packagePath, libsPath, Build.SUPPORTED_ABIS[0]);
+            Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
+            sZygote.preloadPackageForAbi(zip, librarySearchPath, Build.SUPPORTED_ABIS[0]);
         } catch (Exception e) {
             Log.e(LOGTAG, "Error connecting to " + serviceName, e);
             sZygote = null;
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index 11dd0e8..d968e3c 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -16,14 +16,17 @@
 
 package com.android.internal.os;
 
+import android.app.ApplicationLoaders;
 import android.net.LocalSocket;
 import android.os.Build;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.text.TextUtils;
 import android.util.Log;
+import android.webkit.WebViewFactory;
 
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
 
 /**
  * Startup class for the WebView zygote process.
@@ -52,7 +55,27 @@
 
         @Override
         protected boolean handlePreloadPackage(String packagePath, String libsPath) {
-            // TODO: Use preload information to setup the ClassLoader.
+            // Ask ApplicationLoaders to create and cache a classloader for the WebView APK so that
+            // our children will reuse the same classloader instead of creating their own.
+            // This enables us to preload Java and native code in the webview zygote process and
+            // have the preloaded versions actually be used post-fork.
+            ClassLoader loader = ApplicationLoaders.getDefault().createAndCacheWebViewClassLoader(
+                    packagePath, libsPath);
+
+            // Once we have the classloader, look up the WebViewFactoryProvider implementation and
+            // call preloadInZygote() on it to give it the opportunity to preload the native library
+            // and perform any other initialisation work that should be shared among the children.
+            try {
+                Class providerClass = Class.forName(WebViewFactory.CHROMIUM_WEBVIEW_FACTORY, true,
+                                                    loader);
+                Object result = providerClass.getMethod("preloadInZygote").invoke(null);
+                if (!((Boolean)result).booleanValue()) {
+                    Log.e(TAG, "preloadInZygote returned false");
+                }
+            } catch (ClassNotFoundException | NoSuchMethodException | SecurityException |
+                     IllegalAccessException | InvocationTargetException e) {
+                Log.e(TAG, "Exception while preloading package", e);
+            }
             return false;
         }
     }
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index 5dace6b..8844fb0 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -220,6 +220,11 @@
     }
 }
 
+static void SystemProperties_report_sysprop_change(JNIEnv /**env*/, jobject /*clazz*/)
+{
+    report_sysprop_change();
+}
+
 static const JNINativeMethod method_table[] = {
     { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
       (void*) SystemProperties_getS },
@@ -235,6 +240,8 @@
       (void*) SystemProperties_set },
     { "native_add_change_callback", "()V",
       (void*) SystemProperties_add_change_callback },
+    { "native_report_sysprop_change", "()V",
+      (void*) SystemProperties_report_sysprop_change },
 };
 
 int register_android_os_SystemProperties(JNIEnv *env)
diff --git a/media/mca/filterfw/jni/jni_gl_environment.cpp b/media/mca/filterfw/jni/jni_gl_environment.cpp
index 096120e..823e88a 100644
--- a/media/mca/filterfw/jni/jni_gl_environment.cpp
+++ b/media/mca/filterfw/jni/jni_gl_environment.cpp
@@ -63,7 +63,8 @@
 };
 
 jboolean Java_android_filterfw_core_GLEnvironment_nativeAllocate(JNIEnv* env, jobject thiz) {
-  return ToJBool(WrapObjectInJava(new GLEnv(), env, thiz, true));
+  std::unique_ptr<GLEnv> glEnv(new GLEnv());
+  return ToJBool(WrapOwnedObjectInJava(std::move(glEnv), env, thiz, true));
 }
 
 jboolean Java_android_filterfw_core_GLEnvironment_nativeDeallocate(JNIEnv* env, jobject thiz) {
diff --git a/media/mca/filterfw/jni/jni_gl_frame.cpp b/media/mca/filterfw/jni/jni_gl_frame.cpp
index b55bc5d..27b4cd2 100644
--- a/media/mca/filterfw/jni/jni_gl_frame.cpp
+++ b/media/mca/filterfw/jni/jni_gl_frame.cpp
@@ -48,13 +48,11 @@
                                                            jint height) {
   GLEnv* gl_env_ptr = ConvertFromJava<GLEnv>(env, gl_env);
   if (!gl_env_ptr) return JNI_FALSE;
-  GLFrame* frame = new GLFrame(gl_env_ptr);
+  std::unique_ptr<GLFrame> frame(new GLFrame(gl_env_ptr));
   if (frame->Init(width, height)) {
-    return ToJBool(WrapObjectInJava(frame, env, thiz, true));
-  } else {
-    delete frame;
-    return JNI_FALSE;
+    return ToJBool(WrapOwnedObjectInJava(std::move(frame), env, thiz, true));
   }
+  return JNI_FALSE;
 }
 
 jboolean Java_android_filterfw_core_GLFrame_nativeAllocateWithTexture(JNIEnv* env,
@@ -65,13 +63,11 @@
                                                                       jint height) {
   GLEnv* gl_env_ptr = ConvertFromJava<GLEnv>(env, gl_env);
   if (!gl_env_ptr) return JNI_FALSE;
-  GLFrame* frame = new GLFrame(gl_env_ptr);
+  std::unique_ptr<GLFrame> frame(new GLFrame(gl_env_ptr));
   if (frame->InitWithTexture(tex_id, width, height)) {
-    return ToJBool(WrapObjectInJava(frame, env, thiz, true));
-  } else {
-    delete frame;
-    return JNI_FALSE;
+    return ToJBool(WrapOwnedObjectInJava(std::move(frame), env, thiz, true));
   }
+  return JNI_FALSE;
 }
 
 jboolean Java_android_filterfw_core_GLFrame_nativeAllocateWithFbo(JNIEnv* env,
@@ -82,13 +78,11 @@
                                                                   jint height) {
   GLEnv* gl_env_ptr = ConvertFromJava<GLEnv>(env, gl_env);
   if (!gl_env_ptr) return JNI_FALSE;
-  GLFrame* frame = new GLFrame(gl_env_ptr);
+  std::unique_ptr<GLFrame> frame(new GLFrame(gl_env_ptr));
   if (frame->InitWithFbo(fbo_id, width, height)) {
-    return ToJBool(WrapObjectInJava(frame, env, thiz, true));
-  } else {
-    delete frame;
-    return JNI_FALSE;
+    return ToJBool(WrapOwnedObjectInJava(std::move(frame), env, thiz, true));
   }
+  return JNI_FALSE;
 }
 
 jboolean Java_android_filterfw_core_GLFrame_nativeAllocateExternal(JNIEnv* env,
@@ -96,13 +90,11 @@
                                                                    jobject gl_env) {
   GLEnv* gl_env_ptr = ConvertFromJava<GLEnv>(env, gl_env);
   if (!gl_env_ptr) return JNI_FALSE;
-  GLFrame* frame = new GLFrame(gl_env_ptr);
+  std::unique_ptr<GLFrame> frame(new GLFrame(gl_env_ptr));
   if (frame->InitWithExternalTexture()) {
-    return ToJBool(WrapObjectInJava(frame, env, thiz, true));
-  } else {
-    delete frame;
-    return JNI_FALSE;
+    return ToJBool(WrapOwnedObjectInJava(std::move(frame), env, thiz, true));
   }
+  return JNI_FALSE;
 }
 
 jboolean Java_android_filterfw_core_GLFrame_nativeDeallocate(JNIEnv* env, jobject thiz) {
diff --git a/media/mca/filterfw/jni/jni_native_frame.cpp b/media/mca/filterfw/jni/jni_native_frame.cpp
index c8f2352..1a11a19 100644
--- a/media/mca/filterfw/jni/jni_native_frame.cpp
+++ b/media/mca/filterfw/jni/jni_native_frame.cpp
@@ -35,7 +35,8 @@
 jboolean Java_android_filterfw_core_NativeFrame_nativeAllocate(JNIEnv* env,
                                                                jobject thiz,
                                                                jint size) {
-  return ToJBool(WrapObjectInJava(new NativeFrame(size), env, thiz, true));
+  std::unique_ptr<NativeFrame> frame(new NativeFrame(size));
+  return ToJBool(WrapOwnedObjectInJava(std::move(frame), env, thiz, true));
 }
 
 jboolean Java_android_filterfw_core_NativeFrame_nativeDeallocate(JNIEnv* env, jobject thiz) {
diff --git a/media/mca/filterfw/jni/jni_native_program.cpp b/media/mca/filterfw/jni/jni_native_program.cpp
index b30b769..1424607 100644
--- a/media/mca/filterfw/jni/jni_native_program.cpp
+++ b/media/mca/filterfw/jni/jni_native_program.cpp
@@ -28,7 +28,8 @@
 using android::filterfw::NativeProgram;
 
 jboolean Java_android_filterfw_core_NativeProgram_allocate(JNIEnv* env, jobject thiz) {
-  return ToJBool(WrapObjectInJava(new NativeProgram(), env, thiz, true));
+  std::unique_ptr<NativeProgram> program(new NativeProgram());
+  return ToJBool(WrapOwnedObjectInJava(std::move(program), env, thiz, true));
 }
 
 jboolean Java_android_filterfw_core_NativeProgram_deallocate(JNIEnv* env, jobject thiz) {
diff --git a/media/mca/filterfw/jni/jni_shader_program.cpp b/media/mca/filterfw/jni/jni_shader_program.cpp
index 19f43cd..98be04c 100644
--- a/media/mca/filterfw/jni/jni_shader_program.cpp
+++ b/media/mca/filterfw/jni/jni_shader_program.cpp
@@ -46,21 +46,14 @@
   // Create the shader
   if (!fragment_shader || !gl_env_ptr)
     return false;
-  else if (!vertex_shader)
-    return ToJBool(WrapObjectInJava(new ShaderProgram(
-      gl_env_ptr,
-      ToCppString(env, fragment_shader)),
-      env,
-      thiz,
-      true));
+
+  std::unique_ptr<ShaderProgram> shader;
+  if (!vertex_shader)
+    shader.reset(new ShaderProgram(gl_env_ptr, ToCppString(env, fragment_shader)));
   else
-    return ToJBool(WrapObjectInJava(new ShaderProgram(
-      gl_env_ptr,
-      ToCppString(env, vertex_shader),
-      ToCppString(env, fragment_shader)),
-      env,
-      thiz,
-      true));
+    shader.reset(new ShaderProgram(gl_env_ptr, ToCppString(env, vertex_shader),
+                                   ToCppString(env, fragment_shader)));
+  return ToJBool(WrapOwnedObjectInJava(std::move(shader), env, thiz, true));
 }
 
 jboolean Java_android_filterfw_core_ShaderProgram_deallocate(JNIEnv* env, jobject thiz) {
diff --git a/media/mca/filterfw/jni/jni_util.h b/media/mca/filterfw/jni/jni_util.h
index 11c0871..803ed29 100644
--- a/media/mca/filterfw/jni/jni_util.h
+++ b/media/mca/filterfw/jni/jni_util.h
@@ -16,6 +16,7 @@
 
 #include <jni.h>
 
+#include <memory>
 #include <unordered_map>
 #include <string>
 
@@ -214,6 +215,17 @@
   return pool ? pool->WrapObject(c_object, env, j_object, owns) : false;
 }
 
+// Calls WrapObjectInJava, safely freeing c_object if object creation fails.
+template<typename T>
+bool WrapOwnedObjectInJava(std::unique_ptr<T> c_object, JNIEnv* env,
+                           jobject j_object, bool owns) {
+  if (!WrapObjectInJava<T>(c_object.get(), env, j_object, owns))
+    return false;
+  // If we succeeded, a Java object now owns our c object; don't free it.
+  c_object.release();
+  return true;
+}
+
 // Creates a new Java instance, which wraps the passed C++ instance. Returns
 // the wrapped object or JNI_NULL if there was an error. Pass true to owns, if
 // the Java layer should own the object.
diff --git a/media/mca/filterfw/jni/jni_vertex_frame.cpp b/media/mca/filterfw/jni/jni_vertex_frame.cpp
index caae938..d0439fe 100644
--- a/media/mca/filterfw/jni/jni_vertex_frame.cpp
+++ b/media/mca/filterfw/jni/jni_vertex_frame.cpp
@@ -24,7 +24,8 @@
 jboolean Java_android_filterfw_core_VertexFrame_nativeAllocate(JNIEnv* env,
                                                                jobject thiz,
                                                                jint size) {
-  return ToJBool(WrapObjectInJava(new VertexFrame(size), env, thiz, true));
+  std::unique_ptr<VertexFrame> frame(new VertexFrame(size));
+  return ToJBool(WrapOwnedObjectInJava(std::move(frame), env, thiz, true));
 }
 
 jboolean Java_android_filterfw_core_VertexFrame_nativeDeallocate(JNIEnv* env, jobject thiz) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index c6ed04c..ca17c06 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -678,42 +678,49 @@
     public static final String EXTRA_DATA_FAILURE_CAUSE = PhoneConstants.DATA_FAILURE_CAUSE_KEY;
 
     /**
-     * Broadcast intent action for letting custom component know to show voicemail notification.
-     * @hide
+     * Broadcast intent action for letting the default dialer to know to show voicemail
+     * notification.
+     *
+     * <p>
+     * The {@link #EXTRA_NOTIFICATION_COUNT} extra indicates the total numbers of unheard
+     * voicemails.
+     * The {@link #EXTRA_VOICEMAIL_NUMBER} extra indicates the voicemail number if available.
+     * The {@link #EXTRA_CALL_VOICEMAIL_INTENT} extra is a {@link android.app.PendingIntent} that
+     * will call the voicemail number when sent. This extra will be empty if the voicemail number
+     * is not set, and {@link #EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT} will be set instead.
+     * The {@link #EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT} extra is a
+     * {@link android.app.PendingIntent} that will launch the voicemail settings. This extra is only
+     * available when the voicemail number is not set.
+     *
+     * @see #EXTRA_NOTIFICATION_COUNT
+     * @see #EXTRA_VOICEMAIL_NUMBER
+     * @see #EXTRA_CALL_VOICEMAIL_INTENT
+     * @see #EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT
      */
-    @SystemApi
     public static final String ACTION_SHOW_VOICEMAIL_NOTIFICATION =
             "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
 
     /**
      * The number of voice messages associated with the notification.
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_NOTIFICATION_COUNT =
             "android.telephony.extra.NOTIFICATION_COUNT";
 
     /**
      * The voicemail number.
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_VOICEMAIL_NUMBER =
             "android.telephony.extra.VOICEMAIL_NUMBER";
 
     /**
      * The intent to call voicemail.
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_CALL_VOICEMAIL_INTENT =
             "android.telephony.extra.CALL_VOICEMAIL_INTENT";
 
     /**
      * The intent to launch voicemail settings.
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT =
             "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
 
@@ -4550,10 +4557,19 @@
         return false;
     }
 
-    /** @hide */
-    @SystemApi
+    /**
+     * Turns mobile data on or off.
+     *
+     * <p>Requires Permission:
+     *     {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
+     *     calling app has carrier privileges.
+     *
+     * @param enable Whether to enable mobile data.
+     *
+     * @see #hasCarrierPrivileges
+     */
     public void setDataEnabled(boolean enable) {
-        setDataEnabled(SubscriptionManager.getDefaultDataSubscriptionId(), enable);
+        setDataEnabled(getSubId(), enable);
     }
 
     /** @hide */
@@ -4569,10 +4585,20 @@
         }
     }
 
-    /** @hide */
-    @SystemApi
+    /**
+     * Returns whether mobile data is enabled or not.
+     *
+     * <p>Requires Permission:
+     *     {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE},
+     *     {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the
+     *     calling app has carrier privileges.
+     *
+     * @return true if mobile data is enabled.
+     *
+     * @see #hasCarrierPrivileges
+     */
     public boolean getDataEnabled() {
-        return getDataEnabled(SubscriptionManager.getDefaultDataSubscriptionId());
+        return getDataEnabled(getSubId());
     }
 
     /** @hide */
diff --git a/test-runner/src/junit/MODULE_LICENSE_CPL b/test-runner/src/junit/MODULE_LICENSE_CPL
deleted file mode 100644
index 541dbb5..0000000
--- a/test-runner/src/junit/MODULE_LICENSE_CPL
+++ /dev/null
@@ -1 +0,0 @@
-http://www.opensource.org/licenses/cpl1.0.php
diff --git a/test-runner/src/junit/runner/ClassPathTestCollector.java b/test-runner/src/junit/runner/ClassPathTestCollector.java
deleted file mode 100644
index f48ddee..0000000
--- a/test-runner/src/junit/runner/ClassPathTestCollector.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package junit.runner;
-
-import java.util.*;
-import java.io.*;
-
-/**
- * An implementation of a TestCollector that consults the
- * class path. It considers all classes on the class path
- * excluding classes in JARs. It leaves it up to subclasses
- * to decide whether a class is a runnable Test.
- *
- * @see TestCollector
- * {@hide} - Not needed for 1.0 SDK
- */
-public abstract class ClassPathTestCollector implements TestCollector {
-
-    static final int SUFFIX_LENGTH= ".class".length();
-
-    public ClassPathTestCollector() {
-    }
-
-    public Enumeration collectTests() {
-        String classPath= System.getProperty("java.class.path");
-        Hashtable result = collectFilesInPath(classPath);
-        return result.elements();
-    }
-
-    public Hashtable collectFilesInPath(String classPath) {
-        Hashtable result= collectFilesInRoots(splitClassPath(classPath));
-        return result;
-    }
-
-    Hashtable collectFilesInRoots(Vector roots) {
-        Hashtable result= new Hashtable(100);
-        Enumeration e= roots.elements();
-        while (e.hasMoreElements())
-            gatherFiles(new File((String)e.nextElement()), "", result);
-        return result;
-    }
-
-    void gatherFiles(File classRoot, String classFileName, Hashtable result) {
-        File thisRoot= new File(classRoot, classFileName);
-        if (thisRoot.isFile()) {
-            if (isTestClass(classFileName)) {
-                String className= classNameFromFile(classFileName);
-                result.put(className, className);
-            }
-            return;
-        }
-        String[] contents= thisRoot.list();
-        if (contents != null) {
-            for (int i= 0; i < contents.length; i++)
-                gatherFiles(classRoot, classFileName+File.separatorChar+contents[i], result);
-        }
-    }
-
-    Vector splitClassPath(String classPath) {
-        Vector result= new Vector();
-        String separator= System.getProperty("path.separator");
-        StringTokenizer tokenizer= new StringTokenizer(classPath, separator);
-        while (tokenizer.hasMoreTokens())
-            result.addElement(tokenizer.nextToken());
-        return result;
-    }
-
-    protected boolean isTestClass(String classFileName) {
-        return
-                classFileName.endsWith(".class") &&
-                classFileName.indexOf('$') < 0 &&
-                classFileName.indexOf("Test") > 0;
-    }
-
-    protected String classNameFromFile(String classFileName) {
-        // convert /a/b.class to a.b
-        String s= classFileName.substring(0, classFileName.length()-SUFFIX_LENGTH);
-        String s2= s.replace(File.separatorChar, '.');
-        if (s2.startsWith("."))
-            return s2.substring(1);
-        return s2;
-    }
-}
diff --git a/test-runner/src/junit/runner/FailureDetailView.java b/test-runner/src/junit/runner/FailureDetailView.java
deleted file mode 100644
index c846191..0000000
--- a/test-runner/src/junit/runner/FailureDetailView.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package junit.runner;
-
-// The following line was removed for compatibility with Android libraries.
-//import java.awt.Component;
-
-import junit.framework.*;
-
-/**
- * A view to show a details about a failure
- * {@hide} - Not needed for 1.0 SDK
- */
-public interface FailureDetailView {
-    // The following definition was removed for compatibility with Android
-    // libraries.
-    //  /**
-    //   * Returns the component used to present the TraceView
-    //   */
-    //  public Component getComponent();
-
-    /**
-     * Shows details of a TestFailure
-     */
-    public void showFailure(TestFailure failure);
-    /**
-     * Clears the view
-     */
-    public void clear();
-}
diff --git a/test-runner/src/junit/runner/LoadingTestCollector.java b/test-runner/src/junit/runner/LoadingTestCollector.java
deleted file mode 100644
index 9101900..0000000
--- a/test-runner/src/junit/runner/LoadingTestCollector.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package junit.runner;
-
-import java.lang.reflect.*;
-import junit.framework.*;
-
-/**
- * An implementation of a TestCollector that loads
- * all classes on the class path and tests whether
- * it is assignable from Test or provides a static suite method.
- * @see TestCollector
- * {@hide} - Not needed for 1.0 SDK
- */
-public class LoadingTestCollector extends ClassPathTestCollector {
-
-    TestCaseClassLoader fLoader;
-
-    public LoadingTestCollector() {
-        fLoader= new TestCaseClassLoader();
-    }
-
-    protected boolean isTestClass(String classFileName) {
-        try {
-            if (classFileName.endsWith(".class")) {
-                Class testClass= classFromFile(classFileName);
-                return (testClass != null) && isTestClass(testClass);
-            }
-        }
-        catch (ClassNotFoundException expected) {
-        }
-        catch (NoClassDefFoundError notFatal) {
-        }
-        return false;
-    }
-
-    Class classFromFile(String classFileName) throws ClassNotFoundException {
-        String className= classNameFromFile(classFileName);
-        if (!fLoader.isExcluded(className))
-            return fLoader.loadClass(className, false);
-        return null;
-    }
-
-    boolean isTestClass(Class testClass) {
-        if (hasSuiteMethod(testClass))
-            return true;
-        if (Test.class.isAssignableFrom(testClass) &&
-                Modifier.isPublic(testClass.getModifiers()) &&
-                hasPublicConstructor(testClass))
-            return true;
-        return false;
-    }
-
-    boolean hasSuiteMethod(Class testClass) {
-        try {
-            testClass.getMethod(BaseTestRunner.SUITE_METHODNAME, new Class[0]);
-        } catch(Exception e) {
-            return false;
-        }
-        return true;
-    }
-
-    boolean hasPublicConstructor(Class testClass) {
-        try {
-            TestSuite.getTestConstructor(testClass);
-        } catch(NoSuchMethodException e) {
-            return false;
-        }
-        return true;
-    }
-}
diff --git a/test-runner/src/junit/runner/ReloadingTestSuiteLoader.java b/test-runner/src/junit/runner/ReloadingTestSuiteLoader.java
deleted file mode 100644
index c4d80d0..0000000
--- a/test-runner/src/junit/runner/ReloadingTestSuiteLoader.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package junit.runner;
-
-/**
- * A TestSuite loader that can reload classes.
- * {@hide} - Not needed for 1.0 SDK
- */
-public class ReloadingTestSuiteLoader implements TestSuiteLoader {
-
-    public Class load(String suiteClassName) throws ClassNotFoundException {
-        return createLoader().loadClass(suiteClassName, true);
-    }
-
-    public Class reload(Class aClass) throws ClassNotFoundException {
-        return createLoader().loadClass(aClass.getName(), true);
-    }
-
-    protected TestCaseClassLoader createLoader() {
-        return new TestCaseClassLoader();
-    }
-}
diff --git a/test-runner/src/junit/runner/SimpleTestCollector.java b/test-runner/src/junit/runner/SimpleTestCollector.java
deleted file mode 100644
index 6cb0e19..0000000
--- a/test-runner/src/junit/runner/SimpleTestCollector.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package junit.runner;
-
-/**
- * An implementation of a TestCollector that considers
- * a class to be a test class when it contains the
- * pattern "Test" in its name
- * @see TestCollector
- * {@hide} - Not needed for 1.0 SDK
- */
-public class SimpleTestCollector extends ClassPathTestCollector {
-
-    public SimpleTestCollector() {
-    }
-
-    protected boolean isTestClass(String classFileName) {
-        return
-                classFileName.endsWith(".class") &&
-                classFileName.indexOf('$') < 0 &&
-                classFileName.indexOf("Test") > 0;
-    }
-}
diff --git a/test-runner/src/junit/runner/Sorter.java b/test-runner/src/junit/runner/Sorter.java
deleted file mode 100644
index 8d9341d..0000000
--- a/test-runner/src/junit/runner/Sorter.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package junit.runner;
-
-import java.util.*;
-
-/**
- * A custom quick sort with support to customize the swap behaviour.
- * NOTICE: We can't use the the sorting support from the JDK 1.2 collection
- * classes because of the JDK 1.1.7 compatibility.
- * {@hide} - Not needed for 1.0 SDK
- */
-public class Sorter {
-    public static interface Swapper {
-        public void swap(Vector values, int left, int right);
-    }
-
-    public static void sortStrings(Vector values , int left, int right, Swapper swapper) {
-        int oleft= left;
-        int oright= right;
-        String mid= (String)values.elementAt((left + right) / 2);
-        do {
-            while (((String)(values.elementAt(left))).compareTo(mid) < 0)
-                left++;
-            while (mid.compareTo((String)(values.elementAt(right))) < 0)
-                right--;
-            if (left <= right) {
-                swapper.swap(values, left, right);
-                left++;
-                right--;
-            }
-        } while (left <= right);
-
-        if (oleft < right)
-            sortStrings(values, oleft, right, swapper);
-        if (left < oright)
-            sortStrings(values, left, oright, swapper);
-    }
-}
diff --git a/test-runner/src/junit/runner/TestCaseClassLoader.java b/test-runner/src/junit/runner/TestCaseClassLoader.java
deleted file mode 100644
index 09eec7f..0000000
--- a/test-runner/src/junit/runner/TestCaseClassLoader.java
+++ /dev/null
@@ -1,225 +0,0 @@
-package junit.runner;
-
-import java.util.*;
-import java.io.*;
-import java.net.URL;
-import java.util.zip.*;
-
-/**
- * A custom class loader which enables the reloading
- * of classes for each test run. The class loader
- * can be configured with a list of package paths that
- * should be excluded from loading. The loading
- * of these packages is delegated to the system class
- * loader. They will be shared across test runs.
- * <p>
- * The list of excluded package paths is specified in
- * a properties file "excluded.properties" that is located in
- * the same place as the TestCaseClassLoader class.
- * <p>
- * <b>Known limitation:</b> the TestCaseClassLoader cannot load classes
- * from jar files.
- * {@hide} - Not needed for 1.0 SDK
- */
-public class TestCaseClassLoader extends ClassLoader {
-    /** scanned class path */
-    private Vector fPathItems;
-    /** default excluded paths */
-    private String[] defaultExclusions= {
-            "junit.framework.",
-            "junit.extensions.",
-            "junit.runner."
-    };
-    /** name of excluded properties file */
-    static final String EXCLUDED_FILE= "excluded.properties";
-    /** excluded paths */
-    private Vector fExcluded;
-
-    /**
-     * Constructs a TestCaseLoader. It scans the class path
-     * and the excluded package paths
-     */
-    public TestCaseClassLoader() {
-        this(System.getProperty("java.class.path"));
-    }
-
-    /**
-     * Constructs a TestCaseLoader. It scans the class path
-     * and the excluded package paths
-     */
-    public TestCaseClassLoader(String classPath) {
-        scanPath(classPath);
-        readExcludedPackages();
-    }
-
-    private void scanPath(String classPath) {
-        String separator= System.getProperty("path.separator");
-        fPathItems= new Vector(10);
-        StringTokenizer st= new StringTokenizer(classPath, separator);
-        while (st.hasMoreTokens()) {
-            fPathItems.addElement(st.nextToken());
-        }
-    }
-
-    public URL getResource(String name) {
-        return ClassLoader.getSystemResource(name);
-    }
-
-    public InputStream getResourceAsStream(String name) {
-        return ClassLoader.getSystemResourceAsStream(name);
-    }
-
-    public boolean isExcluded(String name) {
-        for (int i= 0; i < fExcluded.size(); i++) {
-            if (name.startsWith((String) fExcluded.elementAt(i))) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public synchronized Class loadClass(String name, boolean resolve)
-            throws ClassNotFoundException {
-
-        Class c= findLoadedClass(name);
-        if (c != null)
-            return c;
-        //
-        // Delegate the loading of excluded classes to the
-        // standard class loader.
-        //
-        if (isExcluded(name)) {
-            try {
-                c= findSystemClass(name);
-                return c;
-            } catch (ClassNotFoundException e) {
-                // keep searching
-            }
-        }
-        if (c == null) {
-            byte[] data= lookupClassData(name);
-            if (data == null)
-                throw new ClassNotFoundException();
-            c= defineClass(name, data, 0, data.length);
-        }
-        if (resolve)
-            resolveClass(c);
-        return c;
-    }
-
-    private byte[] lookupClassData(String className) throws ClassNotFoundException {
-        byte[] data= null;
-        for (int i= 0; i < fPathItems.size(); i++) {
-            String path= (String) fPathItems.elementAt(i);
-            String fileName= className.replace('.', '/')+".class";
-            if (isJar(path)) {
-                data= loadJarData(path, fileName);
-            } else {
-                data= loadFileData(path, fileName);
-            }
-            if (data != null)
-                return data;
-        }
-        throw new ClassNotFoundException(className);
-    }
-
-    boolean isJar(String pathEntry) {
-        return pathEntry.endsWith(".jar") ||
-                pathEntry.endsWith(".apk") ||
-                pathEntry.endsWith(".zip");
-    }
-
-    private byte[] loadFileData(String path, String fileName) {
-        File file= new File(path, fileName);
-        if (file.exists()) {
-            return getClassData(file);
-        }
-        return null;
-    }
-
-    private byte[] getClassData(File f) {
-        try {
-            FileInputStream stream= new FileInputStream(f);
-            ByteArrayOutputStream out= new ByteArrayOutputStream(1000);
-            byte[] b= new byte[1000];
-            int n;
-            while ((n= stream.read(b)) != -1)
-                out.write(b, 0, n);
-            stream.close();
-            out.close();
-            return out.toByteArray();
-
-        } catch (IOException e) {
-        }
-        return null;
-    }
-
-    private byte[] loadJarData(String path, String fileName) {
-        ZipFile zipFile= null;
-        InputStream stream= null;
-        File archive= new File(path);
-        if (!archive.exists())
-            return null;
-        try {
-            zipFile= new ZipFile(archive);
-        } catch(IOException io) {
-            return null;
-        }
-        ZipEntry entry= zipFile.getEntry(fileName);
-        if (entry == null)
-            return null;
-        int size= (int) entry.getSize();
-        try {
-            stream= zipFile.getInputStream(entry);
-            byte[] data= new byte[size];
-            int pos= 0;
-            while (pos < size) {
-                int n= stream.read(data, pos, data.length - pos);
-                pos += n;
-            }
-            zipFile.close();
-            return data;
-        } catch (IOException e) {
-        } finally {
-            try {
-                if (stream != null)
-                    stream.close();
-            } catch (IOException e) {
-            }
-        }
-        return null;
-    }
-
-    private void readExcludedPackages() {
-        fExcluded= new Vector(10);
-        for (int i= 0; i < defaultExclusions.length; i++)
-            fExcluded.addElement(defaultExclusions[i]);
-
-        InputStream is= getClass().getResourceAsStream(EXCLUDED_FILE);
-        if (is == null)
-            return;
-        Properties p= new Properties();
-        try {
-            p.load(is);
-        }
-        catch (IOException e) {
-            return;
-        } finally {
-            try {
-                is.close();
-            } catch (IOException e) {
-            }
-        }
-        for (Enumeration e= p.propertyNames(); e.hasMoreElements(); ) {
-            String key= (String)e.nextElement();
-            if (key.startsWith("excluded.")) {
-                String path= p.getProperty(key);
-                path= path.trim();
-                if (path.endsWith("*"))
-                    path= path.substring(0, path.length()-1);
-                if (path.length() > 0)
-                    fExcluded.addElement(path);
-            }
-        }
-    }
-}
diff --git a/test-runner/src/junit/runner/TestCollector.java b/test-runner/src/junit/runner/TestCollector.java
deleted file mode 100644
index 3ac9d9e..0000000
--- a/test-runner/src/junit/runner/TestCollector.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package junit.runner;
-
-import java.util.*;
-
-
-/**
- * Collects Test class names to be presented
- * by the TestSelector.
- * @see TestSelector
- * {@hide} - Not needed for 1.0 SDK
- */
-public interface TestCollector {
-    /**
-     * Returns an enumeration of Strings with qualified class names
-     */
-    public Enumeration collectTests();
-}
diff --git a/test-runner/src/junit/runner/excluded.properties b/test-runner/src/junit/runner/excluded.properties
deleted file mode 100644
index 3284628..0000000
--- a/test-runner/src/junit/runner/excluded.properties
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# The list of excluded package paths for the TestCaseClassLoader
-#
-excluded.0=sun.*
-excluded.1=com.sun.*
-excluded.2=org.omg.*
-excluded.3=javax.*
-excluded.4=sunw.*
-excluded.5=java.*
-excluded.6=org.w3c.dom.*
-excluded.7=org.xml.sax.*
-excluded.8=net.jini.*
diff --git a/test-runner/src/junit/runner/package.html b/test-runner/src/junit/runner/package.html
deleted file mode 100644
index f08fa70..0000000
--- a/test-runner/src/junit/runner/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<HTML>
-<BODY>
-Utility classes supporting the junit test framework.
-</BODY>
-</HTML>
diff --git a/test-runner/src/junit/textui/package.html b/test-runner/src/junit/textui/package.html
deleted file mode 100644
index 723f2ae..0000000
--- a/test-runner/src/junit/textui/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<HTML>
-<BODY>
-Utility classes supporting the junit test framework.
-{@hide} - Not needed for 1.0 SDK
-</BODY>
-</HTML>
diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java
index 5d3ad058..ba493a0 100644
--- a/wifi/java/android/net/wifi/aware/PublishConfig.java
+++ b/wifi/java/android/net/wifi/aware/PublishConfig.java
@@ -32,9 +32,8 @@
 /**
  * Defines the configuration of a Aware publish session. Built using
  * {@link PublishConfig.Builder}. A publish session is created using
- * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig,
- * WifiAwareDiscoverySessionCallback)}
- * or updated using
+ * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
+ * android.os.Handler)} or updated using
  * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)}.
  *
  * @hide PROPOSED_AWARE_API
diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
index 2a6cc93..5e14f8f 100644
--- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
@@ -32,9 +32,8 @@
 /**
  * Defines the configuration of a Aware subscribe session. Built using
  * {@link SubscribeConfig.Builder}. Subscribe is done using
- * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig,
- * WifiAwareDiscoverySessionCallback)}
- * or
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
+ * android.os.Handler)} or
  * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
  *
  * @hide PROPOSED_AWARE_API
@@ -403,8 +402,8 @@
          * Sets the match style of the subscription - how are matches from a
          * single match session (corresponding to the same publish action on the
          * peer) reported to the host (using the
-         * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])}
-         * ). The options are: only report the first match and ignore the rest
+         * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+         * byte[], byte[])}). The options are: only report the first match and ignore the rest
          * {@link SubscribeConfig#MATCH_STYLE_FIRST_ONLY} or report every single
          * match {@link SubscribeConfig#MATCH_STYLE_ALL} (the default).
          *
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java b/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java
index 2cace61..1e8dbd9 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java
@@ -18,7 +18,7 @@
 
 /**
  * Base class for Aware attach callbacks. Should be extended by applications and set when calling
- * {@link WifiAwareManager#attach(android.os.Handler, WifiAwareAttachCallback)}. These are callbacks
+ * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}. These are callbacks
  * applying to the Aware connection as a whole - not to specific publish or subscribe sessions -
  * for that see {@link WifiAwareDiscoverySessionCallback}.
  *
@@ -27,7 +27,7 @@
 public class WifiAwareAttachCallback {
     /**
      * Called when Aware attach operation
-     * {@link WifiAwareManager#attach(android.os.Handler, WifiAwareAttachCallback)}
+     * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}
      * is completed and that we can now start discovery sessions or connections.
      *
      * @param session The Aware object on which we can execute further Aware operations - e.g.
@@ -39,7 +39,7 @@
 
     /**
      * Called when Aware attach operation
-     * {@link WifiAwareManager#attach(android.os.Handler, WifiAwareAttachCallback)} failed.
+     * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)} failed.
      */
     public void onAttachFailed() {
         /* empty */
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
index 6232c14..072ccab 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
@@ -58,7 +58,8 @@
      * message exchange. Restricts the parameters of the
      * {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])},
      * {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[])}, and
-     * {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[])} variants.
+     * {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int, byte[])}
+     * variants.
      *
      * @return A positive integer, maximum length of byte array for Aware messaging.
      */
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
index 07f7523..e8335d1 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
@@ -32,10 +32,10 @@
  * {@link WifiAwarePublishDiscoverySession} and {@link WifiAwareSubscribeDiscoverySession}. This
  * class provides functionality common to both publish and subscribe discovery sessions:
  * <ul>
- *     <li>Sending messages: {@link #sendMessage(Object, int, byte[])} or
- *     {@link #sendMessage(Object, int, byte[], int)} methods.
+ *     <li>Sending messages: {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[])} or
+ *     {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)} methods.
  *     <li>Creating a network-specifier when requesting a Aware connection:
- *     {@link #createNetworkSpecifier(int, Object, byte[])}.
+ *     {@link #createNetworkSpecifier(int, WifiAwareManager.PeerHandle, byte[])}.
  * </ul>
  * The {@link #destroy()} method must be called to destroy discovery sessions once they are
  * no longer needed.
@@ -62,7 +62,7 @@
 
     /**
      * Return the maximum permitted retry count when sending messages using
-     * {@link #sendMessage(Object, int, byte[], int)}.
+     * {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)}.
      *
      * @return Maximum retry count when sending messages.
      */
@@ -139,21 +139,24 @@
     /**
      * Sends a message to the specified destination. Aware messages are transmitted in the context
      * of a discovery session - executed subsequent to a publish/subscribe
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} event.
+     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * byte[], byte[])} event.
      * <p>
      *     Aware messages are not guaranteed delivery. Callbacks on
      *     {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully,
-     *     {@link WifiAwareDiscoverySessionCallback#onMessageSent(int)}, or transmission failed
-     *     (possibly after several retries) -
+     *     {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
+     *     failed (possibly after several retries) -
      *     {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)}.
      * <p>
      *     The peer will get a callback indicating a message was received using
-     *     {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])}.
+     *     {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     *     byte[])}.
      *
      * @param peerHandle The peer's handle for the message. Must be a result of an
-     *        {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])}
-     *        or
-     *        {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])} events.
+     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * byte[], byte[])} or
+     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * byte[])} events.
      * @param messageId An arbitrary integer used by the caller to identify the message. The same
      *            integer ID will be returned in the callbacks indicating message send success or
      *            failure. The {@code messageId} is not used internally by the Aware service - it
@@ -164,8 +167,8 @@
      *            (note: no retransmissions are attempted in other failure cases). A value of 0
      *            indicates no retries. Max permitted value is {@link #getMaxSendRetryCount()}.
      */
-    public void sendMessage(@NonNull Object peerHandle, int messageId, @Nullable byte[] message,
-            int retryCount) {
+    public void sendMessage(@NonNull WifiAwareManager.PeerHandle peerHandle, int messageId,
+            @Nullable byte[] message, int retryCount) {
         if (mTerminated) {
             Log.w(TAG, "sendMessage: called on terminated session");
             return;
@@ -183,37 +186,43 @@
     /**
      * Sends a message to the specified destination. Aware messages are transmitted in the context
      * of a discovery session - executed subsequent to a publish/subscribe
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} event.
+     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * byte[], byte[])} event.
      * <p>
      *     Aware messages are not guaranteed delivery. Callbacks on
      *     {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully,
-     *     {@link WifiAwareDiscoverySessionCallback#onMessageSent(int)}, or transmission failed
-     *     (possibly after several retries) -
+     *     {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
+     *     failed (possibly after several retries) -
      *     {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)}.
      * <p>
-     *     The peer will get a callback indicating a message was received using
-     *     {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])}.
-     * Equivalent to {@link #sendMessage(Object, int, byte[], int)} with a {@code retryCount} of
-     * 0.
+     * The peer will get a callback indicating a message was received using
+     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * byte[])}.
+     * Equivalent to {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)}
+     * with a {@code retryCount} of 0.
      *
      * @param peerHandle The peer's handle for the message. Must be a result of an
-     *        {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])}
-     *        or
-     *        {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])} events.
+     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * byte[], byte[])} or
+     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * byte[])} events.
      * @param messageId An arbitrary integer used by the caller to identify the message. The same
      *            integer ID will be returned in the callbacks indicating message send success or
      *            failure. The {@code messageId} is not used internally by the Aware service - it
      *                  can be arbitrary and non-unique.
      * @param message The message to be transmitted.
      */
-    public void sendMessage(@NonNull Object peerHandle, int messageId, @Nullable byte[] message) {
+    public void sendMessage(@NonNull WifiAwareManager.PeerHandle peerHandle, int messageId,
+            @Nullable byte[] message) {
         sendMessage(peerHandle, messageId, message, 0);
     }
 
     /**
      * Start a ranging operation with the specified peers. The peer IDs are obtained from an
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])} operation - can
+     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * byte[], byte[])} or
+     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * byte[])} operation - can
      * only range devices which are part of an ongoing discovery session.
      *
      * @param params   RTT parameters - each corresponding to a specific peer ID (the array sizes
@@ -256,11 +265,12 @@
      * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
      * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
      * @param peerHandle The peer's handle obtained through
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])}. On a RESPONDER
-     *               this value is used to gate the acceptance of a connection request from only
-     *               that peer. A RESPONDER may specified a null - indicating that it will accept
-     *               connection requests from any device.
+     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * byte[], byte[])} or
+     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
+     *                   from only that peer. A RESPONDER may specified a null - indicating that
+     *                   it will accept connection requests from any device.
      * @param token An arbitrary token (message) to be used to match connection initiation request
      *              to a responder setup. A RESPONDER is set up with a {@code token} which must
      *              be matched by the token provided by the INITIATOR. A null token is permitted
@@ -274,7 +284,7 @@
      * [or other varieties of that API].
      */
     public String createNetworkSpecifier(@WifiAwareManager.DataPathRole int role,
-            @Nullable Object peerHandle, @Nullable byte[] token) {
+            @Nullable WifiAwareManager.PeerHandle peerHandle, @Nullable byte[] token) {
         if (mTerminated) {
             Log.w(TAG, "createNetworkSpecifier: called on terminated session");
             return null;
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
index 9dfa24f..6331c9c 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
@@ -26,11 +26,10 @@
  * Base class for Aware session events callbacks. Should be extended by
  * applications wanting notifications. The callbacks are set when a
  * publish or subscribe session is created using
- * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig,
- * WifiAwareDiscoverySessionCallback)}
- * or
- * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig,
- * WifiAwareDiscoverySessionCallback)} .
+ * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
+ * android.os.Handler)} or
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
+ * android.os.Handler)}.
  * <p>
  * A single callback is set at session creation - it cannot be replaced.
  *
@@ -62,9 +61,8 @@
 
     /**
      * Called when a publish operation is started successfully in response to a
-     * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig,
-     * WifiAwareDiscoverySessionCallback)}
-     * operation.
+     * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
+     * android.os.Handler)} operation.
      *
      * @param session The {@link WifiAwarePublishDiscoverySession} used to control the
      *            discovery session.
@@ -75,9 +73,8 @@
 
     /**
      * Called when a subscribe operation is started successfully in response to a
-     * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig,
-     * WifiAwareDiscoverySessionCallback)}
-     * operation.
+     * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
+     * android.os.Handler)} operation.
      *
      * @param session The {@link WifiAwareSubscribeDiscoverySession} used to control the
      *            discovery session.
@@ -98,12 +95,10 @@
 
     /**
      * Called when a publish or subscribe discovery session cannot be created:
-     * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig,
-     * WifiAwareDiscoverySessionCallback)}
-     * or
-     * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig,
-     * WifiAwareDiscoverySessionCallback)},
-     * or when a configuration update fails:
+     * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
+     * android.os.Handler)} or
+     * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
+     * android.os.Handler)}, or when a configuration update fails:
      * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} or
      * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
      * <p>
@@ -138,13 +133,14 @@
      * @param matchFilter The filter (Tx on advertiser and Rx on listener) which
      *            resulted in this service discovery.
      */
-    public void onServiceDiscovered(Object peerHandle, byte[] serviceSpecificInfo,
-            byte[] matchFilter) {
+    public void onServiceDiscovered(WifiAwareManager.PeerHandle peerHandle,
+            byte[] serviceSpecificInfo, byte[] matchFilter) {
         /* empty */
     }
 
     /**
-     * Called in response to {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[])}
+     * Called in response to
+     * {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int, byte[])}
      * when a message is transmitted successfully - i.e. when it was received successfully by the
      * peer (corresponds to an ACK being received).
      * <p>
@@ -154,18 +150,18 @@
      *
      * @param messageId The arbitrary message ID specified when sending the message.
      */
-    public void onMessageSent(@SuppressWarnings("unused") int messageId) {
+    public void onMessageSendSucceeded(@SuppressWarnings("unused") int messageId) {
         /* empty */
     }
 
     /**
      * Called when message transmission fails - when no ACK is received from the peer.
      * Retries when ACKs are not received are done by hardware, MAC, and in the Aware stack (using
-     * the {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[], int)} method) -
-     * this event is received after all retries are exhausted.
+     * the {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int,
+     * byte[], int)} method) - this event is received after all retries are exhausted.
      * <p>
      * Note that either this callback or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageSent(int)} will be received
+     * {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)} will be received
      * - never both.
      *
      * @param messageId The arbitrary message ID specified when sending the message.
@@ -176,13 +172,14 @@
 
     /**
      * Called when a message is received from a discovery session peer - in response to the
-     * peer's {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[])} or
-     * {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[], int)}.
+     * peer's {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int,
+     * byte[])} or {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle,
+     * int, byte[], int)}.
      *
      * @param peerHandle An opaque handle to the peer matching our discovery operation.
      * @param message A byte array containing the message.
      */
-    public void onMessageReceived(Object peerHandle, byte[] message) {
+    public void onMessageReceived(WifiAwareManager.PeerHandle peerHandle, byte[] message) {
         /* empty */
     }
 }
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 10b70ab..a34ef47 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -56,14 +56,14 @@
  * The class provides access to:
  * <ul>
  * <li>Initialize a Aware cluster (peer-to-peer synchronization). Refer to
- * {@link #attach(Handler, WifiAwareAttachCallback)}.
+ * {@link #attach(WifiAwareAttachCallback, Handler)}.
  * <li>Create discovery sessions (publish or subscribe sessions). Refer to
- * {@link WifiAwareSession#publish(Handler, PublishConfig, WifiAwareDiscoverySessionCallback)} and
- * {@link WifiAwareSession#subscribe(Handler, SubscribeConfig, WifiAwareDiscoverySessionCallback)}.
+ * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, Handler)} and
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback, Handler)}.
  * <li>Create a Aware network specifier to be used with
  * {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
  * to set-up a Aware connection with a peer. Refer to
- * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])} and
+ * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[])} and
  * {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])}.
  * </ul>
  * <p>
@@ -73,7 +73,7 @@
  *     broadcast. Note that this broadcast is not sticky - you should register for it and then
  *     check the above API to avoid a race condition.
  * <p>
- *     An application must use {@link #attach(Handler, WifiAwareAttachCallback)} to initialize a
+ *     An application must use {@link #attach(WifiAwareAttachCallback, Handler)} to initialize a
  *     Aware cluster - before making any other Aware operation. Aware cluster membership is a
  *     device-wide operation - the API guarantees that the device is in a cluster or joins a
  *     Aware cluster (or starts one if none can be found). Information about attach success (or
@@ -86,12 +86,11 @@
  *     application detaches.
  * <p>
  *     Once a Aware attach is confirmed use the
- *     {@link WifiAwareSession#publish(Handler, PublishConfig, WifiAwareDiscoverySessionCallback)}
+ *     {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, Handler)}
  *     or
- *     {@link WifiAwareSession#subscribe(Handler, SubscribeConfig,
- *     WifiAwareDiscoverySessionCallback)}
- *     to create publish or subscribe Aware discovery sessions. Events are called on the provided
- *     callback object {@link WifiAwareDiscoverySessionCallback}. Specifically, the
+ *     {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
+ *     Handler)} to create publish or subscribe Aware discovery sessions. Events are called on the
+ *     provided callback object {@link WifiAwareDiscoverySessionCallback}. Specifically, the
  *     {@link WifiAwareDiscoverySessionCallback#onPublishStarted(WifiAwarePublishDiscoverySession)}
  *     and
  *     {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(
@@ -102,7 +101,7 @@
  *     the session {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} and
  *     {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can
  *     also be used to send messages using the
- *     {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[])} APIs. When an
+ *     {@link WifiAwareDiscoveryBaseSession#sendMessage(PeerHandle, int, byte[])} APIs. When an
  *     application is finished with a discovery session it <b>must</b> terminate it using the
  *     {@link WifiAwareDiscoveryBaseSession#destroy()} API.
  * <p>
@@ -115,7 +114,7 @@
  *        {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
  *        <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using
  *        {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} or
- *        {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])}.
+ *        {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[])}.
  *    </ul>
  *
  * @hide PROPOSED_AWARE_API
@@ -225,7 +224,7 @@
      * Connection creation role is that of INITIATOR. Used to create a network specifier string
      * when requesting a Aware network.
      *
-     * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])
+     * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[])
      * @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])
      */
     public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0;
@@ -234,7 +233,7 @@
      * Connection creation role is that of RESPONDER. Used to create a network specifier string
      * when requesting a Aware network.
      *
-     * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])
+     * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[])
      * @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])
      */
     public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1;
@@ -326,13 +325,13 @@
      * then this function will simply indicate success immediately using the same {@code
      * attachCallback}.
      *
+     * @param attachCallback A callback for attach events, extended from
+     * {@link WifiAwareAttachCallback}.
      * @param handler The Handler on whose thread to execute the callbacks of the {@code
      * attachCallback} object. If a null is provided then the application's main thread will be
      *                used.
-     * @param attachCallback A callback for attach events, extended from
-     * {@link WifiAwareAttachCallback}.
      */
-    public void attach(@Nullable Handler handler, @NonNull WifiAwareAttachCallback attachCallback) {
+    public void attach(@NonNull WifiAwareAttachCallback attachCallback, @Nullable Handler handler) {
         attach(handler, null, attachCallback, null);
     }
 
@@ -352,20 +351,21 @@
      * on startup and whenever it is updated (it is randomized at regular intervals for privacy).
      * The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
      * permission to execute this attach request. Otherwise, use the
-     * {@link #attach(Handler, WifiAwareAttachCallback)} version. Note that aside from permission
+     * {@link #attach(WifiAwareAttachCallback, Handler)} version. Note that aside from permission
      * requirements this listener will wake up the host at regular intervals causing higher power
      * consumption, do not use it unless the information is necessary (e.g. for OOB discovery).
      *
-     * @param handler The Handler on whose thread to execute the callbacks of the {@code
-     * attachCallback} and {@code identityChangedListener} objects. If a null is provided then the
-     *                application's main thread will be used.
      * @param attachCallback A callback for attach events, extended from
      * {@link WifiAwareAttachCallback}.
      * @param identityChangedListener A listener for changed identity, extended from
      * {@link WifiAwareIdentityChangedListener}.
+     * @param handler The Handler on whose thread to execute the callbacks of the {@code
+     * attachCallback} and {@code identityChangedListener} objects. If a null is provided then the
+     *                application's main thread will be used.
      */
-    public void attach(@Nullable Handler handler, @NonNull WifiAwareAttachCallback attachCallback,
-            @NonNull WifiAwareIdentityChangedListener identityChangedListener) {
+    public void attach(@NonNull WifiAwareAttachCallback attachCallback,
+            @NonNull WifiAwareIdentityChangedListener identityChangedListener,
+            @Nullable Handler handler) {
         attach(handler, null, attachCallback, identityChangedListener);
     }
 
@@ -481,7 +481,7 @@
     }
 
     /** @hide */
-    public void sendMessage(int clientId, int sessionId, Object peerHandle, byte[] message,
+    public void sendMessage(int clientId, int sessionId, PeerHandle peerHandle, byte[] message,
             int messageId, int retryCount) {
         if (peerHandle == null) {
             throw new IllegalArgumentException(
@@ -490,13 +490,13 @@
 
         if (VDBG) {
             Log.v(TAG, "sendMessage(): clientId=" + clientId + ", sessionId=" + sessionId
-                    + ", peerHandle=" + ((OpaquePeerHandle) peerHandle).peerId + ", messageId="
+                    + ", peerHandle=" + peerHandle.peerId + ", messageId="
                     + messageId + ", retryCount=" + retryCount);
         }
 
         try {
-            mService.sendMessage(clientId, sessionId, ((OpaquePeerHandle) peerHandle).peerId,
-                    message, messageId, retryCount);
+            mService.sendMessage(clientId, sessionId, peerHandle.peerId, message, messageId,
+                    retryCount);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -524,12 +524,12 @@
     }
 
     /** @hide */
-    public String createNetworkSpecifier(int clientId, int role, int sessionId, Object peerHandle,
-            byte[] token) {
+    public String createNetworkSpecifier(int clientId, int role, int sessionId,
+            PeerHandle peerHandle, byte[] token) {
         if (VDBG) {
             Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId
-                    + ", peerHandle=" + ((peerHandle == null) ? peerHandle
-                    : ((OpaquePeerHandle) peerHandle).peerId) + ", token=" + token);
+                    + ", peerHandle=" + ((peerHandle == null) ? peerHandle : peerHandle.peerId)
+                    + ", token=" + token);
         }
 
         int type;
@@ -569,7 +569,7 @@
             json.put(NETWORK_SPECIFIER_KEY_CLIENT_ID, clientId);
             json.put(NETWORK_SPECIFIER_KEY_SESSION_ID, sessionId);
             if (peerHandle != null) {
-                json.put(NETWORK_SPECIFIER_KEY_PEER_ID, ((OpaquePeerHandle) peerHandle).peerId);
+                json.put(NETWORK_SPECIFIER_KEY_PEER_ID, peerHandle.peerId);
             }
             if (token != null) {
                 json.put(NETWORK_SPECIFIER_KEY_TOKEN,
@@ -876,18 +876,18 @@
                             break;
                         case CALLBACK_MATCH:
                             mOriginalCallback.onServiceDiscovered(
-                                    new OpaquePeerHandle(msg.arg1),
+                                    new PeerHandle(msg.arg1),
                                     msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE),
                                     msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2));
                             break;
                         case CALLBACK_MESSAGE_SEND_SUCCESS:
-                            mOriginalCallback.onMessageSent(msg.arg1);
+                            mOriginalCallback.onMessageSendSucceeded(msg.arg1);
                             break;
                         case CALLBACK_MESSAGE_SEND_FAIL:
                             mOriginalCallback.onMessageSendFailed(msg.arg1);
                             break;
                         case CALLBACK_MESSAGE_RECEIVED:
-                            mOriginalCallback.onMessageReceived(new OpaquePeerHandle(msg.arg1),
+                            mOriginalCallback.onMessageReceived(new PeerHandle(msg.arg1),
                                     (byte[]) msg.obj);
                             break;
                     }
@@ -1019,12 +1019,14 @@
         }
     }
 
-    /** @hide */
-    public static class OpaquePeerHandle {
-        public OpaquePeerHandle(int peerId) {
+    /** @hide PROPOSED_AWARE_API */
+    public static class PeerHandle {
+        /** @hide */
+        public PeerHandle(int peerId) {
             this.peerId = peerId;
         }
 
+        /** @hide */
         public int peerId;
     }
 }
diff --git a/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java b/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java
index 610a92c..68786d1 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java
@@ -21,9 +21,8 @@
 
 /**
  * A class representing a Aware publish session. Created when
- * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig,
- * WifiAwareDiscoverySessionCallback)}
- * is called and a discovery session is created and returned in
+ * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
+ * android.os.Handler)} is called and a discovery session is created and returned in
  * {@link WifiAwareDiscoverySessionCallback#onPublishStarted(WifiAwarePublishDiscoverySession)}. See
  * baseline functionality of all discovery sessions in {@link WifiAwareDiscoveryBaseSession}. This
  * object allows updating an existing/running publish discovery session using
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 357bd43..acb60a4 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -65,7 +65,7 @@
      * session-wide destroy.
      * <p>
      * An application may re-attach after a destroy using
-     * {@link WifiAwareManager#attach(Handler, WifiAwareAttachCallback)} .
+     * {@link WifiAwareManager#attach(WifiAwareAttachCallback, Handler)} .
      */
     public void destroy() {
         WifiAwareManager mgr = mMgr.get();
@@ -116,15 +116,15 @@
      * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
      * permission to start a publish discovery session.
      *
-     * @param handler The Handler on whose thread to execute the callbacks of the {@code
-     * callback} object. If a null is provided then the application's main thread will be used.
      * @param publishConfig The {@link PublishConfig} specifying the
      *            configuration of the requested publish session.
      * @param callback A {@link WifiAwareDiscoverySessionCallback} derived object to be used for
      *                 session event callbacks.
+     * @param handler The Handler on whose thread to execute the callbacks of the {@code
+     * callback} object. If a null is provided then the application's main thread will be used.
      */
-    public void publish(@Nullable Handler handler, @NonNull PublishConfig publishConfig,
-            @NonNull WifiAwareDiscoverySessionCallback callback) {
+    public void publish(@NonNull PublishConfig publishConfig,
+            @NonNull WifiAwareDiscoverySessionCallback callback, @Nullable Handler handler) {
         WifiAwareManager mgr = mMgr.get();
         if (mgr == null) {
             Log.e(TAG, "publish: called post GC on WifiAwareManager");
@@ -162,15 +162,15 @@
      * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
      * permission to start a subscribe discovery session.
      *
-     * @param handler The Handler on whose thread to execute the callbacks of the {@code
-     * callback} object. If a null is provided then the application's main thread will be used.
      * @param subscribeConfig The {@link SubscribeConfig} specifying the
      *            configuration of the requested subscribe session.
      * @param callback A {@link WifiAwareDiscoverySessionCallback} derived object to be used for
      *                 session event callbacks.
+     * @param handler The Handler on whose thread to execute the callbacks of the {@code
+     * callback} object. If a null is provided then the application's main thread will be used.
      */
-    public void subscribe(@Nullable Handler handler, @NonNull SubscribeConfig subscribeConfig,
-            @NonNull WifiAwareDiscoverySessionCallback callback) {
+    public void subscribe(@NonNull SubscribeConfig subscribeConfig,
+            @NonNull WifiAwareDiscoverySessionCallback callback, @Nullable Handler handler) {
         WifiAwareManager mgr = mMgr.get();
         if (mgr == null) {
             Log.e(TAG, "publish: called post GC on WifiAwareManager");
@@ -193,7 +193,8 @@
      *     This API is targeted for applications which can obtain the peer MAC address using OOB
      *     (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
      *     when using Aware discovery use the alternative network specifier method -
-     *     {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])}.
+     *     {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int,
+     *     WifiAwareManager.PeerHandle, byte[])}.
      *
      * @param role  The role of this device:
      *              {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java b/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java
index 7c48f54..a0ec809 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java
@@ -21,8 +21,8 @@
 
 /**
  * A class representing a Aware subscribe session. Created when
- * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig,
- * WifiAwareDiscoverySessionCallback)}
+ * {@link WifiAwareSession#subscribe(SubscribeConfig,
+ * WifiAwareDiscoverySessionCallback, android.os.Handler)}
  * is called and a discovery session is created and returned in
  * {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(WifiAwareSubscribeDiscoverySession)}.
  * See baseline functionality of all discovery sessions in {@link WifiAwareDiscoveryBaseSession}.
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index a62a0fb..643753a 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -36,6 +36,27 @@
     public HomeSP homeSp = null;
     public Credential credential = null;
 
+    /**
+     * Constructor for creating PasspointConfiguration with default values.
+     */
+    public PasspointConfiguration() {}
+
+    /**
+     * Copy constructor.
+     *
+     * @param source The source to copy from
+     */
+    public PasspointConfiguration(PasspointConfiguration source) {
+        if (source != null) {
+            if (source.homeSp != null) {
+                homeSp = new HomeSP(source.homeSp);
+            }
+            if (source.credential != null) {
+                credential = new Credential(source.credential);
+            }
+        }
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index 57e65eb..790dfaf 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -109,6 +109,25 @@
          */
         public String nonEapInnerMethod = null;
 
+        /**
+         * Constructor for creating UserCredential with default values.
+         */
+        public UserCredential() {}
+
+        /**
+         * Copy constructor.
+         *
+         * @param source The source to copy from
+         */
+        public UserCredential(UserCredential source) {
+            if (source != null) {
+                username = source.username;
+                password = source.password;
+                eapType = source.eapType;
+                nonEapInnerMethod = source.nonEapInnerMethod;
+            }
+        }
+
         @Override
         public int describeContents() {
             return 0;
@@ -221,6 +240,26 @@
          */
         public byte[] certSha256FingerPrint = null;
 
+        /**
+         * Constructor for creating CertificateCredential with default values.
+         */
+        public CertificateCredential() {}
+
+        /**
+         * Copy constructor.
+         *
+         * @param source The source to copy from
+         */
+        public CertificateCredential(CertificateCredential source) {
+            if (source != null) {
+                certType = source.certType;
+                if (source.certSha256FingerPrint != null) {
+                    certSha256FingerPrint = Arrays.copyOf(source.certSha256FingerPrint,
+                                                          source.certSha256FingerPrint.length);
+                }
+            }
+        }
+
         @Override
         public int describeContents() {
             return 0;
@@ -307,6 +346,23 @@
          */
         public int eapType = Integer.MIN_VALUE;
 
+        /**
+         * Constructor for creating SimCredential with default values.
+         */
+        public SimCredential() {}
+
+        /**
+         * Copy constructor
+         *
+         * @param source The source to copy from
+         */
+        public SimCredential(SimCredential source) {
+            if (source != null) {
+                imsi = source.imsi;
+                eapType = source.eapType;
+            }
+        }
+
         @Override
         public int describeContents() {
             return 0;
@@ -422,6 +478,37 @@
      */
     public PrivateKey clientPrivateKey = null;
 
+    /**
+     * Constructor for creating Credential with default values.
+     */
+    public Credential() {}
+
+    /**
+     * Copy constructor.
+     *
+     * @param source The source to copy from
+     */
+    public Credential(Credential source) {
+        if (source != null) {
+            realm = source.realm;
+            if (source.userCredential != null) {
+                userCredential = new UserCredential(source.userCredential);
+            }
+            if (source.certCredential != null) {
+                certCredential = new CertificateCredential(source.certCredential);
+            }
+            if (source.simCredential != null) {
+                simCredential = new SimCredential(source.simCredential);
+            }
+            if (source.clientCertificateChain != null) {
+                clientCertificateChain = Arrays.copyOf(source.clientCertificateChain,
+                                                       source.clientCertificateChain.length);
+            }
+            caCertificate = source.caCertificate;
+            clientPrivateKey = source.clientPrivateKey;
+        }
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
index 5837c06..d4a5792 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
@@ -53,6 +53,27 @@
      */
     public long[] roamingConsortiumOIs = null;
 
+    /**
+     * Constructor for creating HomeSP with default values.
+     */
+    public HomeSP() {}
+
+    /**
+     * Copy constructor.
+     *
+     * @param source The source to copy from
+     */
+    public HomeSP(HomeSP source) {
+        if (source != null) {
+            fqdn = source.fqdn;
+            friendlyName = source.friendlyName;
+            if (source.roamingConsortiumOIs != null) {
+                roamingConsortiumOIs = Arrays.copyOf(source.roamingConsortiumOIs,
+                                                     source.roamingConsortiumOIs.length);
+            }
+        }
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
new file mode 100644
index 0000000..4b6957b
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2016 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.aware;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+
+/**
+ * Unit test harness for TlvBufferUtils class.
+ */
+@SmallTest
+public class TlvBufferUtilsTest {
+    @Rule
+    public ErrorCollector collector = new ErrorCollector();
+
+    /*
+     * TlvBufferUtils Tests
+     */
+
+    @Test
+    public void testTlvBuild() {
+        TlvBufferUtils.TlvConstructor tlv11 = new TlvBufferUtils.TlvConstructor(1, 1);
+        tlv11.allocate(15);
+        tlv11.putByte(0, (byte) 2);
+        tlv11.putByteArray(2, new byte[] {
+                0, 1, 2 });
+
+        collector.checkThat("tlv11-correct-construction",
+                tlv11.getArray(), equalTo(new byte[]{0, 1, 2, 2, 3, 0, 1, 2}));
+
+        LvBufferUtils.LvConstructor tlv01 = new LvBufferUtils.LvConstructor(1);
+        tlv01.allocate(15);
+        tlv01.putByte((byte) 2);
+        tlv01.putByteArray(2, new byte[] {
+                0, 1, 2 });
+
+        collector.checkThat("tlv01-correct-construction",
+                tlv01.getArray(), equalTo(new byte[] {1, 2, 3, 0, 1, 2 }));
+
+        collector.checkThat("tlv11-valid",
+                TlvBufferUtils.isValid(tlv11.getArray(), 1, 1),
+                equalTo(true));
+        collector.checkThat("tlv01-valid",
+                LvBufferUtils.isValid(tlv01.getArray(), 1),
+                equalTo(true));
+    }
+
+    @Test
+    public void testTlvIterate() {
+        final String ascii = "ABC";
+        final String nonAscii = "何かもっと複雑な";
+
+        TlvBufferUtils.TlvConstructor tlv22 = new TlvBufferUtils.TlvConstructor(2, 2);
+        tlv22.allocate(18);
+        tlv22.putInt(0, 2);
+        tlv22.putShort(2, (short) 3);
+        tlv22.putZeroLengthElement(55);
+
+        TlvBufferUtils.TlvIterable tlv22It = new TlvBufferUtils.TlvIterable(2, 2, tlv22.getArray());
+        int count = 0;
+        for (TlvBufferUtils.TlvElement tlv : tlv22It) {
+            if (count == 0) {
+                collector.checkThat("tlv22-correct-iteration-mType", tlv.type, equalTo(0));
+                collector.checkThat("tlv22-correct-iteration-mLength", tlv.length, equalTo(4));
+                collector.checkThat("tlv22-correct-iteration-DATA", tlv.getInt(), equalTo(2));
+            } else if (count == 1) {
+                collector.checkThat("tlv22-correct-iteration-mType", tlv.type, equalTo(2));
+                collector.checkThat("tlv22-correct-iteration-mLength", tlv.length, equalTo(2));
+                collector.checkThat("tlv22-correct-iteration-DATA", (int) tlv.getShort(),
+                        equalTo(3));
+            } else if (count == 2) {
+                collector.checkThat("tlv22-correct-iteration-mType", tlv.type, equalTo(55));
+                collector.checkThat("tlv22-correct-iteration-mLength", tlv.length, equalTo(0));
+            } else {
+                collector.checkThat("Invalid number of iterations in loop - tlv22", true,
+                        equalTo(false));
+            }
+            ++count;
+        }
+        if (count != 3) {
+            collector.checkThat("Invalid number of iterations outside loop - tlv22", true,
+                    equalTo(false));
+        }
+
+        TlvBufferUtils.TlvConstructor tlv02 = new TlvBufferUtils.TlvConstructor(0, 2);
+        tlv02.allocate(100);
+        tlv02.putByte(0, (byte) 2);
+        tlv02.putString(0, ascii);
+        tlv02.putString(0, nonAscii);
+
+        TlvBufferUtils.TlvIterable tlv02It = new TlvBufferUtils.TlvIterable(0, 2, tlv02.getArray());
+        count = 0;
+        for (TlvBufferUtils.TlvElement tlv : tlv02It) {
+            if (count == 0) {
+                collector.checkThat("tlv02-correct-iteration-mLength", tlv.length, equalTo(1));
+                collector.checkThat("tlv02-correct-iteration-DATA", (int) tlv.getByte(),
+                        equalTo(2));
+            } else if (count == 1) {
+                collector.checkThat("tlv02-correct-iteration-mLength", tlv.length,
+                        equalTo(ascii.length()));
+                collector.checkThat("tlv02-correct-iteration-DATA", tlv.getString().equals(ascii),
+                        equalTo(true));
+            } else if (count == 2) {
+                collector.checkThat("tlv02-correct-iteration-mLength", tlv.length,
+                        equalTo(nonAscii.getBytes().length));
+                collector.checkThat("tlv02-correct-iteration-DATA",
+                        tlv.getString().equals(nonAscii), equalTo(true));
+            } else {
+                collector.checkThat("Invalid number of iterations in loop - tlv02", true,
+                        equalTo(false));
+            }
+            ++count;
+        }
+        collector.checkThat("Invalid number of iterations outside loop - tlv02", count,
+                equalTo(3));
+
+        collector.checkThat("tlv22-valid",
+                TlvBufferUtils.isValid(tlv22.getArray(), 2, 2),
+                equalTo(true));
+        collector.checkThat("tlv02-valid",
+                LvBufferUtils.isValid(tlv02.getArray(), 2),
+                equalTo(true));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testTlvInvalidSizeT1L0() {
+        TlvBufferUtils.TlvConstructor tlv10 = new TlvBufferUtils.TlvConstructor(1, 0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testTlvInvalidSizeTm3L2() {
+        TlvBufferUtils.TlvConstructor tlv10 = new TlvBufferUtils.TlvConstructor(-3, 2);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testTlvInvalidSizeT1Lm2() {
+        TlvBufferUtils.TlvConstructor tlv10 = new TlvBufferUtils.TlvConstructor(1, -2);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testTlvInvalidSizeT1L3() {
+        TlvBufferUtils.TlvConstructor tlv10 = new TlvBufferUtils.TlvConstructor(1, 3);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testTlvInvalidSizeT3L1() {
+        TlvBufferUtils.TlvConstructor tlv10 = new TlvBufferUtils.TlvConstructor(3, 1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testTlvItInvalidSizeT1L0() {
+        final byte[] dummy = {
+                0, 1, 2 };
+        final int dummyLength = 3;
+        TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, 0, dummy);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testTlvItInvalidSizeTm3L2() {
+        final byte[] dummy = {
+                0, 1, 2 };
+        final int dummyLength = 3;
+        TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(-3, 2, dummy);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testTlvItInvalidSizeT1Lm2() {
+        final byte[] dummy = {
+                0, 1, 2 };
+        final int dummyLength = 3;
+        TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, -2, dummy);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testTlvItInvalidSizeT1L3() {
+        final byte[] dummy = {
+                0, 1, 2 };
+        final int dummyLength = 3;
+        TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, 3, dummy);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testTlvItInvalidSizeT3L1() {
+        final byte[] dummy = {
+                0, 1, 2 };
+        final int dummyLength = 3;
+        TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(3, 1, dummy);
+    }
+
+    /**
+     * Validate that a malformed byte array fails the TLV validity test.
+     */
+    @Test
+    public void testTlvInvalidByteArray() {
+        LvBufferUtils.LvConstructor tlv01 = new LvBufferUtils.LvConstructor(1);
+        tlv01.allocate(15);
+        tlv01.putByte((byte) 2);
+        tlv01.putByteArray(2, new byte[]{0, 1, 2});
+
+        byte[] array = tlv01.getArray();
+        array[0] = 10;
+
+        collector.checkThat("tlv01-invalid",
+                LvBufferUtils.isValid(array, 1), equalTo(false));
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
new file mode 100644
index 0000000..b30ecf7
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -0,0 +1,1054 @@
+/*
+ * Copyright (C) 2016 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.aware;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.wifi.RttManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.test.TestLooper;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Base64;
+
+import libcore.util.HexEncoding;
+
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit test harness for WifiAwareManager class.
+ */
+@SmallTest
+public class WifiAwareManagerTest {
+    private WifiAwareManager mDut;
+    private TestLooper mMockLooper;
+    private Handler mMockLooperHandler;
+
+    @Rule
+    public ErrorCollector collector = new ErrorCollector();
+
+    @Mock
+    public Context mockContext;
+
+    @Mock
+    public WifiAwareAttachCallback mockCallback;
+
+    @Mock
+    public WifiAwareDiscoverySessionCallback mockSessionCallback;
+
+    @Mock
+    public IWifiAwareManager mockAwareService;
+
+    @Mock
+    public WifiAwarePublishDiscoverySession mockPublishSession;
+
+    @Mock
+    public WifiAwareSubscribeDiscoverySession mockSubscribeSession;
+
+    @Mock
+    public RttManager.RttListener mockRttListener;
+
+    private static final int AWARE_STATUS_ERROR = -1;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mDut = new WifiAwareManager(mockContext, mockAwareService);
+        mMockLooper = new TestLooper();
+        mMockLooperHandler = new Handler(mMockLooper.getLooper());
+    }
+
+    /*
+     * Straight pass-through tests
+     */
+
+    /**
+     * Validate pass-through of enableUsage() API.
+     */
+    @Test
+    public void testEnableUsage() throws Exception {
+        mDut.enableUsage();
+
+        verify(mockAwareService).enableUsage();
+    }
+
+    /**
+     * Validate pass-through of disableUsage() API.
+     */
+    @Test
+    public void testDisableUsage() throws Exception {
+        mDut.disableUsage();
+
+        verify(mockAwareService).disableUsage();
+    }
+
+    /**
+     * Validate pass-through of isUsageEnabled() API.
+     */
+    @Test
+    public void testIsUsageEnable() throws Exception {
+        mDut.isAvailable();
+
+        verify(mockAwareService).isUsageEnabled();
+    }
+
+    /**
+     * Validate pass-through of getCharacteristics() API.
+     */
+    @Test
+    public void testGetCharacteristics() throws Exception {
+        mDut.getCharacteristics();
+
+        verify(mockAwareService).getCharacteristics();
+    }
+
+    /*
+     * WifiAwareEventCallbackProxy Tests
+     */
+
+    /**
+     * Validate the successful connect flow: (1) connect + success (2) publish, (3) disconnect
+     * (4) try publishing on old session (5) connect again
+     */
+    @Test
+    public void testConnectFlow() throws Exception {
+        final int clientId = 4565;
+
+        InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService);
+        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareEventCallback.class);
+        ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
+                WifiAwareSession.class);
+        ArgumentCaptor<IBinder> binder = ArgumentCaptor.forClass(IBinder.class);
+
+        // (1) connect + success
+        mDut.attach(mockCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).connect(binder.capture(), anyString(),
+                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        clientProxyCallback.getValue().onConnectSuccess(clientId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
+        WifiAwareSession session = sessionCaptor.getValue();
+
+        // (2) publish - should succeed
+        PublishConfig publishConfig = new PublishConfig.Builder().build();
+        session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig),
+                any(IWifiAwareDiscoverySessionCallback.class));
+
+        // (3) disconnect
+        session.destroy();
+        inOrder.verify(mockAwareService).disconnect(eq(clientId), eq(binder.getValue()));
+
+        // (4) try publishing again - fails silently
+        session.publish(new PublishConfig.Builder().build(), mockSessionCallback,
+                mMockLooperHandler);
+
+        // (5) connect
+        mDut.attach(mockCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).connect(binder.capture(), anyString(),
+                any(IWifiAwareEventCallback.class), (ConfigRequest) isNull(), eq(false));
+
+        verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService);
+    }
+
+    /**
+     * Validate the failed connect flow: (1) connect + failure, (2) connect + success (3) subscribe
+     */
+    @Test
+    public void testConnectFailure() throws Exception {
+        final int clientId = 4565;
+        final int reason = AWARE_STATUS_ERROR;
+
+        InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService);
+        ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
+                WifiAwareSession.class);
+        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareEventCallback.class);
+
+        // (1) connect + failure
+        mDut.attach(mockCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
+                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        clientProxyCallback.getValue().onConnectFail(reason);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttachFailed();
+
+        // (2) connect + success
+        mDut.attach(mockCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
+                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        clientProxyCallback.getValue().onConnectSuccess(clientId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
+        WifiAwareSession session = sessionCaptor.getValue();
+
+        // (4) subscribe: should succeed
+        SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
+        session.subscribe(subscribeConfig, mockSessionCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).subscribe(eq(clientId), eq(subscribeConfig),
+                any(IWifiAwareDiscoverySessionCallback.class));
+
+        verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService);
+    }
+
+    /**
+     * Validate that can call connect to create multiple sessions: (1) connect
+     * + success, (2) try connect again
+     */
+    @Test
+    public void testInvalidConnectSequence() throws Exception {
+        final int clientId = 4565;
+
+        InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService);
+        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareEventCallback.class);
+
+        // (1) connect + success
+        mDut.attach(mockCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
+                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        clientProxyCallback.getValue().onConnectSuccess(clientId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttached(any(WifiAwareSession.class));
+
+        // (2) connect + success
+        mDut.attach(mockCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
+                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        clientProxyCallback.getValue().onConnectSuccess(clientId + 1);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttached(any(WifiAwareSession.class));
+
+        verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService);
+    }
+
+    /*
+     * WifiAwareDiscoverySessionCallbackProxy Tests
+     */
+
+    /**
+     * Validate the publish flow: (0) connect + success, (1) publish, (2)
+     * success creates session, (3) pass through everything, (4) update publish
+     * through session, (5) terminate locally, (6) try another command -
+     * ignored.
+     */
+    @Test
+    public void testPublishFlow() throws Exception {
+        final int clientId = 4565;
+        final int sessionId = 123;
+        final ConfigRequest configRequest = new ConfigRequest.Builder().build();
+        final PublishConfig publishConfig = new PublishConfig.Builder().build();
+        final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(873);
+        final String string1 = "hey from here...";
+        final String string2 = "some other arbitrary string...";
+        final int messageId = 2123;
+        final int reason = AWARE_STATUS_ERROR;
+
+        InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
+                mockPublishSession);
+        ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
+                WifiAwareSession.class);
+        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareEventCallback.class);
+        ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareDiscoverySessionCallback.class);
+        ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
+                .forClass(WifiAwarePublishDiscoverySession.class);
+        ArgumentCaptor<WifiAwareManager.PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(
+                WifiAwareManager.PeerHandle.class);
+
+        // (0) connect + success
+        mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
+        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
+                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        clientProxyCallback.getValue().onConnectSuccess(clientId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
+        WifiAwareSession session = sessionCaptor.getValue();
+
+        // (1) publish
+        session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig),
+                sessionProxyCallback.capture());
+
+        // (2) publish session created
+        sessionProxyCallback.getValue().onSessionStarted(sessionId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
+
+        // (3) ...
+        publishSession.getValue().sendMessage(peerHandle, messageId, string1.getBytes());
+        sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(),
+                string2.getBytes());
+        sessionProxyCallback.getValue().onMessageReceived(peerHandle.peerId, string1.getBytes());
+        sessionProxyCallback.getValue().onMessageSendFail(messageId, reason);
+        sessionProxyCallback.getValue().onMessageSendSuccess(messageId);
+        mMockLooper.dispatchAll();
+
+        inOrder.verify(mockAwareService).sendMessage(eq(clientId), eq(sessionId),
+                eq(peerHandle.peerId), eq(string1.getBytes()), eq(messageId), eq(0));
+        inOrder.verify(mockSessionCallback).onServiceDiscovered(peerIdCaptor.capture(),
+                eq(string1.getBytes()), eq(string2.getBytes()));
+        assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId,
+                peerHandle.peerId);
+        inOrder.verify(mockSessionCallback).onMessageReceived(peerIdCaptor.capture(),
+                eq(string1.getBytes()));
+        assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId,
+                peerHandle.peerId);
+        inOrder.verify(mockSessionCallback).onMessageSendFailed(eq(messageId));
+        inOrder.verify(mockSessionCallback).onMessageSendSucceeded(eq(messageId));
+
+        // (4) update publish
+        publishSession.getValue().updatePublish(publishConfig);
+        sessionProxyCallback.getValue().onSessionConfigFail(reason);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockAwareService).updatePublish(eq(clientId), eq(sessionId),
+                eq(publishConfig));
+        inOrder.verify(mockSessionCallback).onSessionConfigFailed();
+
+        // (5) terminate
+        publishSession.getValue().destroy();
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockAwareService).terminateSession(clientId, sessionId);
+
+        // (6) try an update (nothing)
+        publishSession.getValue().updatePublish(publishConfig);
+        mMockLooper.dispatchAll();
+
+        verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
+                mockPublishSession);
+    }
+
+    /**
+     * Validate race condition of session terminate and session action: (1)
+     * connect, (2) publish success + terminate, (3) update.
+     */
+    @Test
+    public void testPublishRemoteTerminate() throws Exception {
+        final int clientId = 4565;
+        final int sessionId = 123;
+        final ConfigRequest configRequest = new ConfigRequest.Builder().build();
+        final PublishConfig publishConfig = new PublishConfig.Builder().build();
+        final int reason = WifiAwareDiscoverySessionCallback.TERMINATE_REASON_DONE;
+
+        InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
+                mockPublishSession);
+        ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
+                WifiAwareSession.class);
+        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareEventCallback.class);
+        ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareDiscoverySessionCallback.class);
+        ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
+                .forClass(WifiAwarePublishDiscoverySession.class);
+
+        // (1) connect successfully
+        mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
+        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
+                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        clientProxyCallback.getValue().onConnectSuccess(clientId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
+        WifiAwareSession session = sessionCaptor.getValue();
+
+        // (2) publish: successfully - then terminated
+        session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig),
+                sessionProxyCallback.capture());
+        sessionProxyCallback.getValue().onSessionStarted(sessionId);
+        sessionProxyCallback.getValue().onSessionTerminated(reason);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
+        inOrder.verify(mockSessionCallback).onSessionTerminated(reason);
+
+        // (3) failure when trying to update: NOP
+        publishSession.getValue().updatePublish(publishConfig);
+
+        verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
+                mockPublishSession);
+    }
+
+    /**
+     * Validate the subscribe flow: (0) connect + success, (1) subscribe, (2)
+     * success creates session, (3) pass through everything, (4) update
+     * subscribe through session, (5) terminate locally, (6) try another command
+     * - ignored.
+     */
+    @Test
+    public void testSubscribeFlow() throws Exception {
+        final int clientId = 4565;
+        final int sessionId = 123;
+        final ConfigRequest configRequest = new ConfigRequest.Builder().build();
+        final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
+        final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(873);
+        final String string1 = "hey from here...";
+        final String string2 = "some other arbitrary string...";
+        final int messageId = 2123;
+        final int reason = AWARE_STATUS_ERROR;
+
+        InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
+                mockSubscribeSession);
+        ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
+                WifiAwareSession.class);
+        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareEventCallback.class);
+        ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareDiscoverySessionCallback.class);
+        ArgumentCaptor<WifiAwareSubscribeDiscoverySession> subscribeSession = ArgumentCaptor
+                .forClass(WifiAwareSubscribeDiscoverySession.class);
+        ArgumentCaptor<WifiAwareManager.PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(
+                WifiAwareManager.PeerHandle.class);
+
+        // (0) connect + success
+        mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
+        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
+                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        clientProxyCallback.getValue().onConnectSuccess(clientId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
+        WifiAwareSession session = sessionCaptor.getValue();
+
+        // (1) subscribe
+        session.subscribe(subscribeConfig, mockSessionCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).subscribe(eq(clientId), eq(subscribeConfig),
+                sessionProxyCallback.capture());
+
+        // (2) subscribe session created
+        sessionProxyCallback.getValue().onSessionStarted(sessionId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockSessionCallback).onSubscribeStarted(subscribeSession.capture());
+
+        // (3) ...
+        subscribeSession.getValue().sendMessage(peerHandle, messageId, string1.getBytes());
+        sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(),
+                string2.getBytes());
+        sessionProxyCallback.getValue().onMessageReceived(peerHandle.peerId, string1.getBytes());
+        sessionProxyCallback.getValue().onMessageSendFail(messageId, reason);
+        sessionProxyCallback.getValue().onMessageSendSuccess(messageId);
+        mMockLooper.dispatchAll();
+
+        inOrder.verify(mockAwareService).sendMessage(eq(clientId), eq(sessionId),
+                eq(peerHandle.peerId), eq(string1.getBytes()), eq(messageId), eq(0));
+        inOrder.verify(mockSessionCallback).onServiceDiscovered(peerIdCaptor.capture(),
+                eq(string1.getBytes()), eq(string2.getBytes()));
+        assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId,
+                peerHandle.peerId);
+        inOrder.verify(mockSessionCallback).onMessageReceived(peerIdCaptor.capture(),
+                eq(string1.getBytes()));
+        assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId,
+                peerHandle.peerId);
+        inOrder.verify(mockSessionCallback).onMessageSendFailed(eq(messageId));
+        inOrder.verify(mockSessionCallback).onMessageSendSucceeded(eq(messageId));
+
+        // (4) update subscribe
+        subscribeSession.getValue().updateSubscribe(subscribeConfig);
+        sessionProxyCallback.getValue().onSessionConfigFail(reason);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockAwareService).updateSubscribe(eq(clientId), eq(sessionId),
+                eq(subscribeConfig));
+        inOrder.verify(mockSessionCallback).onSessionConfigFailed();
+
+        // (5) terminate
+        subscribeSession.getValue().destroy();
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockAwareService).terminateSession(clientId, sessionId);
+
+        // (6) try an update (nothing)
+        subscribeSession.getValue().updateSubscribe(subscribeConfig);
+        mMockLooper.dispatchAll();
+
+        verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
+                mockSubscribeSession);
+    }
+
+    /**
+     * Validate race condition of session terminate and session action: (1)
+     * connect, (2) subscribe success + terminate, (3) update.
+     */
+    @Test
+    public void testSubscribeRemoteTerminate() throws Exception {
+        final int clientId = 4565;
+        final int sessionId = 123;
+        final ConfigRequest configRequest = new ConfigRequest.Builder().build();
+        final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
+        final int reason = WifiAwareDiscoverySessionCallback.TERMINATE_REASON_DONE;
+
+        InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
+                mockSubscribeSession);
+        ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
+                WifiAwareSession.class);
+        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareEventCallback.class);
+        ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareDiscoverySessionCallback.class);
+        ArgumentCaptor<WifiAwareSubscribeDiscoverySession> subscribeSession = ArgumentCaptor
+                .forClass(WifiAwareSubscribeDiscoverySession.class);
+
+        // (1) connect successfully
+        mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
+        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
+                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        clientProxyCallback.getValue().onConnectSuccess(clientId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
+        WifiAwareSession session = sessionCaptor.getValue();
+
+        // (2) subscribe: successfully - then terminated
+        session.subscribe(subscribeConfig, mockSessionCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).subscribe(eq(clientId), eq(subscribeConfig),
+                sessionProxyCallback.capture());
+        sessionProxyCallback.getValue().onSessionStarted(sessionId);
+        sessionProxyCallback.getValue().onSessionTerminated(reason);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockSessionCallback).onSubscribeStarted(subscribeSession.capture());
+        inOrder.verify(mockSessionCallback).onSessionTerminated(reason);
+
+        // (3) failure when trying to update: NOP
+        subscribeSession.getValue().updateSubscribe(subscribeConfig);
+
+        verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
+                mockSubscribeSession);
+    }
+
+    /*
+     * ConfigRequest Tests
+     */
+
+    @Test
+    public void testConfigRequestBuilderDefaults() {
+        ConfigRequest configRequest = new ConfigRequest.Builder().build();
+
+        collector.checkThat("mClusterHigh", ConfigRequest.CLUSTER_ID_MAX,
+                equalTo(configRequest.mClusterHigh));
+        collector.checkThat("mClusterLow", ConfigRequest.CLUSTER_ID_MIN,
+                equalTo(configRequest.mClusterLow));
+        collector.checkThat("mMasterPreference", 0,
+                equalTo(configRequest.mMasterPreference));
+        collector.checkThat("mSupport5gBand", false, equalTo(configRequest.mSupport5gBand));
+    }
+
+    @Test
+    public void testConfigRequestBuilder() {
+        final int clusterHigh = 100;
+        final int clusterLow = 5;
+        final int masterPreference = 55;
+        final boolean supportBand5g = true;
+
+        ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh)
+                .setClusterLow(clusterLow).setMasterPreference(masterPreference)
+                .setSupport5gBand(supportBand5g)
+                .build();
+
+        collector.checkThat("mClusterHigh", clusterHigh, equalTo(configRequest.mClusterHigh));
+        collector.checkThat("mClusterLow", clusterLow, equalTo(configRequest.mClusterLow));
+        collector.checkThat("mMasterPreference", masterPreference,
+                equalTo(configRequest.mMasterPreference));
+        collector.checkThat("mSupport5gBand", supportBand5g, equalTo(configRequest.mSupport5gBand));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigRequestBuilderMasterPrefNegative() {
+        ConfigRequest.Builder builder = new ConfigRequest.Builder();
+        builder.setMasterPreference(-1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigRequestBuilderMasterPrefReserved1() {
+        new ConfigRequest.Builder().setMasterPreference(1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigRequestBuilderMasterPrefReserved255() {
+        new ConfigRequest.Builder().setMasterPreference(255);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigRequestBuilderMasterPrefTooLarge() {
+        new ConfigRequest.Builder().setMasterPreference(256);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigRequestBuilderClusterLowNegative() {
+        new ConfigRequest.Builder().setClusterLow(-1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigRequestBuilderClusterHighNegative() {
+        new ConfigRequest.Builder().setClusterHigh(-1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigRequestBuilderClusterLowAboveMax() {
+        new ConfigRequest.Builder().setClusterLow(ConfigRequest.CLUSTER_ID_MAX + 1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigRequestBuilderClusterHighAboveMax() {
+        new ConfigRequest.Builder().setClusterHigh(ConfigRequest.CLUSTER_ID_MAX + 1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigRequestBuilderClusterLowLargerThanHigh() {
+        new ConfigRequest.Builder().setClusterLow(100).setClusterHigh(5).build();
+    }
+
+    @Test
+    public void testConfigRequestParcel() {
+        final int clusterHigh = 189;
+        final int clusterLow = 25;
+        final int masterPreference = 177;
+        final boolean supportBand5g = true;
+
+        ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh)
+                .setClusterLow(clusterLow).setMasterPreference(masterPreference)
+                .setSupport5gBand(supportBand5g)
+                .build();
+
+        Parcel parcelW = Parcel.obtain();
+        configRequest.writeToParcel(parcelW, 0);
+        byte[] bytes = parcelW.marshall();
+        parcelW.recycle();
+
+        Parcel parcelR = Parcel.obtain();
+        parcelR.unmarshall(bytes, 0, bytes.length);
+        parcelR.setDataPosition(0);
+        ConfigRequest rereadConfigRequest = ConfigRequest.CREATOR.createFromParcel(parcelR);
+
+        assertEquals(configRequest, rereadConfigRequest);
+    }
+
+    /*
+     * SubscribeConfig Tests
+     */
+
+    @Test
+    public void testSubscribeConfigBuilderDefaults() {
+        SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
+
+        collector.checkThat("mServiceName", subscribeConfig.mServiceName, equalTo(null));
+        collector.checkThat("mSubscribeType", subscribeConfig.mSubscribeType,
+                equalTo(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE));
+        collector.checkThat("mSubscribeCount", subscribeConfig.mSubscribeCount, equalTo(0));
+        collector.checkThat("mTtlSec", subscribeConfig.mTtlSec, equalTo(0));
+        collector.checkThat("mMatchStyle", subscribeConfig.mMatchStyle,
+                equalTo(SubscribeConfig.MATCH_STYLE_ALL));
+        collector.checkThat("mEnableTerminateNotification",
+                subscribeConfig.mEnableTerminateNotification, equalTo(true));
+    }
+
+    @Test
+    public void testSubscribeConfigBuilder() {
+        final String serviceName = "some_service_or_other";
+        final String serviceSpecificInfo = "long arbitrary string with some info";
+        final byte[] matchFilter = {
+                0, 1, 16, 1, 22 };
+        final int subscribeType = SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE;
+        final int subscribeCount = 10;
+        final int subscribeTtl = 15;
+        final int matchStyle = SubscribeConfig.MATCH_STYLE_FIRST_ONLY;
+        final boolean enableTerminateNotification = false;
+
+        SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName)
+                .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter)
+                .setSubscribeType(subscribeType)
+                .setSubscribeCount(subscribeCount).setTtlSec(subscribeTtl).setMatchStyle(matchStyle)
+                .setTerminateNotificationEnabled(enableTerminateNotification).build();
+
+        collector.checkThat("mServiceName", serviceName.getBytes(),
+                equalTo(subscribeConfig.mServiceName));
+        collector.checkThat("mServiceSpecificInfo",
+                serviceSpecificInfo.getBytes(), equalTo(subscribeConfig.mServiceSpecificInfo));
+        collector.checkThat("mMatchFilter", matchFilter, equalTo(subscribeConfig.mMatchFilter));
+        collector.checkThat("mSubscribeType", subscribeType,
+                equalTo(subscribeConfig.mSubscribeType));
+        collector.checkThat("mSubscribeCount", subscribeCount,
+                equalTo(subscribeConfig.mSubscribeCount));
+        collector.checkThat("mTtlSec", subscribeTtl, equalTo(subscribeConfig.mTtlSec));
+        collector.checkThat("mMatchStyle", matchStyle, equalTo(subscribeConfig.mMatchStyle));
+        collector.checkThat("mEnableTerminateNotification", enableTerminateNotification,
+                equalTo(subscribeConfig.mEnableTerminateNotification));
+    }
+
+    @Test
+    public void testSubscribeConfigParcel() {
+        final String serviceName = "some_service_or_other";
+        final String serviceSpecificInfo = "long arbitrary string with some info";
+        final byte[] matchFilter = {
+                0, 1, 16, 1, 22 };
+        final int subscribeType = SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE;
+        final int subscribeCount = 10;
+        final int subscribeTtl = 15;
+        final int matchStyle = SubscribeConfig.MATCH_STYLE_FIRST_ONLY;
+        final boolean enableTerminateNotification = true;
+
+        SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName)
+                .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter)
+                .setSubscribeType(subscribeType)
+                .setSubscribeCount(subscribeCount).setTtlSec(subscribeTtl).setMatchStyle(matchStyle)
+                .setTerminateNotificationEnabled(enableTerminateNotification).build();
+
+        Parcel parcelW = Parcel.obtain();
+        subscribeConfig.writeToParcel(parcelW, 0);
+        byte[] bytes = parcelW.marshall();
+        parcelW.recycle();
+
+        Parcel parcelR = Parcel.obtain();
+        parcelR.unmarshall(bytes, 0, bytes.length);
+        parcelR.setDataPosition(0);
+        SubscribeConfig rereadSubscribeConfig = SubscribeConfig.CREATOR.createFromParcel(parcelR);
+
+        assertEquals(subscribeConfig, rereadSubscribeConfig);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testSubscribeConfigBuilderBadSubscribeType() {
+        new SubscribeConfig.Builder().setSubscribeType(10);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testSubscribeConfigBuilderNegativeCount() {
+        new SubscribeConfig.Builder().setSubscribeCount(-1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testSubscribeConfigBuilderNegativeTtl() {
+        new SubscribeConfig.Builder().setTtlSec(-100);
+    }
+
+    /**
+     * Validate that a bad match style configuration throws an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testSubscribeConfigBuilderBadMatchStyle() {
+        new SubscribeConfig.Builder().setMatchStyle(10);
+    }
+
+    /*
+     * PublishConfig Tests
+     */
+
+    @Test
+    public void testPublishConfigBuilderDefaults() {
+        PublishConfig publishConfig = new PublishConfig.Builder().build();
+
+        collector.checkThat("mServiceName", publishConfig.mServiceName, equalTo(null));
+        collector.checkThat("mPublishType", publishConfig.mPublishType,
+                equalTo(PublishConfig.PUBLISH_TYPE_UNSOLICITED));
+        collector.checkThat("mPublishCount", publishConfig.mPublishCount, equalTo(0));
+        collector.checkThat("mTtlSec", publishConfig.mTtlSec, equalTo(0));
+        collector.checkThat("mEnableTerminateNotification",
+                publishConfig.mEnableTerminateNotification, equalTo(true));
+    }
+
+    @Test
+    public void testPublishConfigBuilder() {
+        final String serviceName = "some_service_or_other";
+        final String serviceSpecificInfo = "long arbitrary string with some info";
+        final byte[] matchFilter = {
+                0, 1, 16, 1, 22 };
+        final int publishType = PublishConfig.PUBLISH_TYPE_SOLICITED;
+        final int publishCount = 10;
+        final int publishTtl = 15;
+        final boolean enableTerminateNotification = false;
+
+        PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName)
+                .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter)
+                .setPublishType(publishType)
+                .setPublishCount(publishCount).setTtlSec(publishTtl)
+                .setTerminateNotificationEnabled(enableTerminateNotification).build();
+
+        collector.checkThat("mServiceName", serviceName.getBytes(),
+                equalTo(publishConfig.mServiceName));
+        collector.checkThat("mServiceSpecificInfo",
+                serviceSpecificInfo.getBytes(), equalTo(publishConfig.mServiceSpecificInfo));
+        collector.checkThat("mMatchFilter", matchFilter, equalTo(publishConfig.mMatchFilter));
+        collector.checkThat("mPublishType", publishType, equalTo(publishConfig.mPublishType));
+        collector.checkThat("mPublishCount", publishCount, equalTo(publishConfig.mPublishCount));
+        collector.checkThat("mTtlSec", publishTtl, equalTo(publishConfig.mTtlSec));
+        collector.checkThat("mEnableTerminateNotification", enableTerminateNotification,
+                equalTo(publishConfig.mEnableTerminateNotification));
+    }
+
+    @Test
+    public void testPublishConfigParcel() {
+        final String serviceName = "some_service_or_other";
+        final String serviceSpecificInfo = "long arbitrary string with some info";
+        final byte[] matchFilter = {
+                0, 1, 16, 1, 22 };
+        final int publishType = PublishConfig.PUBLISH_TYPE_SOLICITED;
+        final int publishCount = 10;
+        final int publishTtl = 15;
+        final boolean enableTerminateNotification = false;
+
+        PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName)
+                .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter)
+                .setPublishType(publishType)
+                .setPublishCount(publishCount).setTtlSec(publishTtl)
+                .setTerminateNotificationEnabled(enableTerminateNotification).build();
+
+        Parcel parcelW = Parcel.obtain();
+        publishConfig.writeToParcel(parcelW, 0);
+        byte[] bytes = parcelW.marshall();
+        parcelW.recycle();
+
+        Parcel parcelR = Parcel.obtain();
+        parcelR.unmarshall(bytes, 0, bytes.length);
+        parcelR.setDataPosition(0);
+        PublishConfig rereadPublishConfig = PublishConfig.CREATOR.createFromParcel(parcelR);
+
+        assertEquals(publishConfig, rereadPublishConfig);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testPublishConfigBuilderBadPublishType() {
+        new PublishConfig.Builder().setPublishType(5);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testPublishConfigBuilderNegativeCount() {
+        new PublishConfig.Builder().setPublishCount(-4);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testPublishConfigBuilderNegativeTtl() {
+        new PublishConfig.Builder().setTtlSec(-10);
+    }
+
+    /*
+     * Ranging tests
+     */
+
+    /**
+     * Validate ranging + success flow: (1) connect, (2) create a (publish) session, (3) start
+     * ranging, (4) ranging success callback, (5) ranging aborted callback ignored (since
+     * listener removed).
+     */
+    @Test
+    public void testRangingCallbacks() throws Exception {
+        final int clientId = 4565;
+        final int sessionId = 123;
+        final int rangingId = 3482;
+        final ConfigRequest configRequest = new ConfigRequest.Builder().build();
+        final PublishConfig publishConfig = new PublishConfig.Builder().build();
+        final RttManager.RttParams rttParams = new RttManager.RttParams();
+        rttParams.deviceType = RttManager.RTT_PEER_NAN;
+        rttParams.bssid = Integer.toString(1234);
+        final RttManager.RttResult rttResults = new RttManager.RttResult();
+        rttResults.distance = 10;
+
+        when(mockAwareService.startRanging(anyInt(), anyInt(),
+                any(RttManager.ParcelableRttParams.class))).thenReturn(rangingId);
+
+        InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
+                mockPublishSession, mockRttListener);
+        ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
+                WifiAwareSession.class);
+        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareEventCallback.class);
+        ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareDiscoverySessionCallback.class);
+        ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
+                .forClass(WifiAwarePublishDiscoverySession.class);
+        ArgumentCaptor<RttManager.ParcelableRttParams> rttParamCaptor = ArgumentCaptor
+                .forClass(RttManager.ParcelableRttParams.class);
+        ArgumentCaptor<RttManager.RttResult[]> rttResultsCaptor = ArgumentCaptor
+                .forClass(RttManager.RttResult[].class);
+
+        // (1) connect successfully
+        mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
+        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
+                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        clientProxyCallback.getValue().onConnectSuccess(clientId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
+        WifiAwareSession session = sessionCaptor.getValue();
+
+        // (2) publish successfully
+        session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig),
+                sessionProxyCallback.capture());
+        sessionProxyCallback.getValue().onSessionStarted(sessionId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
+
+        // (3) start ranging
+        publishSession.getValue().startRanging(new RttManager.RttParams[]{rttParams},
+                mockRttListener);
+        inOrder.verify(mockAwareService).startRanging(eq(clientId), eq(sessionId),
+                rttParamCaptor.capture());
+        collector.checkThat("RttParams.deviceType", rttParams.deviceType,
+                equalTo(rttParamCaptor.getValue().mParams[0].deviceType));
+        collector.checkThat("RttParams.bssid", rttParams.bssid,
+                equalTo(rttParamCaptor.getValue().mParams[0].bssid));
+
+        // (4) ranging success callback
+        clientProxyCallback.getValue().onRangingSuccess(rangingId,
+                new RttManager.ParcelableRttResults(new RttManager.RttResult[] { rttResults }));
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockRttListener).onSuccess(rttResultsCaptor.capture());
+        collector.checkThat("RttResult.distance", rttResults.distance,
+                equalTo(rttResultsCaptor.getValue()[0].distance));
+
+        // (5) ranging aborted callback (should be ignored since listener cleared on first callback)
+        clientProxyCallback.getValue().onRangingAborted(rangingId);
+        mMockLooper.dispatchAll();
+
+        verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
+                mockPublishSession, mockRttListener);
+    }
+
+    /*
+     * Data-path tests
+     */
+
+    /**
+     * Validate that correct network specifier is generated for client-based data-path.
+     */
+    @Test
+    public void testNetworkSpecifierWithClient() throws Exception {
+        final int clientId = 4565;
+        final int sessionId = 123;
+        final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(123412);
+        final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
+        final String token = "Some arbitrary token string - can really be anything";
+        final ConfigRequest configRequest = new ConfigRequest.Builder().build();
+        final PublishConfig publishConfig = new PublishConfig.Builder().build();
+
+        String tokenB64 = Base64.encodeToString(token.getBytes(), Base64.DEFAULT);
+
+        ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
+                WifiAwareSession.class);
+        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareEventCallback.class);
+        ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareDiscoverySessionCallback.class);
+        ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
+                .forClass(WifiAwarePublishDiscoverySession.class);
+
+        InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
+                mockPublishSession, mockRttListener);
+
+        // (1) connect successfully
+        mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
+        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
+                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        clientProxyCallback.getValue().onConnectSuccess(clientId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
+        WifiAwareSession session = sessionCaptor.getValue();
+
+        // (2) publish successfully
+        session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig),
+                sessionProxyCallback.capture());
+        sessionProxyCallback.getValue().onSessionStarted(sessionId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
+
+        // (3) request a network specifier from the session
+        String networkSpecifier = publishSession.getValue().createNetworkSpecifier(role, peerHandle,
+                token.getBytes());
+
+        // validate format
+        JSONObject jsonObject = new JSONObject(networkSpecifier);
+        collector.checkThat("role", role,
+                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE)));
+        collector.checkThat("client_id", clientId,
+                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID)));
+        collector.checkThat("session_id", sessionId,
+                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID)));
+        collector.checkThat("peer_id", peerHandle.peerId,
+                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID)));
+        collector.checkThat("token", tokenB64,
+                equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_TOKEN)));
+
+        verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
+                mockPublishSession, mockRttListener);
+    }
+
+    /**
+     * Validate that correct network specifier is generated for a direct data-path (i.e.
+     * specifying MAC address as opposed to a client-based oqaque specification).
+     */
+    @Test
+    public void testNetworkSpecifierDirect() throws Exception {
+        final int clientId = 134;
+        final ConfigRequest configRequest = new ConfigRequest.Builder().build();
+        final byte[] someMac = HexEncoding.decode("000102030405".toCharArray(), false);
+        final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
+        final String token = "Some arbitrary token string - can really be anything";
+
+        String tokenB64 = Base64.encodeToString(token.getBytes(), Base64.DEFAULT);
+
+        ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
+                WifiAwareSession.class);
+        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareEventCallback.class);
+
+        InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
+                mockPublishSession, mockRttListener);
+
+        // (1) connect successfully
+        mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
+        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
+                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        clientProxyCallback.getValue().onConnectSuccess(clientId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
+        WifiAwareSession session = sessionCaptor.getValue();
+
+        /* (2) request a direct network specifier*/
+        String networkSpecifier = session.createNetworkSpecifier(role, someMac, token.getBytes());
+
+        /* validate format*/
+        JSONObject jsonObject = new JSONObject(networkSpecifier);
+        collector.checkThat("role", role,
+                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE)));
+        collector.checkThat("client_id", clientId,
+                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID)));
+        collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode(
+                jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(),
+                false)));
+        collector.checkThat("token", tokenB64,
+                equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_TOKEN)));
+
+        verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
+                mockPublishSession, mockRttListener);
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index b4a3acf..2350d32 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -33,6 +33,11 @@
 @SmallTest
 public class PasspointConfigurationTest {
 
+    /**
+     * Utility function for creating a {@link android.net.wifi.hotspot2.pps.HomeSP}.
+     *
+     * @return {@link android.net.wifi.hotspot2.pps.HomeSP}
+     */
     private static HomeSP createHomeSp() {
         HomeSP homeSp = new HomeSP();
         homeSp.fqdn = "fqdn";
@@ -41,6 +46,11 @@
         return homeSp;
     }
 
+    /**
+     * Utility function for creating a {@link android.net.wifi.hotspot2.pps.Credential}.
+     *
+     * @return {@link android.net.wifi.hotspot2.pps.Credential}
+     */
     private static Credential createCredential() {
         Credential cred = new Credential();
         cred.realm = "realm";
@@ -55,6 +65,12 @@
         return cred;
     }
 
+    /**
+     * Verify parcel write and read consistency for the given configuration.
+     *
+     * @param writeConfig The configuration to verify
+     * @throws Exception
+     */
     private static void verifyParcel(PasspointConfiguration writeConfig) throws Exception {
         Parcel parcel = Parcel.obtain();
         writeConfig.writeToParcel(parcel, 0);
@@ -77,6 +93,7 @@
 
     /**
      * Verify parcel read/write for a configuration that contained both HomeSP and Credential.
+     *
      * @throws Exception
      */
     @Test
@@ -158,4 +175,30 @@
         config.credential = createCredential();
         assertTrue(config.validate());
     }
-}
\ No newline at end of file
+
+    /**
+     * Verify that copy constructor works when pass in a null source.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void validateCopyConstructorWithNullSource() throws Exception {
+        PasspointConfiguration copyConfig = new PasspointConfiguration(null);
+        PasspointConfiguration defaultConfig = new PasspointConfiguration();
+        assertTrue(copyConfig.equals(defaultConfig));
+    }
+
+    /**
+     * Verify that copy constructor works when pass in a valid source.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void validateCopyConstructorWithValidSource() throws Exception {
+        PasspointConfiguration sourceConfig = new PasspointConfiguration();
+        sourceConfig.homeSp = createHomeSp();
+        sourceConfig.credential = createCredential();
+        PasspointConfiguration copyConfig = new PasspointConfiguration(sourceConfig);
+        assertTrue(copyConfig.equals(sourceConfig));
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
index 223aa52..9c8b749 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
@@ -470,4 +470,52 @@
         cred.simCredential.eapType = EAPConstants.EAP_SIM;
         assertFalse(cred.validate());
     }
+
+    /**
+     * Verify that copy constructor works when pass in a null source.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void validateCopyConstructorWithNullSource() throws Exception {
+        Credential copyCred = new Credential(null);
+        Credential defaultCred = new Credential();
+        assertTrue(copyCred.equals(defaultCred));
+    }
+
+    /**
+     * Verify that copy constructor works when pass in a source with user credential.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void validateCopyConstructorWithSourceWithUserCred() throws Exception {
+        Credential sourceCred = createCredentialWithUserCredential();
+        Credential copyCred = new Credential(sourceCred);
+        assertTrue(copyCred.equals(sourceCred));
+    }
+
+    /**
+     * Verify that copy constructor works when pass in a source with certificate credential.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void validateCopyConstructorWithSourceWithCertCred() throws Exception {
+        Credential sourceCred = createCredentialWithCertificateCredential();
+        Credential copyCred = new Credential(sourceCred);
+        assertTrue(copyCred.equals(sourceCred));
+    }
+
+    /**
+     * Verify that copy constructor works when pass in a source with SIM credential.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void validateCopyConstructorWithSourceWithSimCred() throws Exception {
+        Credential sourceCred = createCredentialWithSimCredential();
+        Credential copyCred = new Credential(sourceCred);
+        assertTrue(copyCred.equals(sourceCred));
+    }
 }
\ No newline at end of file
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
index fff1477..c707993 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
@@ -118,4 +118,31 @@
         homeSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
         assertTrue(homeSp.validate());
     }
+
+    /**
+     * Verify that copy constructor works when pass in a null source.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void validateCopyConstructorFromNullSource() throws Exception {
+        HomeSP copySp = new HomeSP(null);
+        HomeSP defaultSp = new HomeSP();
+        assertTrue(copySp.equals(defaultSp));
+    }
+
+    /**
+     * Verify that copy constructor works when pass in a valid source.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void validateCopyConstructorFromValidSource() throws Exception {
+        HomeSP sourceSp = new HomeSP();
+        sourceSp.fqdn = "fqdn";
+        sourceSp.friendlyName = "friendlyName";
+        sourceSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
+        HomeSP copySp = new HomeSP(sourceSp);
+        assertTrue(copySp.equals(sourceSp));
+    }
 }