Merge "Better aidl generated dependency" into klp-dev
diff --git a/api/current.txt b/api/current.txt
index 936eb39..27a8480 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5500,10 +5500,13 @@
     method public void onLowMemory();
     method public void onTrimMemory(int);
     method public android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
+    method public android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
+    method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method protected final android.os.ParcelFileDescriptor openFileHelper(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
     method public android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
+    method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
     method protected final void setPathPermissions(android.content.pm.PathPermission[]);
@@ -5527,8 +5530,11 @@
     method public java.lang.String getType(android.net.Uri) throws android.os.RemoteException;
     method public android.net.Uri insert(android.net.Uri, android.content.ContentValues) throws android.os.RemoteException;
     method public android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method public android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
     method public boolean release();
@@ -5616,11 +5622,14 @@
     method public void notifyChange(android.net.Uri, android.database.ContentObserver);
     method public void notifyChange(android.net.Uri, android.database.ContentObserver, boolean);
     method public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
+    method public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public final android.os.ParcelFileDescriptor openFileDescriptor(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
+    method public final android.os.ParcelFileDescriptor openFileDescriptor(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public final java.io.InputStream openInputStream(android.net.Uri) throws java.io.FileNotFoundException;
     method public final java.io.OutputStream openOutputStream(android.net.Uri) throws java.io.FileNotFoundException;
     method public final java.io.OutputStream openOutputStream(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
     method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
+    method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
     method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
     method public final void registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver);
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index cf627d7..b9121c7 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -16,11 +16,9 @@
 
 package android.content;
 
-import static android.content.pm.PackageManager.GET_PROVIDERS;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 import android.app.AppOpsManager;
-import android.content.pm.PackageManager;
 import android.content.pm.PathPermission;
 import android.content.pm.ProviderInfo;
 import android.content.res.AssetFileDescriptor;
@@ -261,17 +259,21 @@
         }
 
         @Override
-        public ParcelFileDescriptor openFile(String callingPkg, Uri uri, String mode)
+        public ParcelFileDescriptor openFile(
+                String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
                 throws FileNotFoundException {
             enforceFilePermission(callingPkg, uri, mode);
-            return ContentProvider.this.openFile(uri, mode);
+            return ContentProvider.this.openFile(
+                    uri, mode, CancellationSignal.fromTransport(cancellationSignal));
         }
 
         @Override
-        public AssetFileDescriptor openAssetFile(String callingPkg, Uri uri, String mode)
+        public AssetFileDescriptor openAssetFile(
+                String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
                 throws FileNotFoundException {
             enforceFilePermission(callingPkg, uri, mode);
-            return ContentProvider.this.openAssetFile(uri, mode);
+            return ContentProvider.this.openAssetFile(
+                    uri, mode, CancellationSignal.fromTransport(cancellationSignal));
         }
 
         @Override
@@ -286,9 +288,10 @@
 
         @Override
         public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
-                Bundle opts) throws FileNotFoundException {
+                Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
             enforceFilePermission(callingPkg, uri, "r");
-            return ContentProvider.this.openTypedAssetFile(uri, mimeType, opts);
+            return ContentProvider.this.openTypedAssetFile(
+                    uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
         }
 
         @Override
@@ -874,6 +877,18 @@
      * <p>The returned ParcelFileDescriptor is owned by the caller, so it is
      * their responsibility to close it when done.  That is, the implementation
      * of this method should create a new ParcelFileDescriptor for each call.
+     * <p>
+     * If opened with the exclusive "r" or "w" modes, the returned
+     * ParcelFileDescriptor can be a pipe or socket pair to enable streaming
+     * of data. Opening with the "rw" or "rwt" modes implies a file on disk that
+     * supports seeking.
+     * <p>
+     * If you need to detect when the returned ParcelFileDescriptor has been
+     * closed, or if the remote process has crashed or encountered some other
+     * error, you can use {@link ParcelFileDescriptor#open(File, int,
+     * android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener)},
+     * {@link ParcelFileDescriptor#createReliablePipe()}, or
+     * {@link ParcelFileDescriptor#createReliableSocketPair()}.
      *
      * <p class="note">For use in Intents, you will want to implement {@link #getType}
      * to return the appropriate MIME type for the data returned here with
@@ -911,6 +926,74 @@
     }
 
     /**
+     * Override this to handle requests to open a file blob.
+     * The default implementation always throws {@link FileNotFoundException}.
+     * This method can be called from multiple threads, as described in
+     * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
+     * and Threads</a>.
+     *
+     * <p>This method returns a ParcelFileDescriptor, which is returned directly
+     * to the caller.  This way large data (such as images and documents) can be
+     * returned without copying the content.
+     *
+     * <p>The returned ParcelFileDescriptor is owned by the caller, so it is
+     * their responsibility to close it when done.  That is, the implementation
+     * of this method should create a new ParcelFileDescriptor for each call.
+     * <p>
+     * If opened with the exclusive "r" or "w" modes, the returned
+     * ParcelFileDescriptor can be a pipe or socket pair to enable streaming
+     * of data. Opening with the "rw" or "rwt" modes implies a file on disk that
+     * supports seeking.
+     * <p>
+     * If you need to detect when the returned ParcelFileDescriptor has been
+     * closed, or if the remote process has crashed or encountered some other
+     * error, you can use {@link ParcelFileDescriptor#open(File, int,
+     * android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener)},
+     * {@link ParcelFileDescriptor#createReliablePipe()}, or
+     * {@link ParcelFileDescriptor#createReliableSocketPair()}.
+     *
+     * <p class="note">For use in Intents, you will want to implement {@link #getType}
+     * to return the appropriate MIME type for the data returned here with
+     * the same URI.  This will allow intent resolution to automatically determine the data MIME
+     * type and select the appropriate matching targets as part of its operation.</p>
+     *
+     * <p class="note">For better interoperability with other applications, it is recommended
+     * that for any URIs that can be opened, you also support queries on them
+     * containing at least the columns specified by {@link android.provider.OpenableColumns}.
+     * You may also want to support other common columns if you have additional meta-data
+     * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED}
+     * in {@link android.provider.MediaStore.MediaColumns}.</p>
+     *
+     * @param uri The URI whose file is to be opened.
+     * @param mode Access mode for the file. May be "r" for read-only access,
+     *            "w" for write-only access, "rw" for read and write access, or
+     *            "rwt" for read and write access that truncates any existing
+     *            file.
+     * @param signal A signal to cancel the operation in progress, or
+     *            {@code null} if none. For example, if you are downloading a
+     *            file from the network to service a "rw" mode request, you
+     *            should periodically call
+     *            {@link CancellationSignal#throwIfCanceled()} to check whether
+     *            the client has canceled the request and abort the download.
+     *
+     * @return Returns a new ParcelFileDescriptor which you can use to access
+     * the file.
+     *
+     * @throws FileNotFoundException Throws FileNotFoundException if there is
+     * no file associated with the given URI or the mode is invalid.
+     * @throws SecurityException Throws SecurityException if the caller does
+     * not have permission to access the file.
+     *
+     * @see #openAssetFile(Uri, String)
+     * @see #openFileHelper(Uri, String)
+     * @see #getType(android.net.Uri)
+     */
+    public ParcelFileDescriptor openFile(Uri uri, String mode, CancellationSignal signal)
+            throws FileNotFoundException {
+        return openFile(uri, mode);
+    }
+
+    /**
      * This is like {@link #openFile}, but can be implemented by providers
      * that need to be able to return sub-sections of files, often assets
      * inside of their .apk.
@@ -924,11 +1007,14 @@
      * {@link ContentResolver#openInputStream ContentResolver.openInputStream}
      * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
      * methods.
+     * <p>
+     * The returned AssetFileDescriptor can be a pipe or socket pair to enable
+     * streaming of data.
      *
      * <p class="note">If you are implementing this to return a full file, you
      * should create the AssetFileDescriptor with
      * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with
-     * applications that can not handle sub-sections of files.</p>
+     * applications that cannot handle sub-sections of files.</p>
      *
      * <p class="note">For use in Intents, you will want to implement {@link #getType}
      * to return the appropriate MIME type for the data returned here with
@@ -965,6 +1051,68 @@
     }
 
     /**
+     * This is like {@link #openFile}, but can be implemented by providers
+     * that need to be able to return sub-sections of files, often assets
+     * inside of their .apk.
+     * This method can be called from multiple threads, as described in
+     * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
+     * and Threads</a>.
+     *
+     * <p>If you implement this, your clients must be able to deal with such
+     * file slices, either directly with
+     * {@link ContentResolver#openAssetFileDescriptor}, or by using the higher-level
+     * {@link ContentResolver#openInputStream ContentResolver.openInputStream}
+     * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
+     * methods.
+     * <p>
+     * The returned AssetFileDescriptor can be a pipe or socket pair to enable
+     * streaming of data.
+     *
+     * <p class="note">If you are implementing this to return a full file, you
+     * should create the AssetFileDescriptor with
+     * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with
+     * applications that cannot handle sub-sections of files.</p>
+     *
+     * <p class="note">For use in Intents, you will want to implement {@link #getType}
+     * to return the appropriate MIME type for the data returned here with
+     * the same URI.  This will allow intent resolution to automatically determine the data MIME
+     * type and select the appropriate matching targets as part of its operation.</p>
+     *
+     * <p class="note">For better interoperability with other applications, it is recommended
+     * that for any URIs that can be opened, you also support queries on them
+     * containing at least the columns specified by {@link android.provider.OpenableColumns}.</p>
+     *
+     * @param uri The URI whose file is to be opened.
+     * @param mode Access mode for the file.  May be "r" for read-only access,
+     * "w" for write-only access (erasing whatever data is currently in
+     * the file), "wa" for write-only access to append to any existing data,
+     * "rw" for read and write access on any existing data, and "rwt" for read
+     * and write access that truncates any existing file.
+     * @param signal A signal to cancel the operation in progress, or
+     *            {@code null} if none. For example, if you are downloading a
+     *            file from the network to service a "rw" mode request, you
+     *            should periodically call
+     *            {@link CancellationSignal#throwIfCanceled()} to check whether
+     *            the client has canceled the request and abort the download.
+     *
+     * @return Returns a new AssetFileDescriptor which you can use to access
+     * the file.
+     *
+     * @throws FileNotFoundException Throws FileNotFoundException if there is
+     * no file associated with the given URI or the mode is invalid.
+     * @throws SecurityException Throws SecurityException if the caller does
+     * not have permission to access the file.
+     *
+     * @see #openFile(Uri, String)
+     * @see #openFileHelper(Uri, String)
+     * @see #getType(android.net.Uri)
+     */
+    public AssetFileDescriptor openAssetFile(Uri uri, String mode, CancellationSignal signal)
+            throws FileNotFoundException {
+        return openAssetFile(uri, mode);
+    }
+
+    /**
      * Convenience for subclasses that wish to implement {@link #openFile}
      * by looking up a column named "_data" at the given URI.
      *
@@ -1041,6 +1189,9 @@
      *
      * <p>See {@link ClipData} for examples of the use and implementation
      * of this method.
+     * <p>
+     * The returned AssetFileDescriptor can be a pipe or socket pair to enable
+     * streaming of data.
      *
      * <p class="note">For better interoperability with other applications, it is recommended
      * that for any URIs that can be opened, you also support queries on them
@@ -1086,6 +1237,64 @@
         throw new FileNotFoundException("Can't open " + uri + " as type " + mimeTypeFilter);
     }
 
+
+    /**
+     * Called by a client to open a read-only stream containing data of a
+     * particular MIME type.  This is like {@link #openAssetFile(Uri, String)},
+     * except the file can only be read-only and the content provider may
+     * perform data conversions to generate data of the desired type.
+     *
+     * <p>The default implementation compares the given mimeType against the
+     * result of {@link #getType(Uri)} and, if they match, simply calls
+     * {@link #openAssetFile(Uri, String)}.
+     *
+     * <p>See {@link ClipData} for examples of the use and implementation
+     * of this method.
+     * <p>
+     * The returned AssetFileDescriptor can be a pipe or socket pair to enable
+     * streaming of data.
+     *
+     * <p class="note">For better interoperability with other applications, it is recommended
+     * that for any URIs that can be opened, you also support queries on them
+     * containing at least the columns specified by {@link android.provider.OpenableColumns}.
+     * You may also want to support other common columns if you have additional meta-data
+     * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED}
+     * in {@link android.provider.MediaStore.MediaColumns}.</p>
+     *
+     * @param uri The data in the content provider being queried.
+     * @param mimeTypeFilter The type of data the client desires.  May be
+     * a pattern, such as *\/*, if the caller does not have specific type
+     * requirements; in this case the content provider will pick its best
+     * type matching the pattern.
+     * @param opts Additional options from the client.  The definitions of
+     * these are specific to the content provider being called.
+     * @param signal A signal to cancel the operation in progress, or
+     *            {@code null} if none. For example, if you are downloading a
+     *            file from the network to service a "rw" mode request, you
+     *            should periodically call
+     *            {@link CancellationSignal#throwIfCanceled()} to check whether
+     *            the client has canceled the request and abort the download.
+     *
+     * @return Returns a new AssetFileDescriptor from which the client can
+     * read data of the desired type.
+     *
+     * @throws FileNotFoundException Throws FileNotFoundException if there is
+     * no file associated with the given URI or the mode is invalid.
+     * @throws SecurityException Throws SecurityException if the caller does
+     * not have permission to access the data.
+     * @throws IllegalArgumentException Throws IllegalArgumentException if the
+     * content provider does not support the requested MIME type.
+     *
+     * @see #getStreamTypes(Uri, String)
+     * @see #openAssetFile(Uri, String)
+     * @see ClipDescription#compareMimeTypes(String, String)
+     */
+    public AssetFileDescriptor openTypedAssetFile(
+            Uri uri, String mimeTypeFilter, Bundle opts, CancellationSignal signal)
+            throws FileNotFoundException {
+        return openTypedAssetFile(uri, mimeTypeFilter, opts);
+    }
+
     /**
      * Interface to write a stream of data to a pipe.  Use with
      * {@link ContentProvider#openPipeHelper}.
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 8dffac7..024a521 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -63,14 +63,7 @@
     /** See {@link ContentProvider#query ContentProvider.query} */
     public Cursor query(Uri url, String[] projection, String selection,
             String[] selectionArgs, String sortOrder) throws RemoteException {
-        try {
-            return query(url, projection, selection,  selectionArgs, sortOrder, null);
-        } catch (DeadObjectException e) {
-            if (!mStable) {
-                mContentResolver.unstableProviderDied(mContentProvider);
-            }
-            throw e;
-        }
+        return query(url, projection, selection,  selectionArgs, sortOrder, null);
     }
 
     /** See {@link ContentProvider#query ContentProvider.query} */
@@ -177,8 +170,25 @@
      */
     public ParcelFileDescriptor openFile(Uri url, String mode)
             throws RemoteException, FileNotFoundException {
+        return openFile(url, mode, null);
+    }
+
+    /**
+     * See {@link ContentProvider#openFile ContentProvider.openFile}.  Note that
+     * this <em>does not</em>
+     * take care of non-content: URIs such as file:.  It is strongly recommended
+     * you use the {@link ContentResolver#openFileDescriptor
+     * ContentResolver.openFileDescriptor} API instead.
+     */
+    public ParcelFileDescriptor openFile(Uri url, String mode, CancellationSignal signal)
+            throws RemoteException, FileNotFoundException {
+        ICancellationSignal remoteSignal = null;
+        if (signal != null) {
+            remoteSignal = mContentProvider.createCancellationSignal();
+            signal.setRemote(remoteSignal);
+        }
         try {
-            return mContentProvider.openFile(mPackageName, url, mode);
+            return mContentProvider.openFile(mPackageName, url, mode, remoteSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -196,8 +206,25 @@
      */
     public AssetFileDescriptor openAssetFile(Uri url, String mode)
             throws RemoteException, FileNotFoundException {
+        return openAssetFile(url, mode, null);
+    }
+
+    /**
+     * See {@link ContentProvider#openAssetFile ContentProvider.openAssetFile}.
+     * Note that this <em>does not</em>
+     * take care of non-content: URIs such as file:.  It is strongly recommended
+     * you use the {@link ContentResolver#openAssetFileDescriptor
+     * ContentResolver.openAssetFileDescriptor} API instead.
+     */
+    public AssetFileDescriptor openAssetFile(Uri url, String mode, CancellationSignal signal)
+            throws RemoteException, FileNotFoundException {
+        ICancellationSignal remoteSignal = null;
+        if (signal != null) {
+            remoteSignal = mContentProvider.createCancellationSignal();
+            signal.setRemote(remoteSignal);
+        }
         try {
-            return mContentProvider.openAssetFile(mPackageName, url, mode);
+            return mContentProvider.openAssetFile(mPackageName, url, mode, remoteSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -208,10 +235,22 @@
 
     /** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
     public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
-            String mimeType, Bundle opts)
+            String mimeType, Bundle opts) throws RemoteException, FileNotFoundException {
+        return openTypedAssetFileDescriptor(uri, mimeType, opts, null);
+    }
+
+    /** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
+    public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
+            String mimeType, Bundle opts, CancellationSignal signal)
             throws RemoteException, FileNotFoundException {
+        ICancellationSignal remoteSignal = null;
+        if (signal != null) {
+            remoteSignal = mContentProvider.createCancellationSignal();
+            signal.setRemote(remoteSignal);
+        }
         try {
-            return mContentProvider.openTypedAssetFile(mPackageName, uri, mimeType, opts);
+            return mContentProvider.openTypedAssetFile(
+                    mPackageName, uri, mimeType, opts, remoteSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index 6f822c1..744e68c 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -18,22 +18,20 @@
 
 import android.content.res.AssetFileDescriptor;
 import android.database.BulkCursorDescriptor;
-import android.database.BulkCursorNative;
 import android.database.BulkCursorToCursorAdaptor;
 import android.database.Cursor;
 import android.database.CursorToBulkCursorAdaptor;
 import android.database.DatabaseUtils;
-import android.database.IBulkCursor;
 import android.database.IContentObserver;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.ICancellationSignal;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.RemoteException;
 
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
@@ -227,9 +225,11 @@
                     String callingPkg = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     String mode = data.readString();
+                    ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
+                            data.readStrongBinder());
 
                     ParcelFileDescriptor fd;
-                    fd = openFile(callingPkg, url, mode);
+                    fd = openFile(callingPkg, url, mode, signal);
                     reply.writeNoException();
                     if (fd != null) {
                         reply.writeInt(1);
@@ -247,9 +247,11 @@
                     String callingPkg = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     String mode = data.readString();
+                    ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
+                            data.readStrongBinder());
 
                     AssetFileDescriptor fd;
-                    fd = openAssetFile(callingPkg, url, mode);
+                    fd = openAssetFile(callingPkg, url, mode, signal);
                     reply.writeNoException();
                     if (fd != null) {
                         reply.writeInt(1);
@@ -296,9 +298,11 @@
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     String mimeType = data.readString();
                     Bundle opts = data.readBundle();
+                    ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
+                            data.readStrongBinder());
 
                     AssetFileDescriptor fd;
-                    fd = openTypedAssetFile(callingPkg, url, mimeType, opts);
+                    fd = openTypedAssetFile(callingPkg, url, mimeType, opts, signal);
                     reply.writeNoException();
                     if (fd != null) {
                         reply.writeInt(1);
@@ -538,7 +542,9 @@
         }
     }
 
-    public ParcelFileDescriptor openFile(String callingPkg, Uri url, String mode)
+    @Override
+    public ParcelFileDescriptor openFile(
+            String callingPkg, Uri url, String mode, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -548,6 +554,7 @@
             data.writeString(callingPkg);
             url.writeToParcel(data, 0);
             data.writeString(mode);
+            data.writeStrongBinder(signal != null ? signal.asBinder() : null);
 
             mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0);
 
@@ -561,7 +568,9 @@
         }
     }
 
-    public AssetFileDescriptor openAssetFile(String callingPkg, Uri url, String mode)
+    @Override
+    public AssetFileDescriptor openAssetFile(
+            String callingPkg, Uri url, String mode, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -571,6 +580,7 @@
             data.writeString(callingPkg);
             url.writeToParcel(data, 0);
             data.writeString(mode);
+            data.writeStrongBinder(signal != null ? signal.asBinder() : null);
 
             mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0);
 
@@ -629,8 +639,9 @@
         }
     }
 
+    @Override
     public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
-            Bundle opts) throws RemoteException, FileNotFoundException {
+            Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
@@ -640,6 +651,7 @@
             url.writeToParcel(data, 0);
             data.writeString(mimeType);
             data.writeBundle(opts);
+            data.writeStrongBinder(signal != null ? signal.asBinder() : null);
 
             mRemote.transact(IContentProvider.OPEN_TYPED_ASSET_FILE_TRANSACTION, data, reply, 0);
 
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 5cabfeef..a761a89 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -55,7 +55,6 @@
 import java.util.List;
 import java.util.Random;
 
-
 /**
  * This class provides applications access to the content model.
  *
@@ -328,7 +327,7 @@
      * content URL can be returned when opened as as stream with
      * {@link #openTypedAssetFileDescriptor}.  Note that the types here are
      * not necessarily a superset of the type returned by {@link #getType} --
-     * many content providers can not return a raw stream for the structured
+     * many content providers cannot return a raw stream for the structured
      * data that they contain.
      *
      * @param url A Uri identifying content (either a list or specific type),
@@ -485,6 +484,9 @@
             if (qCursor != null) {
                 qCursor.close();
             }
+            if (cancellationSignal != null) {
+                cancellationSignal.setRemote(null);
+            }
             if (unstableProvider != null) {
                 releaseUnstableProvider(unstableProvider);
             }
@@ -531,7 +533,7 @@
             // with sufficient testing.
             return new FileInputStream(uri.getPath());
         } else {
-            AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r");
+            AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r", null);
             try {
                 return fd != null ? fd.createInputStream() : null;
             } catch (IOException e) {
@@ -571,7 +573,7 @@
      */
     public final OutputStream openOutputStream(Uri uri, String mode)
             throws FileNotFoundException {
-        AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode);
+        AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null);
         try {
             return fd != null ? fd.createOutputStream() : null;
         } catch (IOException e) {
@@ -597,6 +599,15 @@
      *
      * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
      * on these schemes.
+     * <p>
+     * If opening with the exclusive "r" or "w" modes, the returned
+     * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
+     * of data. Opening with the "rw" mode implies a file on disk that supports
+     * seeking. If possible, always use an exclusive mode to give the underlying
+     * {@link ContentProvider} the most flexibility.
+     * <p>
+     * If you are writing a file, and need to communicate an error to the
+     * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
      *
      * @param uri The desired URI to open.
      * @param mode The file mode to use, as per {@link ContentProvider#openFile
@@ -607,9 +618,54 @@
      * file exists under the URI or the mode is invalid.
      * @see #openAssetFileDescriptor(Uri, String)
      */
+    public final ParcelFileDescriptor openFileDescriptor(Uri uri, String mode)
+            throws FileNotFoundException {
+        return openFileDescriptor(uri, mode, null);
+    }
+
+    /**
+     * Open a raw file descriptor to access data under a URI.  This
+     * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
+     * underlying {@link ContentProvider#openFile}
+     * ContentProvider.openFile()} method, so will <em>not</em> work with
+     * providers that return sub-sections of files.  If at all possible,
+     * you should use {@link #openAssetFileDescriptor(Uri, String)}.  You
+     * will receive a FileNotFoundException exception if the provider returns a
+     * sub-section of a file.
+     *
+     * <h5>Accepts the following URI schemes:</h5>
+     * <ul>
+     * <li>content ({@link #SCHEME_CONTENT})</li>
+     * <li>file ({@link #SCHEME_FILE})</li>
+     * </ul>
+     *
+     * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
+     * on these schemes.
+     * <p>
+     * If opening with the exclusive "r" or "w" modes, the returned
+     * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
+     * of data. Opening with the "rw" mode implies a file on disk that supports
+     * seeking. If possible, always use an exclusive mode to give the underlying
+     * {@link ContentProvider} the most flexibility.
+     * <p>
+     * If you are writing a file, and need to communicate an error to the
+     * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
+     *
+     * @param uri The desired URI to open.
+     * @param mode The file mode to use, as per {@link ContentProvider#openFile
+     * ContentProvider.openFile}.
+     * @param cancellationSignal A signal to cancel the operation in progress,
+     *         or null if none. If the operation is canceled, then
+     *         {@link OperationCanceledException} will be thrown.
+     * @return Returns a new ParcelFileDescriptor pointing to the file.  You
+     * own this descriptor and are responsible for closing it when done.
+     * @throws FileNotFoundException Throws FileNotFoundException if no
+     * file exists under the URI or the mode is invalid.
+     * @see #openAssetFileDescriptor(Uri, String)
+     */
     public final ParcelFileDescriptor openFileDescriptor(Uri uri,
-            String mode) throws FileNotFoundException {
-        AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode);
+            String mode, CancellationSignal cancellationSignal) throws FileNotFoundException {
+        AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode, cancellationSignal);
         if (afd == null) {
             return null;
         }
@@ -677,8 +733,64 @@
      * @throws FileNotFoundException Throws FileNotFoundException of no
      * file exists under the URI or the mode is invalid.
      */
+    public final AssetFileDescriptor openAssetFileDescriptor(Uri uri, String mode)
+            throws FileNotFoundException {
+        return openAssetFileDescriptor(uri, mode, null);
+    }
+
+    /**
+     * Open a raw file descriptor to access data under a URI.  This
+     * interacts with the underlying {@link ContentProvider#openAssetFile}
+     * method of the provider associated with the given URI, to retrieve any file stored there.
+     *
+     * <h5>Accepts the following URI schemes:</h5>
+     * <ul>
+     * <li>content ({@link #SCHEME_CONTENT})</li>
+     * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
+     * <li>file ({@link #SCHEME_FILE})</li>
+     * </ul>
+     * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
+     * <p>
+     * A Uri object can be used to reference a resource in an APK file.  The
+     * Uri should be one of the following formats:
+     * <ul>
+     * <li><code>android.resource://package_name/id_number</code><br/>
+     * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
+     * For example <code>com.example.myapp</code><br/>
+     * <code>id_number</code> is the int form of the ID.<br/>
+     * The easiest way to construct this form is
+     * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
+     * </li>
+     * <li><code>android.resource://package_name/type/name</code><br/>
+     * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
+     * For example <code>com.example.myapp</code><br/>
+     * <code>type</code> is the string form of the resource type.  For example, <code>raw</code>
+     * or <code>drawable</code>.
+     * <code>name</code> is the string form of the resource name.  That is, whatever the file
+     * name was in your res directory, without the type extension.
+     * The easiest way to construct this form is
+     * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
+     * </li>
+     * </ul>
+     *
+     * <p>Note that if this function is called for read-only input (mode is "r")
+     * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor}
+     * for you with a MIME type of "*\/*".  This allows such callers to benefit
+     * from any built-in data conversion that a provider implements.
+     *
+     * @param uri The desired URI to open.
+     * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
+     * ContentProvider.openAssetFile}.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if
+     *            none. If the operation is canceled, then
+     *            {@link OperationCanceledException} will be thrown.
+     * @return Returns a new ParcelFileDescriptor pointing to the file.  You
+     * own this descriptor and are responsible for closing it when done.
+     * @throws FileNotFoundException Throws FileNotFoundException of no
+     * file exists under the URI or the mode is invalid.
+     */
     public final AssetFileDescriptor openAssetFileDescriptor(Uri uri,
-            String mode) throws FileNotFoundException {
+            String mode, CancellationSignal cancellationSignal) throws FileNotFoundException {
         String scheme = uri.getScheme();
         if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
             if (!"r".equals(mode)) {
@@ -696,7 +808,7 @@
             return new AssetFileDescriptor(pfd, 0, -1);
         } else {
             if ("r".equals(mode)) {
-                return openTypedAssetFileDescriptor(uri, "*/*", null);
+                return openTypedAssetFileDescriptor(uri, "*/*", null, cancellationSignal);
             } else {
                 IContentProvider unstableProvider = acquireUnstableProvider(uri);
                 if (unstableProvider == null) {
@@ -706,8 +818,16 @@
                 AssetFileDescriptor fd = null;
 
                 try {
+                    ICancellationSignal remoteCancellationSignal = null;
+                    if (cancellationSignal != null) {
+                        cancellationSignal.throwIfCanceled();
+                        remoteCancellationSignal = unstableProvider.createCancellationSignal();
+                        cancellationSignal.setRemote(remoteCancellationSignal);
+                    }
+
                     try {
-                        fd = unstableProvider.openAssetFile(mPackageName, uri, mode);
+                        fd = unstableProvider.openAssetFile(
+                                mPackageName, uri, mode, remoteCancellationSignal);
                         if (fd == null) {
                             // The provider will be released by the finally{} clause
                             return null;
@@ -721,7 +841,8 @@
                         if (stableProvider == null) {
                             throw new FileNotFoundException("No content provider: " + uri);
                         }
-                        fd = stableProvider.openAssetFile(mPackageName, uri, mode);
+                        fd = stableProvider.openAssetFile(
+                                mPackageName, uri, mode, remoteCancellationSignal);
                         if (fd == null) {
                             // The provider will be released by the finally{} clause
                             return null;
@@ -749,6 +870,9 @@
                 } catch (FileNotFoundException e) {
                     throw e;
                 } finally {
+                    if (cancellationSignal != null) {
+                        cancellationSignal.setRemote(null);
+                    }
                     if (stableProvider != null) {
                         releaseProvider(stableProvider);
                     }
@@ -788,8 +912,45 @@
      * @throws FileNotFoundException Throws FileNotFoundException of no
      * data of the desired type exists under the URI.
      */
+    public final AssetFileDescriptor openTypedAssetFileDescriptor(
+            Uri uri, String mimeType, Bundle opts) throws FileNotFoundException {
+        return openTypedAssetFileDescriptor(uri, mimeType, opts, null);
+    }
+
+    /**
+     * Open a raw file descriptor to access (potentially type transformed)
+     * data from a "content:" URI.  This interacts with the underlying
+     * {@link ContentProvider#openTypedAssetFile} method of the provider
+     * associated with the given URI, to retrieve retrieve any appropriate
+     * data stream for the data stored there.
+     *
+     * <p>Unlike {@link #openAssetFileDescriptor}, this function only works
+     * with "content:" URIs, because content providers are the only facility
+     * with an associated MIME type to ensure that the returned data stream
+     * is of the desired type.
+     *
+     * <p>All text/* streams are encoded in UTF-8.
+     *
+     * @param uri The desired URI to open.
+     * @param mimeType The desired MIME type of the returned data.  This can
+     * be a pattern such as *\/*, which will allow the content provider to
+     * select a type, though there is no way for you to determine what type
+     * it is returning.
+     * @param opts Additional provider-dependent options.
+     * @param cancellationSignal A signal to cancel the operation in progress,
+     *         or null if none. If the operation is canceled, then
+     *         {@link OperationCanceledException} will be thrown.
+     * @return Returns a new ParcelFileDescriptor from which you can read the
+     * data stream from the provider.  Note that this may be a pipe, meaning
+     * you can't seek in it.  The only seek you should do is if the
+     * AssetFileDescriptor contains an offset, to move to that offset before
+     * reading.  You own this descriptor and are responsible for closing it when done.
+     * @throws FileNotFoundException Throws FileNotFoundException of no
+     * data of the desired type exists under the URI.
+     */
     public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
-            String mimeType, Bundle opts) throws FileNotFoundException {
+            String mimeType, Bundle opts, CancellationSignal cancellationSignal)
+            throws FileNotFoundException {
         IContentProvider unstableProvider = acquireUnstableProvider(uri);
         if (unstableProvider == null) {
             throw new FileNotFoundException("No content provider: " + uri);
@@ -798,8 +959,16 @@
         AssetFileDescriptor fd = null;
 
         try {
+            ICancellationSignal remoteCancellationSignal = null;
+            if (cancellationSignal != null) {
+                cancellationSignal.throwIfCanceled();
+                remoteCancellationSignal = unstableProvider.createCancellationSignal();
+                cancellationSignal.setRemote(remoteCancellationSignal);
+            }
+
             try {
-                fd = unstableProvider.openTypedAssetFile(mPackageName, uri, mimeType, opts);
+                fd = unstableProvider.openTypedAssetFile(
+                        mPackageName, uri, mimeType, opts, remoteCancellationSignal);
                 if (fd == null) {
                     // The provider will be released by the finally{} clause
                     return null;
@@ -813,7 +982,8 @@
                 if (stableProvider == null) {
                     throw new FileNotFoundException("No content provider: " + uri);
                 }
-                fd = stableProvider.openTypedAssetFile(mPackageName, uri, mimeType, opts);
+                fd = stableProvider.openTypedAssetFile(
+                        mPackageName, uri, mimeType, opts, remoteCancellationSignal);
                 if (fd == null) {
                     // The provider will be released by the finally{} clause
                     return null;
@@ -841,6 +1011,9 @@
         } catch (FileNotFoundException e) {
             throw e;
         } finally {
+            if (cancellationSignal != null) {
+                cancellationSignal.setRemote(null);
+            }
             if (stableProvider != null) {
                 releaseProvider(stableProvider);
             }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ff81f72..cd1f87b 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2375,7 +2375,7 @@
 
     /**
      * {@link android.print.PrintManager} for printing and managing
-     * printers and print taks.
+     * printers and print tasks.
      *
      * @see #getSystemService
      * @see android.print.PrintManager
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 62b79f0..6ea8876 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -46,9 +46,11 @@
             throws RemoteException;
     public int update(String callingPkg, Uri url, ContentValues values, String selection,
             String[] selectionArgs) throws RemoteException;
-    public ParcelFileDescriptor openFile(String callingPkg, Uri url, String mode)
+    public ParcelFileDescriptor openFile(
+            String callingPkg, Uri url, String mode, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException;
-    public AssetFileDescriptor openAssetFile(String callingPkg, Uri url, String mode)
+    public AssetFileDescriptor openAssetFile(
+            String callingPkg, Uri url, String mode, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException;
     public ContentProviderResult[] applyBatch(String callingPkg,
             ArrayList<ContentProviderOperation> operations)
@@ -60,7 +62,7 @@
     // Data interchange.
     public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
     public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
-            Bundle opts) throws RemoteException, FileNotFoundException;
+            Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException;
 
     /* IPC constants */
     static final String descriptor = "android.content.IContentProvider";
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 017ad98..c99f09c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -35,6 +35,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.StrictMode;
+import android.provider.DocumentsContract;
 import android.util.AttributeSet;
 import android.util.Log;
 
@@ -1192,7 +1193,7 @@
 
     /**
      * An optional field on {@link #ACTION_ASSIST} and {@link #ACTION_VOICE_ASSIST}
-     * containing an the names of the application package of foreground services at the time
+     * containing the application package names of foreground services at the time
      * of the assist request.  This is an array of {@link String}s, with one entry
      * per service.
      */
@@ -2650,11 +2651,16 @@
      * multiple selection), then it can specify {@link #EXTRA_ALLOW_MULTIPLE} to
      * indicate this.
      * <p>
-     * All returned URIs can be opened as a stream with
-     * {@link ContentResolver#openInputStream(Uri)}.
+     * Callers must include {@link #CATEGORY_OPENABLE} in the Intent so that
+     * returned URIs can be opened with
+     * {@link ContentResolver#openFileDescriptor(Uri, String)}.
      * <p>
      * Output: The URI of the item that was picked. This must be a content: URI
-     * so that any receiver can access it.
+     * so that any receiver can access it. If multiple documents were selected,
+     * they are returned in {@link #getClipData()}.
+     *
+     * @see DocumentsContract
+     * @see DocumentsContract#getOpenDocuments(Context)
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
@@ -2669,11 +2675,14 @@
      * optionally hint at the MIME type being created by setting
      * {@link #setType(String)}.
      * <p>
-     * All returned URIs can be opened as a stream with
-     * {@link ContentResolver#openOutputStream(Uri)}.
+     * Callers must include {@link #CATEGORY_OPENABLE} in the Intent so that
+     * returned URIs can be opened with
+     * {@link ContentResolver#openFileDescriptor(Uri, String)}.
      * <p>
      * Output: The URI of the item that was created. This must be a content: URI
      * so that any receiver can access it.
+     *
+     * @see DocumentsContract
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
diff --git a/core/java/android/database/Cursor.java b/core/java/android/database/Cursor.java
index 7381e2c..fc2a885 100644
--- a/core/java/android/database/Cursor.java
+++ b/core/java/android/database/Cursor.java
@@ -25,9 +25,12 @@
 /**
  * This interface provides random read-write access to the result set returned
  * by a database query.
- *
+ * <p>
  * Cursor implementations are not required to be synchronized so code using a Cursor from multiple
  * threads should perform its own synchronization when using the Cursor.
+ * </p><p>
+ * Implementations should subclass {@link AbstractCursor}.
+ * </p>
  */
 public interface Cursor extends Closeable {
     /*
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 7d65736..f12be5f 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -74,8 +74,7 @@
      * richer second screen experiences.
      * </p>
      *
-     * @see android.app.Presentation for information about presenting content
-     * on secondary displays.
+     * @see android.app.Presentation
      * @see Display#FLAG_PRESENTATION
      * @see #getDisplays(String)
      */
@@ -138,8 +137,7 @@
      * more special-purpose displays.
      * </p>
      *
-     * @see android.app.Presentation for information about presenting content
-     * on secondary displays.
+     * @see android.app.Presentation
      * @see #createVirtualDisplay
      * @see #DISPLAY_CATEGORY_PRESENTATION
      * @see Display#FLAG_PRESENTATION
@@ -168,7 +166,7 @@
      * The content of secure windows will be blanked if shown on this display.
      * </p>
      *
-     * @see Display#FLAG_SECURE for information about secure displays.
+     * @see Display#FLAG_SECURE
      * @see #createVirtualDisplay
      */
     public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 1 << 2;
@@ -325,6 +323,16 @@
         mGlobal.connectWifiDisplay(deviceAddress);
     }
 
+    /** @hide */
+    public void pauseWifiDisplay() {
+        mGlobal.pauseWifiDisplay();
+    }
+
+    /** @hide */
+    public void resumeWifiDisplay() {
+        mGlobal.resumeWifiDisplay();
+    }
+
     /**
      * Disconnects from the current Wifi display.
      * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 10c14ff..936a086 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -287,6 +287,22 @@
         }
     }
 
+    public void pauseWifiDisplay() {
+        try {
+            mDm.pauseWifiDisplay();
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to pause Wifi display.", ex);
+        }
+    }
+
+    public void resumeWifiDisplay() {
+        try {
+            mDm.resumeWifiDisplay();
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to resume Wifi display.", ex);
+        }
+    }
+
     public void disconnectWifiDisplay() {
         try {
             mDm.disconnectWifiDisplay();
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index afaf436..6b2c887 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -55,4 +55,10 @@
 
     // No permissions required but must be same Uid as the creator.
     void releaseVirtualDisplay(in IBinder token);
+
+    // Requires CONFIGURE_WIFI_DISPLAY permission.
+    void pauseWifiDisplay();
+
+    // Requires CONFIGURE_WIFI_DISPLAY permission.
+    void resumeWifiDisplay();
 }
diff --git a/core/java/android/hardware/display/WifiDisplaySessionInfo.java b/core/java/android/hardware/display/WifiDisplaySessionInfo.java
new file mode 100644
index 0000000..33d2725
--- /dev/null
+++ b/core/java/android/hardware/display/WifiDisplaySessionInfo.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2012 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.hardware.display;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains information regarding a wifi display session
+ * (such as session id, source ip address, etc.). This is needed for
+ * Wifi Display Certification process.
+ * <p>
+ * This object is immutable.
+ * </p>
+ *
+ * @hide
+ */
+public final class WifiDisplaySessionInfo implements Parcelable {
+    private final boolean mClient;
+    private final int mSessionId;
+    private final String mGroupId;
+    private final String mPassphrase;
+    private final String mIP;
+
+    public static final Creator<WifiDisplaySessionInfo> CREATOR =
+            new Creator<WifiDisplaySessionInfo>() {
+        @Override
+        public WifiDisplaySessionInfo createFromParcel(Parcel in) {
+            boolean client = (in.readInt() != 0);
+            int session = in.readInt();
+            String group = in.readString();
+            String pp = in.readString();
+            String ip = in.readString();
+
+            return new WifiDisplaySessionInfo(client, session, group, pp, ip);
+        }
+
+        @Override
+        public WifiDisplaySessionInfo[] newArray(int size) {
+            return new WifiDisplaySessionInfo[size];
+        }
+    };
+
+    public WifiDisplaySessionInfo() {
+        this(true, 0, "", "", "");
+    }
+
+    public WifiDisplaySessionInfo(
+            boolean client, int session, String group, String pp, String ip) {
+        mClient = client;
+        mSessionId = session;
+        mGroupId = group;
+        mPassphrase = pp;
+        mIP = ip;
+    }
+
+    public boolean isClient() {
+        return mClient;
+    }
+
+    public int getSessionId() {
+        return mSessionId;
+    }
+
+    public String getGroupId() {
+        return mGroupId;
+    }
+
+    public String getPassphrase() {
+        return mPassphrase;
+    }
+
+    public String getIP() {
+        return mIP;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mClient ? 1 : 0);
+        dest.writeInt(mSessionId);
+        dest.writeString(mGroupId);
+        dest.writeString(mPassphrase);
+        dest.writeString(mIP);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    // For debugging purposes only.
+    @Override
+    public String toString() {
+        return "WifiDisplaySessionInfo:"
+                +"\n    Client/Owner: " + (mClient ? "Client":"Owner")
+                +"\n    GroupId: " + mGroupId
+                +"\n    Passphrase: " + mPassphrase
+                +"\n    SessionId: " + mSessionId
+                +"\n    IP Address: " + mIP
+                ;
+    }
+}
diff --git a/core/java/android/hardware/display/WifiDisplayStatus.java b/core/java/android/hardware/display/WifiDisplayStatus.java
index 77acdc0..5216727 100644
--- a/core/java/android/hardware/display/WifiDisplayStatus.java
+++ b/core/java/android/hardware/display/WifiDisplayStatus.java
@@ -39,6 +39,9 @@
     private final WifiDisplay mActiveDisplay;
     private final WifiDisplay[] mDisplays;
 
+    /** Session info needed for Miracast Certification */
+    private final WifiDisplaySessionInfo mSessionInfo;
+
     /** Feature state: Wifi display is not available on this device. */
     public static final int FEATURE_STATE_UNAVAILABLE = 0;
     /** Feature state: Wifi display is disabled, probably because Wifi is disabled. */
@@ -76,8 +79,11 @@
                 displays[i] = WifiDisplay.CREATOR.createFromParcel(in);
             }
 
+            WifiDisplaySessionInfo sessionInfo =
+                    WifiDisplaySessionInfo.CREATOR.createFromParcel(in);
+
             return new WifiDisplayStatus(featureState, scanState, activeDisplayState,
-                    activeDisplay, displays);
+                    activeDisplay, displays, sessionInfo);
         }
 
         public WifiDisplayStatus[] newArray(int size) {
@@ -87,11 +93,11 @@
 
     public WifiDisplayStatus() {
         this(FEATURE_STATE_UNAVAILABLE, SCAN_STATE_NOT_SCANNING, DISPLAY_STATE_NOT_CONNECTED,
-                null, WifiDisplay.EMPTY_ARRAY);
+                null, WifiDisplay.EMPTY_ARRAY, null);
     }
 
-    public WifiDisplayStatus(int featureState, int scanState,
-            int activeDisplayState, WifiDisplay activeDisplay, WifiDisplay[] displays) {
+    public WifiDisplayStatus(int featureState, int scanState, int activeDisplayState,
+            WifiDisplay activeDisplay, WifiDisplay[] displays, WifiDisplaySessionInfo sessionInfo) {
         if (displays == null) {
             throw new IllegalArgumentException("displays must not be null");
         }
@@ -101,6 +107,8 @@
         mActiveDisplayState = activeDisplayState;
         mActiveDisplay = activeDisplay;
         mDisplays = displays;
+
+        mSessionInfo = (sessionInfo != null) ? sessionInfo : new WifiDisplaySessionInfo();
     }
 
     /**
@@ -144,13 +152,20 @@
 
     /**
      * Gets the list of Wifi displays, returns a combined list of all available
-     * Wifi displays as reported by the most recent scan, and all remembered 
+     * Wifi displays as reported by the most recent scan, and all remembered
      * Wifi displays (not necessarily available at the time).
      */
     public WifiDisplay[] getDisplays() {
         return mDisplays;
     }
 
+    /**
+     * Gets the Wifi display session info (required for certification only)
+     */
+    public WifiDisplaySessionInfo getSessionInfo() {
+        return mSessionInfo;
+    }
+
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mFeatureState);
@@ -168,6 +183,8 @@
         for (WifiDisplay display : mDisplays) {
             display.writeToParcel(dest, flags);
         }
+
+        mSessionInfo.writeToParcel(dest, flags);
     }
 
     @Override
@@ -183,6 +200,7 @@
                 + ", activeDisplayState=" + mActiveDisplayState
                 + ", activeDisplay=" + mActiveDisplay
                 + ", displays=" + Arrays.toString(mDisplays)
+                + ", sessionInfo=" + mSessionInfo
                 + "}";
     }
 }
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index da7647a..65c9220 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -16,6 +16,9 @@
 
 package android.provider;
 
+import static android.net.TrafficStats.KB_IN_BYTES;
+import static libcore.io.OsConstants.SEEK_SET;
+
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -30,19 +33,49 @@
 import android.graphics.Point;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.OnCloseListener;
 import android.util.Log;
 
 import com.google.android.collect.Lists;
 
+import libcore.io.ErrnoException;
+import libcore.io.IoBridge;
 import libcore.io.IoUtils;
+import libcore.io.Libcore;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.util.List;
 
 /**
- * The contract between a storage backend and the platform. Contains definitions
- * for the supported URIs and columns.
+ * Defines the contract between a documents provider and the platform.
+ * <p>
+ * A document provider is a {@link ContentProvider} that presents a set of
+ * documents in a hierarchical structure. The system provides UI that visualizes
+ * all available document providers, offering users the ability to open existing
+ * documents or create new documents.
+ * <p>
+ * Each provider expresses one or more "roots" which each serve as the top-level
+ * of a tree. For example, a root could represent an account, or a physical
+ * storage device. Under each root, documents are referenced by a unique
+ * {@link DocumentColumns#DOC_ID}, and each root starts at the
+ * {@link Documents#DOC_ID_ROOT} document.
+ * <p>
+ * Documents can be either an openable file (with a specific MIME type), or a
+ * directory containing additional documents (with the
+ * {@link Documents#MIME_TYPE_DIR} MIME type). Each document can have different
+ * capabilities, as described by {@link DocumentColumns#FLAGS}. The same
+ * {@link DocumentColumns#DOC_ID} can be included in multiple directories.
+ * <p>
+ * Document providers must be protected with the
+ * {@link android.Manifest.permission#MANAGE_DOCUMENTS} permission, which can
+ * only be requested by the system. The system-provided UI then issues narrow
+ * Uri permission grants for individual documents when the user explicitly picks
+ * documents.
+ *
+ * @see Intent#ACTION_OPEN_DOCUMENT
+ * @see Intent#ACTION_CREATE_DOCUMENT
  */
 public final class DocumentsContract {
     private static final String TAG = "Documents";
@@ -59,6 +92,9 @@
     /** {@hide} */
     public static final String ACTION_DOCUMENT_CHANGED = "android.provider.action.DOCUMENT_CHANGED";
 
+    /**
+     * Constants for individual documents.
+     */
     public static class Documents {
         private Documents() {
         }
@@ -73,7 +109,7 @@
 
         /**
          * {@link DocumentColumns#DOC_ID} value representing the root directory of a
-         * storage root.
+         * documents root.
          */
         public static final String DOC_ID_ROOT = "0";
 
@@ -144,8 +180,8 @@
 
     /**
      * Extra boolean flag included in a directory {@link Cursor#getExtras()}
-     * indicating that the backend can provide additional data if requested,
-     * such as additional search results.
+     * indicating that the document provider can provide additional data if
+     * requested, such as additional search results.
      */
     public static final String EXTRA_HAS_MORE = "has_more";
 
@@ -170,21 +206,24 @@
     private static final String PARAM_LOCAL_ONLY = "localOnly";
 
     /**
-     * Build URI representing the roots in a storage backend.
+     * Build Uri representing the roots offered by a document provider.
      */
     public static Uri buildRootsUri(String authority) {
         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
                 .authority(authority).appendPath(PATH_ROOTS).build();
     }
 
+    /**
+     * Build Uri representing a specific root offered by a document provider.
+     */
     public static Uri buildRootUri(String authority, String rootId) {
         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
                 .authority(authority).appendPath(PATH_ROOTS).appendPath(rootId).build();
     }
 
     /**
-     * Build URI representing the given {@link DocumentColumns#DOC_ID} in a
-     * storage root.
+     * Build Uri representing the given {@link DocumentColumns#DOC_ID} in a
+     * document provider.
      */
     public static Uri buildDocumentUri(String authority, String rootId, String docId) {
         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority)
@@ -193,8 +232,8 @@
     }
 
     /**
-     * Build URI representing the contents of the given directory in a storage
-     * backend. The given document must be {@link Documents#MIME_TYPE_DIR}.
+     * Build Uri representing the contents of the given directory in a document
+     * provider. The given document must be {@link Documents#MIME_TYPE_DIR}.
      */
     public static Uri buildContentsUri(String authority, String rootId, String docId) {
         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority)
@@ -203,8 +242,9 @@
     }
 
     /**
-     * Build URI representing a search for matching documents under a directory
-     * in a storage backend.
+     * Build Uri representing a search for matching documents under a specific
+     * directory in a document provider. The given document must have
+     * {@link Documents#FLAG_SUPPORTS_SEARCH}.
      */
     public static Uri buildSearchUri(String authority, String rootId, String docId, String query) {
         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority)
@@ -212,20 +252,36 @@
                 .appendPath(PATH_SEARCH).appendQueryParameter(PARAM_QUERY, query).build();
     }
 
+    /**
+     * Convenience method for {@link #buildDocumentUri(String, String, String)},
+     * extracting authority and root from the given Uri.
+     */
     public static Uri buildDocumentUri(Uri relatedUri, String docId) {
         return buildDocumentUri(relatedUri.getAuthority(), getRootId(relatedUri), docId);
     }
 
+    /**
+     * Convenience method for {@link #buildContentsUri(String, String, String)},
+     * extracting authority and root from the given Uri.
+     */
     public static Uri buildContentsUri(Uri relatedUri) {
         return buildContentsUri(
                 relatedUri.getAuthority(), getRootId(relatedUri), getDocId(relatedUri));
     }
 
+    /**
+     * Convenience method for
+     * {@link #buildSearchUri(String, String, String, String)}, extracting
+     * authority and root from the given Uri.
+     */
     public static Uri buildSearchUri(Uri relatedUri, String query) {
         return buildSearchUri(
                 relatedUri.getAuthority(), getRootId(relatedUri), getDocId(relatedUri), query);
     }
 
+    /**
+     * Extract the {@link RootColumns#ROOT_ID} from the given Uri.
+     */
     public static String getRootId(Uri documentUri) {
         final List<String> paths = documentUri.getPathSegments();
         if (paths.size() < 2) {
@@ -237,6 +293,9 @@
         return paths.get(1);
     }
 
+    /**
+     * Extract the {@link DocumentColumns#DOC_ID} from the given Uri.
+     */
     public static String getDocId(Uri documentUri) {
         final List<String> paths = documentUri.getPathSegments();
         if (paths.size() < 4) {
@@ -252,15 +311,17 @@
     }
 
     /**
-     * Return requested search query from the given Uri.
+     * Return requested search query from the given Uri, as constructed by
+     * {@link #buildSearchUri(String, String, String, String)}.
      */
     public static String getSearchQuery(Uri documentUri) {
         return documentUri.getQueryParameter(PARAM_QUERY);
     }
 
     /**
-     * Mark the given Uri to indicate that only locally-available contents
-     * should be returned.
+     * Mark the given Uri to indicate that only locally-available data should be
+     * returned. That is, no network connections should be initiated to provide
+     * the metadata or content.
      */
     public static Uri setLocalOnly(Uri documentUri) {
         return documentUri.buildUpon()
@@ -268,20 +329,21 @@
     }
 
     /**
-     * Return if the given Uri is requesting that only locally-available content
-     * be returned. That is, no network connections should be initiated to
-     * provide the metadata or content.
+     * Return if the given Uri is requesting that only locally-available data be
+     * returned. That is, no network connections should be initiated to provide
+     * the metadata or content.
      */
     public static boolean isLocalOnly(Uri documentUri) {
         return documentUri.getBooleanQueryParameter(PARAM_LOCAL_ONLY, false);
     }
 
     /**
-     * These are standard columns for document URIs. Storage backend providers
-     * <em>must</em> support at least these columns when queried.
+     * Standard columns for document queries. Document providers <em>must</em>
+     * support at least these columns when queried.
      *
-     * @see Intent#ACTION_OPEN_DOCUMENT
-     * @see Intent#ACTION_CREATE_DOCUMENT
+     * @see DocumentsContract#buildDocumentUri(String, String, String)
+     * @see DocumentsContract#buildContentsUri(String, String, String)
+     * @see DocumentsContract#buildSearchUri(String, String, String, String)
      */
     public interface DocumentColumns extends OpenableColumns {
         /**
@@ -296,8 +358,8 @@
         /**
          * MIME type of a document, matching the value returned by
          * {@link ContentResolver#getType(android.net.Uri)}. This field must be
-         * provided when a new document is created, but after that the field is
-         * read-only.
+         * provided when a new document is created. This field is read-only to
+         * document clients.
          * <p>
          * Type: STRING
          *
@@ -308,7 +370,9 @@
         /**
          * Timestamp when a document was last modified, in milliseconds since
          * January 1, 1970 00:00:00.0 UTC. This field is read-only to document
-         * clients.
+         * clients. Document providers can update this field using events from
+         * {@link OnCloseListener} or other reliable
+         * {@link ParcelFileDescriptor} transport.
          * <p>
          * Type: INTEGER (long)
          *
@@ -325,13 +389,17 @@
         public static final String FLAGS = "flags";
 
         /**
-         * Summary for this document, or {@code null} to omit.
+         * Summary for this document, or {@code null} to omit. This field is
+         * read-only to document clients.
          * <p>
          * Type: STRING
          */
         public static final String SUMMARY = "summary";
     }
 
+    /**
+     * Constants for individual document roots.
+     */
     public static class Roots {
         private Roots() {
         }
@@ -340,7 +408,8 @@
         public static final String MIME_TYPE_ITEM = "vnd.android.cursor.item/root";
 
         /**
-         * Root that represents a cloud-based storage service.
+         * Root that represents a storage service, such as a cloud-based
+         * service.
          *
          * @see RootColumns#ROOT_TYPE
          */
@@ -371,15 +440,17 @@
     }
 
     /**
-     * These are standard columns for the roots URI.
+     * Standard columns for document root queries.
      *
      * @see DocumentsContract#buildRootsUri(String)
+     * @see DocumentsContract#buildRootUri(String, String)
      */
     public interface RootColumns {
         public static final String ROOT_ID = "root_id";
 
         /**
-         * Storage root type, use for clustering.
+         * Storage root type, use for clustering. This field is read-only to
+         * document clients.
          * <p>
          * Type: INTEGER (int)
          *
@@ -389,8 +460,9 @@
         public static final String ROOT_TYPE = "root_type";
 
         /**
-         * Icon resource ID for this storage root, or {@code 0} to use the
-         * default {@link ProviderInfo#icon}.
+         * Icon resource ID for this storage root, or {@code null} to use the
+         * default {@link ProviderInfo#icon}. This field is read-only to
+         * document clients.
          * <p>
          * Type: INTEGER (int)
          */
@@ -398,22 +470,25 @@
 
         /**
          * Title for this storage root, or {@code null} to use the default
-         * {@link ProviderInfo#labelRes}.
+         * {@link ProviderInfo#labelRes}. This field is read-only to document
+         * clients.
          * <p>
          * Type: STRING
          */
         public static final String TITLE = "title";
 
         /**
-         * Summary for this storage root, or {@code null} to omit.
+         * Summary for this storage root, or {@code null} to omit. This field is
+         * read-only to document clients.
          * <p>
          * Type: STRING
          */
         public static final String SUMMARY = "summary";
 
         /**
-         * Number of free bytes of available in this storage root, or -1 if
-         * unknown or unbounded.
+         * Number of free bytes of available in this storage root, or
+         * {@code null} if unknown or unbounded. This field is read-only to
+         * document clients.
          * <p>
          * Type: INTEGER (long)
          */
@@ -452,31 +527,59 @@
 
     /**
      * Return thumbnail representing the document at the given URI. Callers are
-     * responsible for their own caching. Given document must have
+     * responsible for their own in-memory caching. Given document must have
      * {@link Documents#FLAG_SUPPORTS_THUMBNAIL} set.
      *
      * @return decoded thumbnail, or {@code null} if problem was encountered.
      */
     public static Bitmap getThumbnail(ContentResolver resolver, Uri documentUri, Point size) {
-        final Bundle opts = new Bundle();
-        opts.putParcelable(EXTRA_THUMBNAIL_SIZE, size);
+        final Bundle openOpts = new Bundle();
+        openOpts.putParcelable(DocumentsContract.EXTRA_THUMBNAIL_SIZE, size);
 
         AssetFileDescriptor afd = null;
         try {
-            afd = resolver.openTypedAssetFileDescriptor(documentUri, "image/*", opts);
+            afd = resolver.openTypedAssetFileDescriptor(documentUri, "image/*", openOpts);
 
             final FileDescriptor fd = afd.getFileDescriptor();
-            final BitmapFactory.Options bitmapOpts = new BitmapFactory.Options();
+            final long offset = afd.getStartOffset();
+            final long length = afd.getDeclaredLength();
 
-            bitmapOpts.inJustDecodeBounds = true;
-            BitmapFactory.decodeFileDescriptor(fd, null, bitmapOpts);
+            // Some thumbnails might be a region inside a larger file, such as
+            // an EXIF thumbnail. Since BitmapFactory aggressively seeks around
+            // the entire file, we read the region manually.
+            byte[] region = null;
+            if (offset > 0 && length <= 64 * KB_IN_BYTES) {
+                region = new byte[(int) length];
+                Libcore.os.lseek(fd, offset, SEEK_SET);
+                if (IoBridge.read(fd, region, 0, region.length) != region.length) {
+                    region = null;
+                }
+            }
 
-            final int widthSample = bitmapOpts.outWidth / size.x;
-            final int heightSample = bitmapOpts.outHeight / size.y;
+            // We requested a rough thumbnail size, but the remote size may have
+            // returned something giant, so defensively scale down as needed.
+            final BitmapFactory.Options opts = new BitmapFactory.Options();
+            opts.inJustDecodeBounds = true;
+            if (region != null) {
+                BitmapFactory.decodeByteArray(region, 0, region.length, opts);
+            } else {
+                BitmapFactory.decodeFileDescriptor(fd, null, opts);
+            }
 
-            bitmapOpts.inJustDecodeBounds = false;
-            bitmapOpts.inSampleSize = Math.min(widthSample, heightSample);
-            return BitmapFactory.decodeFileDescriptor(fd, null, bitmapOpts);
+            final int widthSample = opts.outWidth / size.x;
+            final int heightSample = opts.outHeight / size.y;
+
+            opts.inJustDecodeBounds = false;
+            opts.inSampleSize = Math.min(widthSample, heightSample);
+            Log.d(TAG, "Decoding with sample size " + opts.inSampleSize);
+            if (region != null) {
+                return BitmapFactory.decodeByteArray(region, 0, region.length, opts);
+            } else {
+                return BitmapFactory.decodeFileDescriptor(fd, null, opts);
+            }
+        } catch (ErrnoException e) {
+            Log.w(TAG, "Failed to load thumbnail for " + documentUri + ": " + e);
+            return null;
         } catch (IOException e) {
             Log.w(TAG, "Failed to load thumbnail for " + documentUri + ": " + e);
             return null;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b3309e1a..0b51b8a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5075,6 +5075,14 @@
        public static final String WIFI_DISPLAY_ON = "wifi_display_on";
 
        /**
+        * Whether Wifi display certification mode is enabled/disabled
+        * 0=disabled. 1=enabled.
+        * @hide
+        */
+       public static final String WIFI_DISPLAY_CERTIFICATION_ON =
+               "wifi_display_certification_on";
+
+       /**
         * Whether to notify the user of open networks.
         * <p>
         * If not connected and the scan results have an open network, we will
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 521ba81..1f2ab93 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -138,6 +138,7 @@
             = "lockscreen.biometricweakeverchosen";
     public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
             = "lockscreen.power_button_instantly_locks";
+    public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
 
     public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
 
@@ -1053,28 +1054,38 @@
         return nextAlarm;
     }
 
-    private boolean getBoolean(String secureSettingKey, boolean defaultValue) {
+    private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
         try {
-            return getLockSettings().getBoolean(secureSettingKey, defaultValue,
-                    getCurrentOrCallingUserId());
+            return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
         } catch (RemoteException re) {
             return defaultValue;
         }
     }
 
-    private void setBoolean(String secureSettingKey, boolean enabled) {
+    private boolean getBoolean(String secureSettingKey, boolean defaultValue) {
+        return getBoolean(secureSettingKey, defaultValue, getCurrentOrCallingUserId());
+    }
+
+    private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
         try {
-            getLockSettings().setBoolean(secureSettingKey, enabled, getCurrentOrCallingUserId());
+            getLockSettings().setBoolean(secureSettingKey, enabled, userId);
         } catch (RemoteException re) {
             // What can we do?
             Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
         }
     }
 
+    private void setBoolean(String secureSettingKey, boolean enabled) {
+        setBoolean(secureSettingKey, enabled, getCurrentOrCallingUserId());
+    }
+
     public int[] getAppWidgets() {
+        return getAppWidgets(UserHandle.USER_CURRENT);
+    }
+
+    private int[] getAppWidgets(int userId) {
         String appWidgetIdString = Settings.Secure.getStringForUser(
-                mContentResolver, Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS,
-                UserHandle.USER_CURRENT);
+                mContentResolver, Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS, userId);
         String delims = ",";
         if (appWidgetIdString != null && appWidgetIdString.length() > 0) {
             String[] appWidgetStringIds = appWidgetIdString.split(delims);
@@ -1361,4 +1372,35 @@
         return false;
     }
 
+    /**
+     * Determine whether the user has selected any non-system widgets in keyguard
+     *
+     * @return true if widgets have been selected
+     */
+    public boolean hasWidgetsEnabledInKeyguard(int userid) {
+        int widgets[] = getAppWidgets(userid);
+        for (int i = 0; i < widgets.length; i++) {
+            if (widgets[i] > 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean getWidgetsEnabled() {
+        return getWidgetsEnabled(getCurrentOrCallingUserId());
+    }
+
+    public boolean getWidgetsEnabled(int userId) {
+        return getBoolean(LOCKSCREEN_WIDGETS_ENABLED, false, userId);
+    }
+
+    public void setWidgetsEnabled(boolean enabled) {
+        setWidgetsEnabled(enabled, getCurrentOrCallingUserId());
+    }
+
+    public void setWidgetsEnabled(boolean enabled, int userId) {
+        setBoolean(LOCKSCREEN_WIDGETS_ENABLED, enabled, userId);
+    }
+
 }
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
index 80d13be..3fd8ed9 100644
--- a/core/jni/android_media_RemoteDisplay.cpp
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -61,7 +61,7 @@
 
 public:
     virtual void onDisplayConnected(const sp<IGraphicBufferProducer>& bufferProducer,
-            uint32_t width, uint32_t height, uint32_t flags) {
+            uint32_t width, uint32_t height, uint32_t flags, uint32_t session) {
         JNIEnv* env = AndroidRuntime::getJNIEnv();
 
         jobject surfaceObj = android_view_Surface_createFromIGraphicBufferProducer(env, bufferProducer);
@@ -73,7 +73,7 @@
 
         env->CallVoidMethod(mRemoteDisplayObjGlobal,
                 gRemoteDisplayClassInfo.notifyDisplayConnected,
-                surfaceObj, width, height, flags);
+                surfaceObj, width, height, flags, session);
         env->DeleteLocalRef(surfaceObj);
         checkAndClearExceptionFromCallback(env, "notifyDisplayConnected");
     }
@@ -117,6 +117,14 @@
         mDisplay->dispose();
     }
 
+    void pause() {
+        mDisplay->pause();
+    }
+
+    void resume() {
+        mDisplay->resume();
+    }
+
 private:
     sp<IRemoteDisplay> mDisplay;
     sp<NativeRemoteDisplayClient> mClient;
@@ -149,6 +157,16 @@
     return reinterpret_cast<jint>(wrapper);
 }
 
+static void nativePause(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
+    NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
+    wrapper->pause();
+}
+
+static void nativeResume(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
+    NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
+    wrapper->resume();
+}
+
 static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
     NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
     delete wrapper;
@@ -161,6 +179,10 @@
             (void*)nativeListen },
     {"nativeDispose", "(I)V",
             (void*)nativeDispose },
+    {"nativePause", "(I)V",
+            (void*)nativePause },
+    {"nativeResume", "(I)V",
+            (void*)nativeResume },
 };
 
 int register_android_media_RemoteDisplay(JNIEnv* env)
@@ -171,7 +193,7 @@
     jclass clazz = env->FindClass("android/media/RemoteDisplay");
     gRemoteDisplayClassInfo.notifyDisplayConnected =
             env->GetMethodID(clazz, "notifyDisplayConnected",
-                    "(Landroid/view/Surface;III)V");
+                    "(Landroid/view/Surface;IIII)V");
     gRemoteDisplayClassInfo.notifyDisplayDisconnected =
             env->GetMethodID(clazz, "notifyDisplayDisconnected", "()V");
     gRemoteDisplayClassInfo.notifyDisplayError =
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0d1ace8..faf6e63 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1900,14 +1900,14 @@
         android:description="@string/permdesc_bindAccessibilityService"
         android:protectionLevel="signature" />
 
-    <!-- Must be required by an {@link android.printservice.PrintService},
+    <!-- Must be required by a {@link android.printservice.PrintService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_PRINT_SERVICE"
         android:label="@string/permlab_bindPrintService"
         android:description="@string/permdesc_bindPrintService"
         android:protectionLevel="signature" />
 
-    <!-- Must be required by an {@link android.nfc.cardemulation.HostApduService}
+    <!-- Must be required by a {@link android.nfc.cardemulation.HostApduService}
          or {@link android.nfc.cardemulation.OffHostApduService} to ensure that only
          the system can bind to it. -->
     <permission android:name="android.permission.BIND_NFC_SERVICE"
@@ -1931,7 +1931,7 @@
         android:description="@string/permdesc_bindTextService"
         android:protectionLevel="signature" />
 
-    <!-- Must be required by an {@link android.net.VpnService},
+    <!-- Must be required by a {@link android.net.VpnService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_VPN_SERVICE"
         android:label="@string/permlab_bindVpnService"
@@ -1953,7 +1953,7 @@
         android:protectionLevel="signature" />
 
     <!-- Required to add or remove another application as a device admin.
-         <p/>Not for use by third-party apps. -->
+         <p/>Not for use by third-party applications. -->
     <permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
         android:label="@string/permlab_manageDeviceAdmins"
         android:description="@string/permdesc_manageDeviceAdmins"
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
index 0820f07..a36fa36 100644
--- a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
+++ b/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index 10cdab0..e2606d6 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -63,6 +63,8 @@
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
+    private static final String EXTENDED_INFO_DATA = "extended_info_data";
+
     static {
         // Load the respective library
         System.loadLibrary("drmframework_jni");
@@ -184,8 +186,22 @@
         DrmManagerClient instance = (DrmManagerClient)((WeakReference)thisReference).get();
 
         if (null != instance && null != instance.mInfoHandler) {
+            DrmInfoEvent event = new DrmInfoEvent(uniqueId, infoType, message);
             Message m = instance.mInfoHandler.obtainMessage(
-                InfoHandler.INFO_EVENT_TYPE, uniqueId, infoType, message);
+                    InfoHandler.INFO_EVENT_TYPE, event);
+            instance.mInfoHandler.sendMessage(m);
+        }
+    }
+
+    private static void notify(
+            Object thisReference, int uniqueId, int infoType, String message,
+            HashMap<String, Object> attributes) {
+        DrmManagerClient instance = (DrmManagerClient)((WeakReference)thisReference).get();
+
+        if (null != instance && null != instance.mInfoHandler) {
+            DrmInfoEvent event = new DrmInfoEvent(uniqueId, infoType, message, attributes);
+            Message m = instance.mInfoHandler.obtainMessage(
+                    InfoHandler.INFO_EVENT_TYPE, event);
             instance.mInfoHandler.sendMessage(m);
         }
     }
@@ -198,23 +214,25 @@
         }
 
         public void handleMessage(Message msg) {
-            DrmInfoEvent info = null;
+            DrmInfoEvent info = (DrmInfoEvent) msg.obj;
             DrmErrorEvent error = null;
+            int uniqueId;
+            int eventType;
+            String message;
 
             switch (msg.what) {
             case InfoHandler.INFO_EVENT_TYPE:
-                int uniqueId = msg.arg1;
-                int infoType = msg.arg2;
-                String message = msg.obj.toString();
+                uniqueId = info.getUniqueId();
+                eventType = info.getType();
+                message = info.getMessage();
 
-                switch (infoType) {
+                switch (eventType) {
                 case DrmInfoEvent.TYPE_REMOVE_RIGHTS: {
                     try {
                         DrmUtils.removeFile(message);
                     } catch (IOException e) {
                         e.printStackTrace();
                     }
-                    info = new DrmInfoEvent(uniqueId, infoType, message);
                     break;
                 }
                 case DrmInfoEvent.TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT:
@@ -222,11 +240,11 @@
                 case DrmInfoEvent.TYPE_WAIT_FOR_RIGHTS:
                 case DrmInfoEvent.TYPE_ACCOUNT_ALREADY_REGISTERED:
                 case DrmInfoEvent.TYPE_RIGHTS_REMOVED: {
-                    info = new DrmInfoEvent(uniqueId, infoType, message);
                     break;
                 }
                 default:
-                    error = new DrmErrorEvent(uniqueId, infoType, message);
+                    info = null;
+                    error = new DrmErrorEvent(uniqueId, eventType, message);
                     break;
                 }
 
diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp
index baddf62..7fce3d0 100644
--- a/drm/jni/android_drm_DrmManagerClient.cpp
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -169,11 +169,49 @@
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jstring message = env->NewStringUTF(event.getMessage().string());
     ALOGV("JNIOnInfoListener::onInfo => %d | %d | %s", uniqueId, type, event.getMessage().string());
+    const DrmBuffer& drmBuffer = event.getData();
+    if (event.getCount() > 0 || drmBuffer.length > 0) {
+        jclass hashMapClazz = env->FindClass("java/util/HashMap");
+        jmethodID hashMapInitId = env->GetMethodID(hashMapClazz, "<init>", "()V");
+        jmethodID hashMapPutId = env->GetMethodID(hashMapClazz, "put",
+                "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+        jobject hashMapObject = env->NewObject(hashMapClazz, hashMapInitId);
+        env->DeleteLocalRef(hashMapClazz);
 
-    env->CallStaticVoidMethod(
-            mClass,
-            env->GetStaticMethodID(mClass, "notify", "(Ljava/lang/Object;IILjava/lang/String;)V"),
-            mObject, uniqueId, type, message);
+        if (0 < drmBuffer.length) {
+            jfieldID fid = env->GetStaticFieldID(
+                mClass, "EXTENDED_INFO_DATA", "Ljava/lang/String;");
+            jstring key = (jstring) env->GetStaticObjectField(mClass, fid);
+
+            jbyteArray valueByte = env->NewByteArray(drmBuffer.length);
+            env->SetByteArrayRegion(valueByte, 0, drmBuffer.length, (jbyte*) drmBuffer.data);
+            env->CallObjectMethod(hashMapObject, hashMapPutId, key, valueByte);
+            env->DeleteLocalRef(valueByte);
+            env->DeleteLocalRef(key);
+        }
+        DrmInfoEvent::KeyIterator keyIt = event.keyIterator();
+        while (keyIt.hasNext()) {
+            String8 mapKey = keyIt.next();
+            jstring key = env->NewStringUTF(mapKey.string());
+            jstring value = env->NewStringUTF(event.get(mapKey).string());
+            env->CallObjectMethod(hashMapObject, hashMapPutId, key, value);
+            env->DeleteLocalRef(value);
+            env->DeleteLocalRef(key);
+        }
+        env->CallStaticVoidMethod(
+                mClass,
+                env->GetStaticMethodID(mClass, "notify",
+                        "(Ljava/lang/Object;IILjava/lang/String;Ljava/util/HashMap;)V"),
+                mObject, uniqueId, type, message, hashMapObject);
+        env->DeleteLocalRef(hashMapObject);
+    } else {
+        env->CallStaticVoidMethod(
+                mClass,
+                env->GetStaticMethodID(mClass, "notify",
+                        "(Ljava/lang/Object;IILjava/lang/String;)V"),
+                mObject, uniqueId, type, message);
+    }
+    env->DeleteLocalRef(message);
 }
 
 static Mutex sLock;
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 362b586..7d05a74 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -61,6 +61,7 @@
     Bitmap mBitmap;
     int mUsage;
     Allocation mAdaptedAllocation;
+    int mSize;
 
     boolean mConstrainedLOD;
     boolean mConstrainedFace;
@@ -268,10 +269,22 @@
 
         mType = t;
         mUsage = usage;
+        mSize = mType.getCount() * mType.getElement().getBytesSize();
 
         if (t != null) {
             updateCacheInfo(t);
         }
+        try {
+            RenderScript.registerNativeAllocation.invoke(RenderScript.sRuntime, mSize);
+        } catch (Exception e) {
+            Log.e(RenderScript.LOG_TAG, "Couldn't invoke registerNativeAllocation:" + e);
+            throw new RSRuntimeException("Couldn't invoke registerNativeAllocation:" + e);
+        }
+    }
+
+    protected void finalize() throws Throwable {
+        RenderScript.registerNativeFree.invoke(RenderScript.sRuntime, mSize);
+        super.finalize();
     }
 
     private void validateIsInt32() {
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 4de4766..854f079 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -18,6 +18,7 @@
 
 import java.io.File;
 import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -61,11 +62,24 @@
     static boolean sInitialized;
     native static void _nInit();
 
+    static Object sRuntime;
+    static Method registerNativeAllocation;
+    static Method registerNativeFree;
 
     static {
         sInitialized = false;
         if (!SystemProperties.getBoolean("config.disable_renderscript", false)) {
             try {
+                Class<?> vm_runtime = Class.forName("dalvik.system.VMRuntime");
+                Method get_runtime = vm_runtime.getDeclaredMethod("getRuntime");
+                sRuntime = get_runtime.invoke(null);
+                registerNativeAllocation = vm_runtime.getDeclaredMethod("registerNativeAllocation", Integer.TYPE);
+                registerNativeFree = vm_runtime.getDeclaredMethod("registerNativeFree", Integer.TYPE);
+            } catch (Exception e) {
+                Log.e(LOG_TAG, "Error loading GC methods: " + e);
+                throw new RSRuntimeException("Error loading GC methods: " + e);
+            }
+            try {
                 System.loadLibrary("rs_jni");
                 _nInit();
                 sInitialized = true;
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 4cd3e37..20eb356 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -291,6 +291,20 @@
     }
 
     /**
+     * Returns the offset and length of thumbnail inside the JPEG file, or
+     * {@code null} if there is no thumbnail.
+     *
+     * @return two-element array, the offset in the first value, and length in
+     *         the second, or {@code null} if no thumbnail was found.
+     * @hide
+     */
+    public long[] getThumbnailRange() {
+        synchronized (sLock) {
+            return getThumbnailRangeNative(mFilename);
+        }
+    }
+
+    /**
      * Stores the latitude and longitude value in a float array. The first element is
      * the latitude, and the second element is the longitude. Returns false if the
      * Exif tags are not available.
@@ -416,4 +430,6 @@
     private native void commitChangesNative(String fileName);
 
     private native byte[] getThumbnailNative(String fileName);
+
+    private native long[] getThumbnailRangeNative(String fileName);
 }
diff --git a/media/java/android/media/RemoteDisplay.java b/media/java/android/media/RemoteDisplay.java
index b463d26..7afce1a 100644
--- a/media/java/android/media/RemoteDisplay.java
+++ b/media/java/android/media/RemoteDisplay.java
@@ -42,6 +42,8 @@
 
     private native int nativeListen(String iface);
     private native void nativeDispose(int ptr);
+    private native void nativePause(int ptr);
+    private native void nativeResume(int ptr);
 
     private RemoteDisplay(Listener listener, Handler handler) {
         mListener = listener;
@@ -87,6 +89,14 @@
         dispose(false);
     }
 
+    public void pause() {
+        nativePause(mPtr);
+    }
+
+    public void resume() {
+        nativeResume(mPtr);
+    }
+
     private void dispose(boolean finalized) {
         if (mPtr != 0) {
             if (mGuard != null) {
@@ -113,11 +123,11 @@
 
     // Called from native.
     private void notifyDisplayConnected(final Surface surface,
-            final int width, final int height, final int flags) {
+            final int width, final int height, final int flags, final int session) {
         mHandler.post(new Runnable() {
             @Override
             public void run() {
-                mListener.onDisplayConnected(surface, width, height, flags);
+                mListener.onDisplayConnected(surface, width, height, flags, session);
             }
         });
     }
@@ -146,7 +156,8 @@
      * Listener invoked when the remote display connection changes state.
      */
     public interface Listener {
-        void onDisplayConnected(Surface surface, int width, int height, int flags);
+        void onDisplayConnected(Surface surface,
+                int width, int height, int flags, int session);
         void onDisplayDisconnected();
         void onDisplayError(int error);
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 091737d..22e3b98 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -584,7 +584,6 @@
             SaveFragment.get(fm).setReplaceTarget(doc);
         } else if (mAction == ACTION_MANAGE) {
             // Open the document
-            // TODO: trampoline activity for launching downloaded APKs
             final Intent intent = new Intent(Intent.ACTION_VIEW);
             intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
             intent.setData(doc.uri);
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index b4bf563..8843e19 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -20,10 +20,13 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.UriMatcher;
+import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.database.MatrixCursor.RowBuilder;
+import android.media.ExifInterface;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.provider.DocumentsContract;
@@ -296,7 +299,6 @@
                 final Root root = mRoots.get(DocumentsContract.getRootId(uri));
                 final String docId = DocumentsContract.getDocId(uri);
 
-                // TODO: offer as thumbnail
                 final File file = docIdToFile(root, docId);
                 return ParcelFileDescriptor.open(file, ContentResolver.modeToMode(uri, mode));
             }
@@ -307,6 +309,39 @@
     }
 
     @Override
+    public AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts)
+            throws FileNotFoundException {
+        if (opts == null || !opts.containsKey(DocumentsContract.EXTRA_THUMBNAIL_SIZE)) {
+            return super.openTypedAssetFile(uri, mimeTypeFilter, opts);
+        }
+
+        switch (sMatcher.match(uri)) {
+            case URI_DOCS_ID: {
+                final Root root = mRoots.get(DocumentsContract.getRootId(uri));
+                final String docId = DocumentsContract.getDocId(uri);
+
+                final File file = docIdToFile(root, docId);
+                final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+                        file, ParcelFileDescriptor.MODE_READ_ONLY);
+
+                try {
+                    final ExifInterface exif = new ExifInterface(file.getAbsolutePath());
+                    final long[] thumb = exif.getThumbnailRange();
+                    if (thumb != null) {
+                        return new AssetFileDescriptor(pfd, thumb[0], thumb[1]);
+                    }
+                } catch (IOException e) {
+                }
+
+                return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH);
+            }
+            default: {
+                throw new UnsupportedOperationException("Unsupported Uri " + uri);
+            }
+        }
+    }
+
+    @Override
     public Uri insert(Uri uri, ContentValues values) {
         switch (sMatcher.match(uri)) {
             case URI_DOCS_ID: {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index 2904f4c..d4b79b7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -217,7 +217,7 @@
             mCleanupAppWidgetsOnBootCompleted = true;
             return;
         }
-        if (!mSafeModeEnabled && !widgetsDisabledByDpm()) {
+        if (!mSafeModeEnabled && !widgetsDisabled()) {
             // Clean up appWidgetIds that are bound to lockscreen, but not actually used
             // This is only to clean up after another bug: we used to not call
             // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code
@@ -413,8 +413,11 @@
         return disabledFeatures;
     }
 
-    private boolean widgetsDisabledByDpm() {
-        return (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0;
+    private boolean widgetsDisabled() {
+        boolean disabledByDpm =
+                (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0;
+        boolean disabledByUser = !mLockPatternUtils.getWidgetsEnabled();
+        return disabledByDpm || disabledByUser;
     }
 
     private boolean cameraDisabledByDpm() {
@@ -1149,7 +1152,7 @@
     }
 
     private void addDefaultWidgets() {
-        if (!mSafeModeEnabled && !widgetsDisabledByDpm()) {
+        if (!mSafeModeEnabled && !widgetsDisabled()) {
             LayoutInflater inflater = LayoutInflater.from(mContext);
             View addWidget = inflater.inflate(R.layout.keyguard_add_widget, this, false);
             mAppWidgetContainer.addWidget(addWidget, 0);
@@ -1209,7 +1212,7 @@
     }
 
     private void addWidgetsFromSettings() {
-        if (mSafeModeEnabled || widgetsDisabledByDpm()) {
+        if (mSafeModeEnabled || widgetsDisabled()) {
             return;
         }
 
@@ -1246,7 +1249,6 @@
 
         try {
             mAppWidgetManager.bindAppWidgetId(appWidgetId, defaultAppWidget);
-
         } catch (IllegalArgumentException e) {
             Log.e(TAG, "Error when trying to bind default AppWidget: " + e);
             mAppWidgetHost.deleteAppWidgetId(appWidgetId);
@@ -1254,6 +1256,7 @@
         }
         return appWidgetId;
     }
+
     public void checkAppWidgetConsistency() {
         // Since this method may bind a widget (which we can't do until boot completed) we
         // may have to defer it until after boot complete.
@@ -1272,7 +1275,8 @@
         if (!widgetPageExists) {
             final int insertPageIndex = getInsertPageIndex();
 
-            final boolean userAddedWidgetsEnabled = !widgetsDisabledByDpm();
+            final boolean userAddedWidgetsEnabled = !widgetsDisabled();
+
             boolean addedDefaultAppWidget = false;
 
             if (!mSafeModeEnabled) {
diff --git a/services/java/com/android/server/LockSettingsService.java b/services/java/com/android/server/LockSettingsService.java
index e28a258..c5555c8 100644
--- a/services/java/com/android/server/LockSettingsService.java
+++ b/services/java/com/android/server/LockSettingsService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.app.ActivityManagerNative;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -27,6 +28,9 @@
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteStatement;
+import android.media.AudioManager;
+import android.media.AudioService;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.RemoteException;
@@ -37,6 +41,7 @@
 import android.provider.Settings.Secure;
 import android.provider.Settings.SettingNotFoundException;
 import android.text.TextUtils;
+import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.widget.ILockSettings;
@@ -391,7 +396,7 @@
         private static final String TAG = "LockSettingsDB";
         private static final String DATABASE_NAME = "locksettings.db";
 
-        private static final int DATABASE_VERSION = 1;
+        private static final int DATABASE_VERSION = 2;
 
         public DatabaseHelper(Context context) {
             super(context, DATABASE_NAME, null, DATABASE_VERSION);
@@ -424,7 +429,45 @@
 
         @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
-            // Nothing yet
+            int upgradeVersion = oldVersion;
+            if (upgradeVersion == 1) {
+                // Set the initial value for {@link LockPatternUtils#LOCKSCREEN_WIDGETS_ENABLED}
+                // during upgrade based on whether each user previously had widgets in keyguard.
+                maybeEnableWidgetSettingForUsers(db);
+                upgradeVersion = 2;
+            }
+
+            if (upgradeVersion != DATABASE_VERSION) {
+                Log.w(TAG, "Failed to upgrade database!");
+            }
+        }
+
+        private void maybeEnableWidgetSettingForUsers(SQLiteDatabase db) {
+            final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
+            final ContentResolver cr = mContext.getContentResolver();
+            final LockPatternUtils utils = new LockPatternUtils(mContext);
+            final List<UserInfo> users = um.getUsers();
+            for (int i = 0; i < users.size(); i++) {
+                final int userId = users.get(i).id;
+                final boolean enabled = utils.hasWidgetsEnabledInKeyguard(userId);
+                Log.v(TAG, "Widget upgrade uid=" + userId + ", enabled="
+                        + enabled + ", w[]=" + utils.getAppWidgets());
+                loadSetting(db, LockPatternUtils.LOCKSCREEN_WIDGETS_ENABLED, userId, enabled);
+            }
+        }
+
+        private void loadSetting(SQLiteDatabase db, String key, int userId, boolean value) {
+            SQLiteStatement stmt = null;
+            try {
+                stmt = db.compileStatement(
+                        "INSERT OR REPLACE INTO locksettings(name,user,value) VALUES(?,?,?);");
+                stmt.bindString(1, key);
+                stmt.bindLong(2, userId);
+                stmt.bindLong(3, value ? 1 : 0);
+                stmt.execute();
+            } finally {
+                if (stmt != null) stmt.close();
+            }
         }
     }
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8f4b6c2..4678b85 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -7644,7 +7644,7 @@
             sCallerIdentity.set(new Identity(
                     Binder.getCallingPid(), Binder.getCallingUid()));
             try {
-                pfd = cph.provider.openFile(null, uri, "r");
+                pfd = cph.provider.openFile(null, uri, "r", null);
             } catch (FileNotFoundException e) {
                 // do nothing; pfd will be returned null
             } finally {
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 659163c..249c8b0 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -497,6 +497,48 @@
         }
     }
 
+    @Override
+    public void pauseWifiDisplay() {
+        if (mContext.checkCallingPermission(
+                android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+                        != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY"
+                    + "permission to pause a wifi display session.");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSyncRoot) {
+                if (mWifiDisplayAdapter != null) {
+                    mWifiDisplayAdapter.requestPauseLocked();
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    @Override
+    public void resumeWifiDisplay() {
+        if (mContext.checkCallingPermission(
+                android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+                        != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY"
+                    + "permission to resume a wifi display session.");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSyncRoot) {
+                if (mWifiDisplayAdapter != null) {
+                    mWifiDisplayAdapter.requestResumeLocked();
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     @Override // Binder call
     public void disconnectWifiDisplay() {
         final long token = Binder.clearCallingIdentity();
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index a9da30f..f7bbdf8 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -30,6 +30,7 @@
 import android.content.res.Resources;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.WifiDisplay;
+import android.hardware.display.WifiDisplaySessionInfo;
 import android.hardware.display.WifiDisplayStatus;
 import android.media.RemoteDisplay;
 import android.os.Handler;
@@ -93,6 +94,7 @@
     private WifiDisplay[] mDisplays = WifiDisplay.EMPTY_ARRAY;
     private WifiDisplay[] mAvailableDisplays = WifiDisplay.EMPTY_ARRAY;
     private WifiDisplay[] mRememberedDisplays = WifiDisplay.EMPTY_ARRAY;
+    private WifiDisplaySessionInfo mSessionInfo;
 
     private boolean mPendingStatusChangeBroadcast;
     private boolean mPendingNotificationUpdate;
@@ -204,6 +206,36 @@
         return false;
     }
 
+    public void requestPauseLocked() {
+        if (DEBUG) {
+            Slog.d(TAG, "requestPauseLocked");
+        }
+
+        getHandler().post(new Runnable() {
+            @Override
+            public void run() {
+                if (mDisplayController != null) {
+                    mDisplayController.requestPause();
+                }
+            }
+        });
+      }
+
+    public void requestResumeLocked() {
+        if (DEBUG) {
+            Slog.d(TAG, "requestResumeLocked");
+        }
+
+        getHandler().post(new Runnable() {
+            @Override
+            public void run() {
+                if (mDisplayController != null) {
+                    mDisplayController.requestResume();
+                }
+            }
+        });
+    }
+
     public void requestDisconnectLocked() {
         if (DEBUG) {
             Slog.d(TAG, "requestDisconnectedLocked");
@@ -267,7 +299,7 @@
         if (mCurrentStatus == null) {
             mCurrentStatus = new WifiDisplayStatus(
                     mFeatureState, mScanState, mActiveDisplayState,
-                    mActiveDisplay, mDisplays);
+                    mActiveDisplay, mDisplays, mSessionInfo);
         }
 
         if (DEBUG) {
@@ -580,6 +612,14 @@
         }
 
         @Override
+        public void onDisplaySessionInfo(WifiDisplaySessionInfo sessionInfo) {
+            synchronized (getSyncRoot()) {
+                mSessionInfo = sessionInfo;
+                scheduleStatusChangedBroadcastLocked();
+            }
+        }
+
+        @Override
         public void onDisplayChanged(WifiDisplay display) {
             synchronized (getSyncRoot()) {
                 display = mPersistentDataStore.applyWifiDisplayAlias(display);
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index 846a74d..cd201f5 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -25,6 +25,7 @@
 import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.hardware.display.WifiDisplay;
+import android.hardware.display.WifiDisplaySessionInfo;
 import android.hardware.display.WifiDisplayStatus;
 import android.media.AudioManager;
 import android.media.RemoteDisplay;
@@ -76,6 +77,7 @@
     private static final int MAX_THROUGHPUT = 50;
     private static final int CONNECTION_TIMEOUT_SECONDS = 60;
     private static final int RTSP_TIMEOUT_SECONDS = 15;
+    private static final int RTSP_TIMEOUT_SECONDS_CERT_MODE = 120;
 
     private static final int DISCOVER_PEERS_MAX_RETRIES = 10;
     private static final int DISCOVER_PEERS_RETRY_DELAY_MILLIS = 500;
@@ -146,6 +148,10 @@
     private int mAdvertisedDisplayHeight;
     private int mAdvertisedDisplayFlags;
 
+    // Certification
+    private boolean mWifiDisplayCertMode;
+    private WifiP2pDevice mThisDevice;
+
     public WifiDisplayController(Context context, Handler handler, Listener listener) {
         mContext = context;
         mHandler = handler;
@@ -158,6 +164,7 @@
         intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
         intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
         intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+        intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
         context.registerReceiver(mWifiP2pReceiver, intentFilter, null, mHandler);
 
         ContentObserver settingsObserver = new ContentObserver(mHandler) {
@@ -170,6 +177,8 @@
         final ContentResolver resolver = mContext.getContentResolver();
         resolver.registerContentObserver(Settings.Global.getUriFor(
                 Settings.Global.WIFI_DISPLAY_ON), false, settingsObserver);
+        resolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON), false, settingsObserver);
         updateSettings();
     }
 
@@ -177,6 +186,8 @@
         final ContentResolver resolver = mContext.getContentResolver();
         mWifiDisplayOnSetting = Settings.Global.getInt(resolver,
                 Settings.Global.WIFI_DISPLAY_ON, 0) != 0;
+        mWifiDisplayCertMode = Settings.Global.getInt(resolver,
+                Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON, 0) != 0;
 
         updateWfdEnableState();
     }
@@ -223,6 +234,18 @@
         }
     }
 
+    public void requestPause() {
+        if (mRemoteDisplay != null) {
+            mRemoteDisplay.pause();
+        }
+    }
+
+    public void requestResume() {
+        if (mRemoteDisplay != null) {
+            mRemoteDisplay.resume();
+        }
+    }
+
     public void requestDisconnect() {
         disconnect();
     }
@@ -482,6 +505,7 @@
             Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
             mDisconnectingDevice = mConnectedDevice;
             mConnectedDevice = null;
+            mConnectedDeviceGroupInfo = null;
 
             unadvertiseDisplay();
 
@@ -548,8 +572,12 @@
             return; // wait for asynchronous callback
         }
 
-        // Step 4. If we wanted to disconnect, then mission accomplished.
+        // Step 4. If we wanted to disconnect, or we're updating after starting an
+        // autonomous GO, then mission accomplished.
         if (mDesiredDevice == null) {
+            if (mWifiDisplayCertMode) {
+                mListener.onDisplaySessionInfo(getSessionInfo(mConnectedDeviceGroupInfo, 0));
+            }
             unadvertiseDisplay();
             return; // done
         }
@@ -625,13 +653,18 @@
             mRemoteDisplay = RemoteDisplay.listen(iface, new RemoteDisplay.Listener() {
                 @Override
                 public void onDisplayConnected(Surface surface,
-                        int width, int height, int flags) {
+                        int width, int height, int flags, int session) {
                     if (mConnectedDevice == oldDevice && !mRemoteDisplayConnected) {
                         Slog.i(TAG, "Opened RTSP connection with Wifi display: "
                                 + mConnectedDevice.deviceName);
                         mRemoteDisplayConnected = true;
                         mHandler.removeCallbacks(mRtspTimeout);
 
+                        if (mWifiDisplayCertMode) {
+                            mListener.onDisplaySessionInfo(
+                                    getSessionInfo(mConnectedDeviceGroupInfo, session));
+                        }
+
                         final WifiDisplay display = createWifiDisplay(mConnectedDevice);
                         advertiseDisplay(display, surface, width, height, flags);
                     }
@@ -658,10 +691,31 @@
                 }
             }, mHandler);
 
-            mHandler.postDelayed(mRtspTimeout, RTSP_TIMEOUT_SECONDS * 1000);
+            // Use extended timeout value for certification, as some tests require user inputs
+            int rtspTimeout = mWifiDisplayCertMode ?
+                    RTSP_TIMEOUT_SECONDS_CERT_MODE : RTSP_TIMEOUT_SECONDS;
+
+            mHandler.postDelayed(mRtspTimeout, rtspTimeout * 1000);
         }
     }
 
+    private WifiDisplaySessionInfo getSessionInfo(WifiP2pGroup info, int session) {
+        if (info == null) {
+            return null;
+        }
+        Inet4Address addr = getInterfaceAddress(info);
+        WifiDisplaySessionInfo sessionInfo = new WifiDisplaySessionInfo(
+                !info.getOwner().deviceAddress.equals(mThisDevice.deviceAddress),
+                session,
+                info.getOwner().deviceAddress + " " + info.getNetworkName(),
+                info.getPassphrase(),
+                (addr != null) ? addr.getHostAddress() : "");
+        if (DEBUG) {
+            Slog.d(TAG, sessionInfo.toString());
+        }
+        return sessionInfo;
+    }
+
     private void handleStateChanged(boolean enabled) {
         mWifiP2pEnabled = enabled;
         updateWfdEnableState();
@@ -676,7 +730,7 @@
     private void handleConnectionChanged(NetworkInfo networkInfo) {
         mNetworkInfo = networkInfo;
         if (mWfdEnabled && networkInfo.isConnected()) {
-            if (mDesiredDevice != null) {
+            if (mDesiredDevice != null || mWifiDisplayCertMode) {
                 mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, new GroupInfoListener() {
                     @Override
                     public void onGroupInfoAvailable(WifiP2pGroup info) {
@@ -698,6 +752,25 @@
                             return;
                         }
 
+                        if (mWifiDisplayCertMode) {
+                            boolean owner = info.getOwner().deviceAddress
+                                    .equals(mThisDevice.deviceAddress);
+                            if (owner && info.getClientList().isEmpty()) {
+                                // this is the case when we started Autonomous GO,
+                                // and no client has connected, save group info
+                                // and updateConnection()
+                                mConnectingDevice = mDesiredDevice = null;
+                                mConnectedDeviceGroupInfo = info;
+                                updateConnection();
+                            } else if (mConnectingDevice == null && mDesiredDevice == null) {
+                                // this is the case when we received an incoming connection
+                                // from the sink, update both mConnectingDevice and mDesiredDevice
+                                // then proceed to updateConnection() below
+                                mConnectingDevice = mDesiredDevice = owner ?
+                                        info.getClientList().iterator().next() : info.getOwner();
+                            }
+                        }
+
                         if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) {
                             Slog.i(TAG, "Connected to Wifi display: "
                                     + mConnectingDevice.deviceName);
@@ -712,6 +785,7 @@
                 });
             }
         } else {
+            mConnectedDeviceGroupInfo = null;
             disconnect();
 
             // After disconnection for a group, for some reason we have a tendency
@@ -910,6 +984,13 @@
                 }
 
                 handleConnectionChanged(networkInfo);
+            } else if (action.equals(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)) {
+                mThisDevice = (WifiP2pDevice) intent.getParcelableExtra(
+                        WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
+                if (DEBUG) {
+                    Slog.d(TAG, "Received WIFI_P2P_THIS_DEVICE_CHANGED_ACTION: mThisDevice= "
+                            + mThisDevice);
+                }
             }
         }
     };
@@ -928,6 +1009,7 @@
         void onDisplayChanged(WifiDisplay display);
         void onDisplayConnected(WifiDisplay display,
                 Surface surface, int width, int height, int flags);
+        void onDisplaySessionInfo(WifiDisplaySessionInfo sessionInfo);
         void onDisplayDisconnected();
     }
 }
diff --git a/services/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/jni/com_android_server_location_FlpHardwareProvider.cpp
index 9465a68..b403ee6 100644
--- a/services/jni/com_android_server_location_FlpHardwareProvider.cpp
+++ b/services/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -217,6 +217,8 @@
   }
 
   // TODO: wire sources_used if Location class exposes them
+
+  env->DeleteLocalRef(locationClass);
 }
 
 /*
@@ -257,6 +259,8 @@
 
   jmethodID getFlags = env->GetMethodID(batchOptionsClass, "getFlags", "()I");
   batchOptions.flags = env->CallIntMethod(batchOptionsObject, getFlags);
+
+  env->DeleteLocalRef(batchOptionsClass);
 }
 
 /*
@@ -326,6 +330,8 @@
   options->last_transition = env->CallIntMethod(geofenceRequestObject, getLastTransition);
 
   // TODO: set data.sources_to_use when available
+
+  env->DeleteLocalRef(geofenceRequestClass);
 }
 
 /*
@@ -408,6 +414,8 @@
   }
 
   // TODO: wire FlpLocation::sources_used when needed
+
+  sCallbackEnv->DeleteLocalRef(locationClass);
 }
 
 /*
@@ -430,6 +438,8 @@
     sCallbackEnv->SetObjectArrayElement(locationsArray, i, locationObject);
     sCallbackEnv->DeleteLocalRef(locationObject);
   }
+
+  sCallbackEnv->DeleteLocalRef(locationClass);
 }
 
 static void LocationCallback(int32_t locationsCount, FlpLocation** locations) {
@@ -455,6 +465,10 @@
       locationsArray
       );
   CheckExceptions(sCallbackEnv, __FUNCTION__);
+
+  if(locationsArray != NULL) {
+    sCallbackEnv->DeleteLocalRef(locationsArray);
+  }
 }
 
 static void AcquireWakelock() {
@@ -522,6 +536,10 @@
       sourcesUsed
       );
   CheckExceptions(sCallbackEnv, __FUNCTION__);
+
+  if(locationObject != NULL) {
+    sCallbackEnv->DeleteLocalRef(locationObject);
+  }
 }
 
 static void GeofenceMonitorStatusCallback(
@@ -545,6 +563,10 @@
       locationObject
       );
   CheckExceptions(sCallbackEnv, __FUNCTION__);
+
+  if(locationObject != NULL) {
+    sCallbackEnv->DeleteLocalRef(locationObject);
+  }
 }
 
 static void GeofenceAddCallback(int32_t geofenceId, int32_t result) {
@@ -843,6 +865,7 @@
     jobject geofenceObject = env->GetObjectArrayElement(geofenceRequestsArray, i);
 
     TranslateGeofenceFromGeofenceHardwareRequestParcelable(env, geofenceObject, geofences[i]);
+    env->DeleteLocalRef(geofenceObject);
   }
 
   sFlpGeofencingInterface->add_geofences(geofenceRequestsCount, &geofences);
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java
index 373f24a..596ea0a 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-runner/src/android/test/mock/MockContentProvider.java
@@ -83,13 +83,15 @@
         }
 
         @Override
-        public AssetFileDescriptor openAssetFile(String callingPackage, Uri url, String mode)
+        public AssetFileDescriptor openAssetFile(
+                String callingPackage, Uri url, String mode, ICancellationSignal signal)
                 throws RemoteException, FileNotFoundException {
             return MockContentProvider.this.openAssetFile(url, mode);
         }
 
         @Override
-        public ParcelFileDescriptor openFile(String callingPackage, Uri url, String mode)
+        public ParcelFileDescriptor openFile(
+                String callingPackage, Uri url, String mode, ICancellationSignal signal)
                 throws RemoteException, FileNotFoundException {
             return MockContentProvider.this.openFile(url, mode);
         }
@@ -126,7 +128,7 @@
 
         @Override
         public AssetFileDescriptor openTypedAssetFile(String callingPackage, Uri url,
-                String mimeType, Bundle opts)
+                String mimeType, Bundle opts, ICancellationSignal signal)
                 throws RemoteException, FileNotFoundException {
             return MockContentProvider.this.openTypedAssetFile(url, mimeType, opts);
         }
diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-runner/src/android/test/mock/MockIContentProvider.java
index 2b4fce6..b14ce49 100644
--- a/test-runner/src/android/test/mock/MockIContentProvider.java
+++ b/test-runner/src/android/test/mock/MockIContentProvider.java
@@ -61,11 +61,13 @@
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
-    public ParcelFileDescriptor openFile(String callingPackage, Uri url, String mode) {
+    public ParcelFileDescriptor openFile(
+            String callingPackage, Uri url, String mode, ICancellationSignal signal) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
-    public AssetFileDescriptor openAssetFile(String callingPackage, Uri uri, String mode) {
+    public AssetFileDescriptor openAssetFile(
+            String callingPackage, Uri uri, String mode, ICancellationSignal signal) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
@@ -104,7 +106,7 @@
     }
 
     public AssetFileDescriptor openTypedAssetFile(String callingPackage, Uri url, String mimeType,
-            Bundle opts) throws RemoteException, FileNotFoundException {
+            Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
index 4aea38f..688cc87 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -81,14 +81,16 @@
     }
 
     @Override
-    public AssetFileDescriptor openAssetFile(String callingPackage, Uri arg0, String arg1)
+    public AssetFileDescriptor openAssetFile(
+            String callingPackage, Uri arg0, String arg1, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException {
         // TODO Auto-generated method stub
         return null;
     }
 
     @Override
-    public ParcelFileDescriptor openFile(String callingPackage, Uri arg0, String arg1)
+    public ParcelFileDescriptor openFile(
+            String callingPackage, Uri arg0, String arg1, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException {
         // TODO Auto-generated method stub
         return null;
@@ -122,7 +124,7 @@
 
     @Override
     public AssetFileDescriptor openTypedAssetFile(String callingPackage, Uri arg0, String arg1,
-            Bundle arg2) throws RemoteException, FileNotFoundException {
+            Bundle arg2, ICancellationSignal signal) throws RemoteException, FileNotFoundException {
         // TODO Auto-generated method stub
         return null;
     }
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 79c1163..d3342dd 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -619,6 +619,37 @@
         return doBooleanCommand("P2P_LISTEN " + timeout);
     }
 
+    public boolean p2pExtListen(boolean enable, int period, int interval) {
+        if (enable && interval < period) {
+            return false;
+        }
+        return doBooleanCommand("P2P_EXT_LISTEN"
+                    + (enable ? (" " + period + " " + interval) : ""));
+    }
+
+    public boolean p2pSetChannel(int lc, int oc) {
+        if (DBG) Log.d(mTAG, "p2pSetChannel: lc="+lc+", oc="+oc);
+
+        if (lc >=1 && lc <= 11) {
+            if (!doBooleanCommand("P2P_SET listen_channel " + lc)) {
+                return false;
+            }
+        } else if (lc != 0) {
+            return false;
+        }
+
+        if (oc >= 1 && oc <= 165 ) {
+            int freq = (oc <= 14 ? 2407 : 5000) + oc * 5;
+            return doBooleanCommand("P2P_SET disallow_freq 1000-"
+                    + (freq - 5) + "," + (freq + 5) + "-6000");
+        } else if (oc == 0) {
+            /* oc==0 disables "P2P_SET disallow_freq" (enables all freqs) */
+            return doBooleanCommand("P2P_SET disallow_freq \"\"");
+        }
+
+        return false;
+    }
+
     public boolean p2pFlush() {
         return doBooleanCommand("P2P_FLUSH");
     }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 737ab91..4988b92 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -30,6 +30,7 @@
 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceResponse;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Handler;
 import android.os.Looper;
@@ -430,6 +431,28 @@
     /** @hide */
     public static final int START_WPS_SUCCEEDED                     = BASE + 64;
 
+    /** @hide */
+    public static final int START_LISTEN                            = BASE + 65;
+    /** @hide */
+    public static final int START_LISTEN_FAILED                     = BASE + 66;
+    /** @hide */
+    public static final int START_LISTEN_SUCCEEDED                  = BASE + 67;
+
+    /** @hide */
+    public static final int STOP_LISTEN                             = BASE + 68;
+    /** @hide */
+    public static final int STOP_LISTEN_FAILED                      = BASE + 69;
+    /** @hide */
+    public static final int STOP_LISTEN_SUCCEEDED                   = BASE + 70;
+
+    /** @hide */
+    public static final int SET_CHANNEL                             = BASE + 71;
+    /** @hide */
+    public static final int SET_CHANNEL_FAILED                      = BASE + 72;
+    /** @hide */
+    public static final int SET_CHANNEL_SUCCEEDED                   = BASE + 73;
+
+
     /**
      * Create a new WifiP2pManager instance. Applications use
      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
@@ -667,6 +690,9 @@
                     case DELETE_PERSISTENT_GROUP_FAILED:
                     case SET_WFD_INFO_FAILED:
                     case START_WPS_FAILED:
+                    case START_LISTEN_FAILED:
+                    case STOP_LISTEN_FAILED:
+                    case SET_CHANNEL_FAILED:
                         if (listener != null) {
                             ((ActionListener) listener).onFailure(message.arg1);
                         }
@@ -689,6 +715,9 @@
                     case DELETE_PERSISTENT_GROUP_SUCCEEDED:
                     case SET_WFD_INFO_SUCCEEDED:
                     case START_WPS_SUCCEEDED:
+                    case START_LISTEN_SUCCEEDED:
+                    case STOP_LISTEN_SUCCEEDED:
+                    case SET_CHANNEL_SUCCEEDED:
                         if (listener != null) {
                             ((ActionListener) listener).onSuccess();
                         }
@@ -955,6 +984,22 @@
         c.mAsyncChannel.sendMessage(REMOVE_GROUP, 0, c.putListener(listener));
     }
 
+    /** @hide */
+    public void listen(Channel c, boolean enable, ActionListener listener) {
+        checkChannel(c);
+        c.mAsyncChannel.sendMessage(enable ? START_LISTEN : STOP_LISTEN,
+                0, c.putListener(listener));
+    }
+
+    /** @hide */
+    public void setWifiP2pChannels(Channel c, int lc, int oc, ActionListener listener) {
+        checkChannel(c);
+        Bundle p2pChannels = new Bundle();
+        p2pChannels.putInt("lc", lc);
+        p2pChannels.putInt("oc", oc);
+        c.mAsyncChannel.sendMessage(SET_CHANNEL, 0, c.putListener(listener), p2pChannels);
+    }
+
     /**
      * Start a Wi-Fi Protected Setup (WPS) session.
      *
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 63b94a2..05196b8 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -48,6 +48,7 @@
 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
 import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.Handler;
@@ -628,6 +629,9 @@
                 case DhcpStateMachine.CMD_ON_QUIT:
                 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
                 case SET_MIRACAST_MODE:
+                case WifiP2pManager.START_LISTEN:
+                case WifiP2pManager.STOP_LISTEN:
+                case WifiP2pManager.SET_CHANNEL:
                     break;
                 case WifiStateMachine.CMD_ENABLE_P2P:
                     // Enable is lazy and has no response
@@ -729,7 +733,16 @@
                     replyToMessage(message, WifiP2pManager.START_WPS_FAILED,
                             WifiP2pManager.P2P_UNSUPPORTED);
                     break;
-               default:
+                case WifiP2pManager.START_LISTEN:
+                    replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED,
+                            WifiP2pManager.P2P_UNSUPPORTED);
+                    break;
+                case WifiP2pManager.STOP_LISTEN:
+                    replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED,
+                            WifiP2pManager.P2P_UNSUPPORTED);
+                    break;
+
+                default:
                     return NOT_HANDLED;
             }
             return HANDLED;
@@ -1022,6 +1035,35 @@
                 case SET_MIRACAST_MODE:
                     mWifiNative.setMiracastMode(message.arg1);
                     break;
+                case WifiP2pManager.START_LISTEN:
+                    if (DBG) logd(getName() + " start listen mode");
+                    mWifiNative.p2pFlush();
+                    if (mWifiNative.p2pExtListen(true, 500, 500)) {
+                        replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
+                    }
+                    break;
+                case WifiP2pManager.STOP_LISTEN:
+                    if (DBG) logd(getName() + " stop listen mode");
+                    if (mWifiNative.p2pExtListen(false, 0, 0)) {
+                        replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
+                    }
+                    mWifiNative.p2pFlush();
+                    break;
+                case WifiP2pManager.SET_CHANNEL:
+                    Bundle p2pChannels = (Bundle) message.obj;
+                    int lc = p2pChannels.getInt("lc", 0);
+                    int oc = p2pChannels.getInt("oc", 0);
+                    if (DBG) logd(getName() + " set listen and operating channel");
+                    if (mWifiNative.p2pSetChannel(lc, oc)) {
+                        replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
+                    }
+                    break;
                 default:
                    return NOT_HANDLED;
             }
@@ -1171,6 +1213,35 @@
                         mWifiNative.p2pGroupRemove(mGroup.getInterface());
                     }
                     break;
+                case WifiP2pManager.START_LISTEN:
+                    if (DBG) logd(getName() + " start listen mode");
+                    mWifiNative.p2pFlush();
+                    if (mWifiNative.p2pExtListen(true, 500, 500)) {
+                        replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
+                    }
+                    break;
+                case WifiP2pManager.STOP_LISTEN:
+                    if (DBG) logd(getName() + " stop listen mode");
+                    if (mWifiNative.p2pExtListen(false, 0, 0)) {
+                        replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
+                    }
+                    mWifiNative.p2pFlush();
+                    break;
+                case WifiP2pManager.SET_CHANNEL:
+                    Bundle p2pChannels = (Bundle) message.obj;
+                    int lc = p2pChannels.getInt("lc", 0);
+                    int oc = p2pChannels.getInt("oc", 0);
+                    if (DBG) logd(getName() + " set listen and operating channel");
+                    if (mWifiNative.p2pSetChannel(lc, oc)) {
+                        replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
+                    }
+                    break;
                 default:
                     return NOT_HANDLED;
             }