Merge commit '745766e11e8bb7e8642be33be6bdf501af245074' into HEAD

* commit '745766e11e8bb7e8642be33be6bdf501af245074':
  Forward package removed broadcast to KeyChainService
diff --git a/api/current.txt b/api/current.txt
index 06927c3..5018ecf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4297,6 +4297,14 @@
     field public java.lang.String serviceDetails;
   }
 
+  public final class AuthenticationRequiredException extends java.lang.SecurityException implements android.os.Parcelable {
+    ctor public AuthenticationRequiredException(java.lang.Throwable, android.app.PendingIntent);
+    method public int describeContents();
+    method public android.app.PendingIntent getUserAction();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.AuthenticationRequiredException> CREATOR;
+  }
+
   public final class AutomaticZenRule implements android.os.Parcelable {
     ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
     ctor public AutomaticZenRule(android.os.Parcel);
@@ -5708,17 +5716,6 @@
     field public static final int STYLE_SPINNER = 0; // 0x0
   }
 
-  public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
-    ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, android.app.RemoteAction);
-    method public int describeContents();
-    method public android.app.RemoteAction getUserAction();
-    method public java.lang.CharSequence getUserMessage();
-    method public void showAsDialog(android.app.Activity);
-    method public void showAsNotification(android.content.Context, java.lang.String);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.app.RecoverableSecurityException> CREATOR;
-  }
-
   public final class RemoteAction implements android.os.Parcelable {
     ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
     method public android.app.RemoteAction clone();
@@ -24621,6 +24618,7 @@
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+    field public static final java.lang.String COLUMN_LOCKED = "locked";
     field public static final java.lang.String COLUMN_NETWORK_AFFILIATION = "network_affiliation";
     field public static final java.lang.String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
@@ -26280,16 +26278,6 @@
 
 package android.net.wifi {
 
-  public final class IconInfo implements android.os.Parcelable {
-    ctor public IconInfo(java.lang.String, byte[]);
-    ctor public IconInfo(android.net.wifi.IconInfo);
-    method public int describeContents();
-    method public byte[] getData();
-    method public java.lang.String getFilename();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.wifi.IconInfo> CREATOR;
-  }
-
   public class ScanResult implements android.os.Parcelable {
     method public int describeContents();
     method public boolean is80211mcResponder();
@@ -26538,7 +26526,8 @@
     field public static final java.lang.String EXTRA_BSSID_LONG = "android.net.wifi.extra.BSSID_LONG";
     field public static final java.lang.String EXTRA_DELAY = "android.net.wifi.extra.DELAY";
     field public static final java.lang.String EXTRA_ESS = "android.net.wifi.extra.ESS";
-    field public static final java.lang.String EXTRA_ICON_INFO = "android.net.wifi.extra.ICON_INFO";
+    field public static final java.lang.String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
+    field public static final java.lang.String EXTRA_ICON = "android.net.wifi.extra.ICON";
     field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
     field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
     field public static final java.lang.String EXTRA_NEW_STATE = "newState";
@@ -31197,7 +31186,6 @@
     method public final android.util.SizeF readSizeF();
     method public final android.util.SparseArray readSparseArray(java.lang.ClassLoader);
     method public final android.util.SparseBooleanArray readSparseBooleanArray();
-    method public final android.util.SparseIntArray readSparseIntArray();
     method public final java.lang.String readString();
     method public final void readStringArray(java.lang.String[]);
     method public final void readStringList(java.util.List<java.lang.String>);
@@ -31242,7 +31230,6 @@
     method public final void writeSizeF(android.util.SizeF);
     method public final void writeSparseArray(android.util.SparseArray<java.lang.Object>);
     method public final void writeSparseBooleanArray(android.util.SparseBooleanArray);
-    method public final void writeSparseIntArray(android.util.SparseIntArray);
     method public final void writeString(java.lang.String);
     method public final void writeStringArray(java.lang.String[]);
     method public final void writeStringList(java.util.List<java.lang.String>);
diff --git a/api/system-current.txt b/api/system-current.txt
index c99ca68..2bf01d1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4441,6 +4441,14 @@
     field public java.lang.String serviceDetails;
   }
 
+  public final class AuthenticationRequiredException extends java.lang.SecurityException implements android.os.Parcelable {
+    ctor public AuthenticationRequiredException(java.lang.Throwable, android.app.PendingIntent);
+    method public int describeContents();
+    method public android.app.PendingIntent getUserAction();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.AuthenticationRequiredException> CREATOR;
+  }
+
   public final class AutomaticZenRule implements android.os.Parcelable {
     ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
     ctor public AutomaticZenRule(android.os.Parcel);
@@ -5900,17 +5908,6 @@
     field public static final int STYLE_SPINNER = 0; // 0x0
   }
 
-  public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
-    ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, android.app.RemoteAction);
-    method public int describeContents();
-    method public android.app.RemoteAction getUserAction();
-    method public java.lang.CharSequence getUserMessage();
-    method public void showAsDialog(android.app.Activity);
-    method public void showAsNotification(android.content.Context, java.lang.String);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.app.RecoverableSecurityException> CREATOR;
-  }
-
   public final class RemoteAction implements android.os.Parcelable {
     ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
     method public android.app.RemoteAction clone();
@@ -28564,16 +28561,6 @@
     field public boolean truncated;
   }
 
-  public final class IconInfo implements android.os.Parcelable {
-    ctor public IconInfo(java.lang.String, byte[]);
-    ctor public IconInfo(android.net.wifi.IconInfo);
-    method public int describeContents();
-    method public byte[] getData();
-    method public java.lang.String getFilename();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.wifi.IconInfo> CREATOR;
-  }
-
   public class RttManager {
     method public void disableResponder(android.net.wifi.RttManager.ResponderCallback);
     method public void enableResponder(android.net.wifi.RttManager.ResponderCallback);
@@ -29069,7 +29056,8 @@
     field public static final java.lang.String EXTRA_CHANGE_REASON = "changeReason";
     field public static final java.lang.String EXTRA_DELAY = "android.net.wifi.extra.DELAY";
     field public static final java.lang.String EXTRA_ESS = "android.net.wifi.extra.ESS";
-    field public static final java.lang.String EXTRA_ICON_INFO = "android.net.wifi.extra.ICON_INFO";
+    field public static final java.lang.String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
+    field public static final java.lang.String EXTRA_ICON = "android.net.wifi.extra.ICON";
     field public static final java.lang.String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
     field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
     field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
@@ -33925,7 +33913,6 @@
     method public final android.util.SizeF readSizeF();
     method public final android.util.SparseArray readSparseArray(java.lang.ClassLoader);
     method public final android.util.SparseBooleanArray readSparseBooleanArray();
-    method public final android.util.SparseIntArray readSparseIntArray();
     method public final java.lang.String readString();
     method public final void readStringArray(java.lang.String[]);
     method public final void readStringList(java.util.List<java.lang.String>);
@@ -33970,7 +33957,6 @@
     method public final void writeSizeF(android.util.SizeF);
     method public final void writeSparseArray(android.util.SparseArray<java.lang.Object>);
     method public final void writeSparseBooleanArray(android.util.SparseBooleanArray);
-    method public final void writeSparseIntArray(android.util.SparseIntArray);
     method public final void writeString(java.lang.String);
     method public final void writeStringArray(java.lang.String[]);
     method public final void writeStringList(java.util.List<java.lang.String>);
diff --git a/api/test-current.txt b/api/test-current.txt
index d1088dd..da25aa9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4307,6 +4307,14 @@
     field public java.lang.String serviceDetails;
   }
 
+  public final class AuthenticationRequiredException extends java.lang.SecurityException implements android.os.Parcelable {
+    ctor public AuthenticationRequiredException(java.lang.Throwable, android.app.PendingIntent);
+    method public int describeContents();
+    method public android.app.PendingIntent getUserAction();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.AuthenticationRequiredException> CREATOR;
+  }
+
   public final class AutomaticZenRule implements android.os.Parcelable {
     ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
     ctor public AutomaticZenRule(android.os.Parcel);
@@ -5719,17 +5727,6 @@
     field public static final int STYLE_SPINNER = 0; // 0x0
   }
 
-  public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
-    ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, android.app.RemoteAction);
-    method public int describeContents();
-    method public android.app.RemoteAction getUserAction();
-    method public java.lang.CharSequence getUserMessage();
-    method public void showAsDialog(android.app.Activity);
-    method public void showAsNotification(android.content.Context, java.lang.String);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.app.RecoverableSecurityException> CREATOR;
-  }
-
   public final class RemoteAction implements android.os.Parcelable {
     ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
     method public android.app.RemoteAction clone();
@@ -11751,6 +11748,15 @@
     field protected final java.util.ArrayList<T> mObservers;
   }
 
+  public final class PageViewCursor extends android.database.CursorWrapper implements android.database.CrossProcessCursor {
+    ctor public PageViewCursor(android.database.Cursor, int, int);
+    method public void fillWindow(int, android.database.CursorWindow);
+    method public android.database.CursorWindow getWindow();
+    method public boolean onMove(int, int);
+    method public static android.database.Cursor wrap(android.database.Cursor, android.os.Bundle);
+    field public static final java.lang.String EXTRA_AUTO_PAGED = "android.content.extra.AUTO_PAGED";
+  }
+
   public class SQLException extends java.lang.RuntimeException {
     ctor public SQLException();
     ctor public SQLException(java.lang.String);
@@ -24723,6 +24729,7 @@
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+    field public static final java.lang.String COLUMN_LOCKED = "locked";
     field public static final java.lang.String COLUMN_NETWORK_AFFILIATION = "network_affiliation";
     field public static final java.lang.String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
@@ -26382,16 +26389,6 @@
 
 package android.net.wifi {
 
-  public final class IconInfo implements android.os.Parcelable {
-    ctor public IconInfo(java.lang.String, byte[]);
-    ctor public IconInfo(android.net.wifi.IconInfo);
-    method public int describeContents();
-    method public byte[] getData();
-    method public java.lang.String getFilename();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.wifi.IconInfo> CREATOR;
-  }
-
   public class ScanResult implements android.os.Parcelable {
     method public int describeContents();
     method public boolean is80211mcResponder();
@@ -26640,7 +26637,8 @@
     field public static final java.lang.String EXTRA_BSSID_LONG = "android.net.wifi.extra.BSSID_LONG";
     field public static final java.lang.String EXTRA_DELAY = "android.net.wifi.extra.DELAY";
     field public static final java.lang.String EXTRA_ESS = "android.net.wifi.extra.ESS";
-    field public static final java.lang.String EXTRA_ICON_INFO = "android.net.wifi.extra.ICON_INFO";
+    field public static final java.lang.String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
+    field public static final java.lang.String EXTRA_ICON = "android.net.wifi.extra.ICON";
     field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
     field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
     field public static final java.lang.String EXTRA_NEW_STATE = "newState";
@@ -31320,7 +31318,6 @@
     method public final android.util.SizeF readSizeF();
     method public final android.util.SparseArray readSparseArray(java.lang.ClassLoader);
     method public final android.util.SparseBooleanArray readSparseBooleanArray();
-    method public final android.util.SparseIntArray readSparseIntArray();
     method public final java.lang.String readString();
     method public final void readStringArray(java.lang.String[]);
     method public final void readStringList(java.util.List<java.lang.String>);
@@ -31365,7 +31362,6 @@
     method public final void writeSizeF(android.util.SizeF);
     method public final void writeSparseArray(android.util.SparseArray<java.lang.Object>);
     method public final void writeSparseBooleanArray(android.util.SparseBooleanArray);
-    method public final void writeSparseIntArray(android.util.SparseIntArray);
     method public final void writeString(java.lang.String);
     method public final void writeStringArray(java.lang.String[]);
     method public final void writeStringList(java.util.List<java.lang.String>);
diff --git a/core/java/android/app/AuthenticationRequiredException.java b/core/java/android/app/AuthenticationRequiredException.java
new file mode 100644
index 0000000..8960979
--- /dev/null
+++ b/core/java/android/app/AuthenticationRequiredException.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 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.app;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Specialization of {@link SecurityException} that is thrown when authentication is needed from the
+ * end user before viewing the content.
+ * <p>
+ * This exception is only appropriate where there is a concrete action the user can take to
+ * authorize and make forward progress, such as confirming or entering authentication credentials,
+ * or granting access via other means.
+ * <p class="note">
+ * Note: legacy code that receives this exception may treat it as a general
+ * {@link SecurityException}, and thus there is no guarantee that the action contained will be
+ * invoked by the user.
+ * </p>
+ */
+public final class AuthenticationRequiredException extends SecurityException implements Parcelable {
+    private static final String TAG = "AuthenticationRequiredException";
+
+    private final PendingIntent mUserAction;
+
+    /** {@hide} */
+    public AuthenticationRequiredException(Parcel in) {
+        this(new SecurityException(in.readString()), PendingIntent.CREATOR.createFromParcel(in));
+    }
+
+    /**
+     * Create an instance ready to be thrown.
+     *
+     * @param cause original cause with details designed for engineering
+     *            audiences.
+     * @param userAction primary action that will initiate the recovery. This
+     *            must launch an activity that is expected to set
+     *            {@link Activity#setResult(int)} before finishing to
+     *            communicate the final status of the recovery. For example,
+     *            apps that observe {@link Activity#RESULT_OK} may choose to
+     *            immediately retry their operation. If this exception was
+     *            thrown from a {@link ContentProvider}, you should also send
+     *            any relevant {@link ContentResolver#notifyChange} events to
+     *            trigger reloading of data.
+     */
+    public AuthenticationRequiredException(Throwable cause, PendingIntent userAction) {
+        super(cause.getMessage());
+        mUserAction = Preconditions.checkNotNull(userAction);
+    }
+
+    /**
+     * Return primary action that will initiate the authorization.
+     */
+    public PendingIntent getUserAction() {
+        return mUserAction;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(getMessage());
+        mUserAction.writeToParcel(dest, flags);
+    }
+
+    public static final Creator<AuthenticationRequiredException> CREATOR =
+            new Creator<AuthenticationRequiredException>() {
+        @Override
+        public AuthenticationRequiredException createFromParcel(Parcel source) {
+            return new AuthenticationRequiredException(source);
+        }
+
+        @Override
+        public AuthenticationRequiredException[] newArray(int size) {
+            return new AuthenticationRequiredException[size];
+        }
+    };
+}
diff --git a/core/java/android/app/RecoverableSecurityException.java b/core/java/android/app/RecoverableSecurityException.java
index 8612f18..a503a46 100644
--- a/core/java/android/app/RecoverableSecurityException.java
+++ b/core/java/android/app/RecoverableSecurityException.java
@@ -45,7 +45,8 @@
  * Note: legacy code that receives this exception may treat it as a general
  * {@link SecurityException}, and thus there is no guarantee that the messages
  * contained will be shown to the end user.
- * </p>
+ *
+ * @hide
  */
 public final class RecoverableSecurityException extends SecurityException implements Parcelable {
     private static final String TAG = "RecoverableSecurityException";
diff --git a/core/java/android/database/PageViewCursor.java b/core/java/android/database/PageViewCursor.java
index 5f42f30..44727a0 100644
--- a/core/java/android/database/PageViewCursor.java
+++ b/core/java/android/database/PageViewCursor.java
@@ -18,13 +18,13 @@
 import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.content.ContentResolver;
 import android.os.Build;
 import android.os.Bundle;
 import android.util.Log;
 import android.util.MathUtils;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 
 /**
@@ -34,11 +34,10 @@
  *
  * @hide
  */
+@TestApi
 public final class PageViewCursor extends CursorWrapper implements CrossProcessCursor {
 
-    /**
-     * An in internal extra added to results that are auto-paged using the wrapper.
-     */
+    /** An extra added to results that are auto-paged using the wrapper. */
     public static final String EXTRA_AUTO_PAGED = "android.content.extra.AUTO_PAGED";
 
     private static final String TAG = "PageViewCursor";
@@ -56,7 +55,6 @@
     /**
      * @see PageViewCursor#wrap(Cursor, Bundle)
      */
-    @VisibleForTesting
     public PageViewCursor(Cursor cursor, int offset, int limit) {
         super(cursor);
 
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 7a39d23..2e35a51 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -898,6 +898,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public final void writeSparseIntArray(SparseIntArray val) {
         if (val == null) {
             writeInt(-1);
@@ -2323,6 +2326,7 @@
     /**
      * Read and return a new SparseIntArray object from the parcel at the current
      * dataPosition(). Returns null if the previously written array object was null.
+     * @hide
      */
     public final SparseIntArray readSparseIntArray() {
         int N = readInt();
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index f69c996..3137658 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -92,6 +92,12 @@
     public static final int VPN_UID = 1016;
 
     /**
+     * Defines the UID/GID for keystore.
+     * @hide
+     */
+    public static final int KEYSTORE_UID = 1017;
+
+    /**
      * Defines the UID/GID for the NFC service process.
      * @hide
      */
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 620d33a5..9e68afb 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -38,7 +38,7 @@
 import android.Manifest;
 import android.annotation.CallSuper;
 import android.annotation.Nullable;
-import android.app.RecoverableSecurityException;
+import android.app.AuthenticationRequiredException;
 import android.content.ClipDescription;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
@@ -235,10 +235,6 @@
      * {@link Document#COLUMN_DOCUMENT_ID}. You must allocate a new
      * {@link Document#COLUMN_DOCUMENT_ID} to represent the document, which must
      * not change once returned.
-     * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), but it is not guaranteed that
-     * the client will handle this properly.
      *
      * @param parentDocumentId the parent directory to create the new document
      *            under.
@@ -247,6 +243,10 @@
      * @param displayName the display name of the new document. The provider may
      *            alter this name to meet any internal constraints, such as
      *            avoiding conflicting names.
+
+     * @throws AuthenticationRequiredException If authentication is required from the user (such as
+     *             login credentials), but it is not guaranteed that the client will handle this
+     *             properly.
      */
     @SuppressWarnings("unused")
     public String createDocument(String parentDocumentId, String mimeType, String displayName)
@@ -262,15 +262,14 @@
      * URI permission grants will be updated to point at the new document. If
      * the original {@link Document#COLUMN_DOCUMENT_ID} is still valid after the
      * rename, return {@code null}.
-     * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), but it is not guaranteed that
-     * the client will handle this properly.
      *
      * @param documentId the document to rename.
      * @param displayName the updated display name of the document. The provider
      *            may alter this name to meet any internal constraints, such as
      *            avoiding conflicting names.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
      */
     @SuppressWarnings("unused")
     public String renameDocument(String documentId, String displayName)
@@ -286,12 +285,11 @@
      * call (such as documents inside a directory) the implementor is
      * responsible for revoking those permissions using
      * {@link #revokeDocumentPermission(String)}.
-     * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), but it is not guaranteed that
-     * the client will handle this properly.
      *
      * @param documentId the document to delete.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
      */
     @SuppressWarnings("unused")
     public void deleteDocument(String documentId) throws FileNotFoundException {
@@ -305,13 +303,12 @@
      * the same document provider. Upon completion returns the document id of
      * the copied document at the target destination. {@code null} must never
      * be returned.
-     * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), but it is not guaranteed that
-     * the client will handle this properly.
      *
      * @param sourceDocumentId the document to copy.
      * @param targetParentDocumentId the target document to be copied into as a child.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
      */
     @SuppressWarnings("unused")
     public String copyDocument(String sourceDocumentId, String targetParentDocumentId)
@@ -329,15 +326,14 @@
      *
      * <p>It's the responsibility of the provider to revoke grants if the document
      * is no longer accessible using <code>sourceDocumentId</code>.
-     * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), but it is not guaranteed that
-     * the client will handle this properly.
      *
      * @param sourceDocumentId the document to move.
      * @param sourceParentDocumentId the parent of the document to move.
      * @param targetParentDocumentId the target document to be a new parent of the
      *     source document.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
      */
     @SuppressWarnings("unused")
     public String moveDocument(String sourceDocumentId, String sourceParentDocumentId,
@@ -355,11 +351,11 @@
      * <p>It's the responsibility of the provider to revoke grants if the document is
      * removed from the last parent, and effectively the document is deleted.
      *
-     * <p>{@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), but it is not guaranteed that
-     * the client will handle this properly.
      * @param documentId the document to remove.
      * @param parentDocumentId the parent of the document to move.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
      */
     @SuppressWarnings("unused")
     public void removeDocument(String documentId, String parentDocumentId)
@@ -377,9 +373,6 @@
      * <p>This API assumes that document ID has enough info to infer the root.
      * Different roots should use different document ID to refer to the same
      * document.
-     * <p>{@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), but it is not guaranteed that
-     * the client will handle this properly.perly.
      *
      *
      * @param parentDocumentId the document from which the path starts if not null,
@@ -388,6 +381,9 @@
      * @return the path of the requested document. If parentDocumentId is null
      *     returned root ID must not be null. If parentDocumentId is not null
      *     returned root ID must be null.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
      */
     public Path findDocumentPath(@Nullable String parentDocumentId, String childDocumentId)
             throws FileNotFoundException {
@@ -397,7 +393,7 @@
     /**
      * Creates an intent sender for a web link, if the document is web linkable.
      * <p>
-     * {@link RecoverableSecurityException} can be thrown if user does not have
+     * {@link AuthenticationRequiredException} can be thrown if user does not have
      * sufficient permission for the linked document. Before any new permissions
      * are granted for the linked document, a visible UI must be shown, so the
      * user can explicitly confirm whether the permission grants are expected.
@@ -414,6 +410,9 @@
      *
      * @param documentId the document to create a web link intent for.
      * @param options additional information, such as list of recipients. Optional.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
      *
      * @see DocumentsContract.Document#FLAG_WEB_LINKABLE
      * @see android.app.PendingIntent#getIntentSender
@@ -436,9 +435,6 @@
      * android.database.ContentObserver, boolean)} with
      * {@link DocumentsContract#buildRootsUri(String)} to notify the system.
      * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), or returned as part of
-     * Cursor's bundle. It is not guaranteed that the client will handle this properly.
      *
      * @param projection list of {@link Root} columns to put into the cursor. If
      *            {@code null} all supported columns should be included.
@@ -452,10 +448,6 @@
      * sorted by {@link Document#COLUMN_LAST_MODIFIED} in descending order, and
      * limited to only return the 64 most recently modified documents.
      * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), or returned as part of
-     * Cursor's bundle. It is not guaranteed that the client will handle this properly.
-     * <p>
      * Recent documents do not support change notifications.
      *
      * @param projection list of {@link Document} columns to put into the
@@ -472,16 +464,14 @@
     /**
      * Return metadata for the single requested document. You should avoid
      * making network requests to keep this request fast.
-     * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), or returned as part of
-     * Cursor's bundle. It is not guaranteed that the client will handle this properly.
-     *
      *
      * @param documentId the document to return.
      * @param projection list of {@link Document} columns to put into the
      *            cursor. If {@code null} all supported columns should be
      *            included.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
      */
     public abstract Cursor queryDocument(String documentId, String[] projection)
             throws FileNotFoundException;
@@ -509,11 +499,6 @@
      * you can call {@link ContentResolver#notifyChange(Uri,
      * android.database.ContentObserver, boolean)} with that Uri to send change
      * notifications.
-     * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), or returned as part of
-     * Cursor's bundle. It is not guaranteed that the client will handle this properly.
-     *
      *
      * @param parentDocumentId the directory to return children for.
      * @param projection list of {@link Document} columns to put into the
@@ -525,6 +510,9 @@
      *            may be unordered. This ordering is a hint that can be used to
      *            prioritize how data is fetched from the network, but UI may
      *            always enforce a specific ordering.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
      * @see DocumentsContract#EXTRA_LOADING
      * @see DocumentsContract#EXTRA_INFO
      * @see DocumentsContract#EXTRA_ERROR
@@ -552,10 +540,6 @@
      * you can call {@link ContentResolver#notifyChange(Uri,
      * android.database.ContentObserver, boolean)} with that Uri to send change
      * notifications.
-     * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), or returned as part of
-     * Cursor's bundle. It is not guaranteed that the client will handle this properly.
      *
      * @param parentDocumentId the directory to return children for.
      * @param projection list of {@link Document} columns to put into the
@@ -567,6 +551,9 @@
      *            will be used, which may be unordered. See
      *            {@link ContentResolver#QUERY_ARG_SORT_COLUMNS} for
      *            details.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
      *
      * @see DocumentsContract#EXTRA_LOADING
      * @see DocumentsContract#EXTRA_INFO
@@ -609,16 +596,16 @@
      * String, String)}. Then you can call {@link ContentResolver#notifyChange(Uri,
      * android.database.ContentObserver, boolean)} with that Uri to send change
      * notifications.
-     * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), or returned as part of
-     * Cursor's bundle. It is not guaranteed that the client will handle this properly.
      *
      * @param rootId the root to search under.
      * @param query string to match documents against.
      * @param projection list of {@link Document} columns to put into the
      *            cursor. If {@code null} all supported columns should be
      *            included.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
+     *
      * @see DocumentsContract#EXTRA_LOADING
      * @see DocumentsContract#EXTRA_INFO
      * @see DocumentsContract#EXTRA_ERROR
@@ -641,9 +628,9 @@
      * implementation queries {@link #queryDocument(String, String[])}, so
      * providers may choose to override this as an optimization.
      * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), but it is not guaranteed that
-     * the client will handle this properly.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
      */
     public String getDocumentType(String documentId) throws FileNotFoundException {
         final Cursor cursor = queryDocument(documentId, null);
@@ -669,15 +656,14 @@
      * <p>
      * If you block while downloading content, you should periodically check
      * {@link CancellationSignal#isCanceled()} to abort abandoned open requests.
-     * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), but it is not guaranteed that
-     * the client will handle this properly.
      *
      * @param documentId the document to return.
      * @param mode the mode to open with, such as 'r', 'w', or 'rw'.
      * @param signal used by the caller to signal if the request should be
      *            cancelled. May be null.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
      * @see ParcelFileDescriptor#open(java.io.File, int, android.os.Handler,
      *      OnCloseListener)
      * @see ParcelFileDescriptor#createReliablePipe()
@@ -697,15 +683,14 @@
      * If you perform expensive operations to download or generate a thumbnail,
      * you should periodically check {@link CancellationSignal#isCanceled()} to
      * abort abandoned thumbnail requests.
-     * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), but it is not guaranteed that
-     * the client will handle this properly.
      *
      * @param documentId the document to return.
      * @param sizeHint hint of the optimal thumbnail dimensions.
      * @param signal used by the caller to signal if the request should be
      *            cancelled. May be null.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
      * @see Document#FLAG_SUPPORTS_THUMBNAIL
      */
     @SuppressWarnings("unused")
@@ -723,10 +708,6 @@
      * matching the specified MIME type filter.
      * <p>
      * Virtual documents must have at least one streamable format.
-     * <p>
-     * {@link RecoverableSecurityException} can be thrown if more input is required
-     * from the user (such as insufficient permission), but it is not guaranteed that
-     * the client will handle this properly.
      *
      * @param documentId the document to return.
      * @param mimeTypeFilter the MIME type filter for the requested format. May
@@ -735,6 +716,9 @@
      *            provider.
      * @param signal used by the caller to signal if the request should be
      *            cancelled. May be null.
+     * @throws AuthenticationRequiredException If authentication is required from
+     *            the user (such as login credentials), but it is not guaranteed
+     *            that the client will handle this properly.
      * @see #getDocumentStreamTypes(String, String)
      */
     @SuppressWarnings("unused")
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 7b99d07..78d18fd 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -75,6 +75,7 @@
     private int mDropDownWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
     private boolean mDropDownVerticalOffsetSet;
     private boolean mIsAnimatedFromAnchor = true;
+    private boolean mOverlapAnchor;
 
     private int mDropDownGravity = Gravity.NO_GRAVITY;
 
@@ -672,6 +673,7 @@
             mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
             mPopup.setTouchInterceptor(mTouchInterceptor);
             mPopup.setEpicenterBounds(mEpicenterBounds);
+            mPopup.setOverlapAnchor(mOverlapAnchor);
             mPopup.showAsDropDown(getAnchorView(), mDropDownHorizontalOffset,
                     mDropDownVerticalOffset, mDropDownGravity);
             mDropDownList.setSelection(ListView.INVALID_POSITION);
@@ -1245,6 +1247,13 @@
         return listContent + otherHeights;
     }
 
+    /**
+     * @hide
+     */
+    public void setOverlapAnchor(boolean overlap) {
+        mOverlapAnchor = overlap;
+    }
+
     private class PopupDataSetObserver extends DataSetObserver {
         @Override
         public void onChanged() {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 26b3ae2..9f10531 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -55,6 +55,7 @@
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
+import android.view.WindowManagerGlobal;
 
 import com.android.internal.R;
 
@@ -137,6 +138,7 @@
 
     private final int[] mTmpDrawingLocation = new int[2];
     private final int[] mTmpScreenLocation = new int[2];
+    private final int[] mTmpAppLocation = new int[2];
     private final Rect mTempRect = new Rect();
 
     private Context mContext;
@@ -242,6 +244,9 @@
 
     private final OnScrollChangedListener mOnScrollChangedListener = this::alignToAnchor;
 
+    private final View.OnLayoutChangeListener mOnLayoutChangeListener =
+            (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> alignToAnchor();
+
     private int mAnchorXoff;
     private int mAnchorYoff;
     private int mAnchoredGravity;
@@ -1238,7 +1243,8 @@
         mIsShowing = true;
         mIsDropdown = true;
 
-        final WindowManager.LayoutParams p = createPopupLayoutParams(anchor.getWindowToken());
+        final WindowManager.LayoutParams p =
+                createPopupLayoutParams(anchor.getApplicationWindowToken());
         preparePopup(p);
 
         final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,
@@ -1547,13 +1553,21 @@
         }
 
         // Initially, align to the bottom-left corner of the anchor plus offsets.
+        final int[] appScreenLocation = mTmpAppLocation;
+        final View appRootView = getAppRootView(anchor);
+        appRootView.getLocationOnScreen(appScreenLocation);
+
+        final int[] screenLocation = mTmpScreenLocation;
+        anchor.getLocationOnScreen(screenLocation);
+
         final int[] drawingLocation = mTmpDrawingLocation;
-        anchor.getLocationInWindow(drawingLocation);
+        drawingLocation[0] = screenLocation[0] - appScreenLocation[0];
+        drawingLocation[1] = screenLocation[1] - appScreenLocation[1];
         outParams.x = drawingLocation[0] + xOffset;
         outParams.y = drawingLocation[1] + anchorHeight + yOffset;
 
         final Rect displayFrame = new Rect();
-        anchor.getWindowVisibleDisplayFrame(displayFrame);
+        appRootView.getWindowVisibleDisplayFrame(displayFrame);
         if (width == MATCH_PARENT) {
             width = displayFrame.right - displayFrame.left;
         }
@@ -1574,9 +1588,6 @@
             outParams.x -= width - anchorWidth;
         }
 
-        final int[] screenLocation = mTmpScreenLocation;
-        anchor.getLocationOnScreen(screenLocation);
-
         // First, attempt to fit the popup vertically without resizing.
         final boolean fitsVertical = tryFitVertical(outParams, yOffset, height,
                 anchorHeight, drawingLocation[1], screenLocation[1], displayFrame.top,
@@ -1595,7 +1606,9 @@
                     scrollY + height + anchorHeight + yOffset);
             if (allowScroll && anchor.requestRectangleOnScreen(r, true)) {
                 // Reset for the new anchor position.
-                anchor.getLocationInWindow(drawingLocation);
+                anchor.getLocationOnScreen(screenLocation);
+                drawingLocation[0] = screenLocation[0] - appScreenLocation[0];
+                drawingLocation[1] = screenLocation[1] - appScreenLocation[1];
                 outParams.x = drawingLocation[0] + xOffset;
                 outParams.y = drawingLocation[1] + anchorHeight + yOffset;
 
@@ -1793,7 +1806,8 @@
         Rect displayFrame = null;
         final Rect visibleDisplayFrame = new Rect();
 
-        anchor.getWindowVisibleDisplayFrame(visibleDisplayFrame);
+        final View appView = getAppRootView(anchor);
+        appView.getWindowVisibleDisplayFrame(visibleDisplayFrame);
         if (ignoreBottomDecorations) {
             // In the ignore bottom decorations case we want to
             // still respect all other decorations so we use the inset visible
@@ -2240,6 +2254,7 @@
         final View anchorRoot = mAnchorRoot != null ? mAnchorRoot.get() : null;
         if (anchorRoot != null) {
             anchorRoot.removeOnAttachStateChangeListener(mOnAnchorRootDetachedListener);
+            anchorRoot.removeOnLayoutChangeListener(mOnLayoutChangeListener);
         }
 
         mAnchor = null;
@@ -2258,6 +2273,7 @@
 
         final View anchorRoot = anchor.getRootView();
         anchorRoot.addOnAttachStateChangeListener(mOnAnchorRootDetachedListener);
+        anchorRoot.addOnLayoutChangeListener(mOnLayoutChangeListener);
 
         mAnchor = new WeakReference<>(anchor);
         mAnchorRoot = new WeakReference<>(anchorRoot);
@@ -2281,6 +2297,15 @@
         }
     }
 
+    private View getAppRootView(View anchor) {
+        final View appWindowView = WindowManagerGlobal.getInstance().getWindowView(
+                anchor.getApplicationWindowToken());
+        if (appWindowView != null) {
+            return appWindowView;
+        }
+        return anchor.getRootView();
+    }
+
     private class PopupDecorView extends FrameLayout {
         private TransitionListenerAdapter mPendingExitListener;
 
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index ebcec5c..6dff8b4 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -381,6 +381,7 @@
 
         if (parentView != null) {
             // This menu is a cascading submenu anchored to a parent view.
+            popupWindow.setAnchorView(parentView);
             popupWindow.setTouchModal(false);
             popupWindow.setEnterTransition(null);
 
@@ -388,42 +389,30 @@
             final boolean showOnRight = nextMenuPosition == HORIZ_POSITION_RIGHT;
             mLastPosition = nextMenuPosition;
 
-            // A popup anchored to mAnchorView with (0,0) offset would be shown at this position.
-            final int[] offsetOrigin = new int[2];
-            mAnchorView.getLocationOnScreen(offsetOrigin);
-            offsetOrigin[1] += mAnchorView.getHeight();
-
-            final int[] parentViewScreenLocation = new int[2];
-            parentView.getLocationOnScreen(parentViewScreenLocation);
-
-            // Translate the parent view location into the offset coordinate space.
-            // If used as horizontal/vertical offsets, these values would position the submenu
-            // at the exact same position as the parent item.
-            final int parentOffsetLeft = parentViewScreenLocation[0] - offsetOrigin[0];
-            final int parentOffsetTop = parentViewScreenLocation[1] - offsetOrigin[1];
-
-            // Adjust the horizontal offset to display the submenu to the right or to the left
+            // Compute the horizontal offset to display the submenu to the right or to the left
             // of the parent item.
             // By now, mDropDownGravity is the resolved absolute gravity, so
             // this should work in both LTR and RTL.
             final int x;
             if ((mDropDownGravity & Gravity.RIGHT) == Gravity.RIGHT) {
                 if (showOnRight) {
-                    x = parentOffsetLeft + menuWidth;
+                    x = menuWidth;
                 } else {
-                    x = parentOffsetLeft - parentView.getWidth();
+                    x = -parentView.getWidth();
                 }
             } else {
                 if (showOnRight) {
-                    x = parentOffsetLeft + parentView.getWidth();
+                    x = parentView.getWidth();
                 } else {
-                    x = parentOffsetLeft - menuWidth;
+                    x = -menuWidth;
                 }
             }
             popupWindow.setHorizontalOffset(x);
 
-            // Use the same vertical offset as the parent item.
-            popupWindow.setVerticalOffset(parentOffsetTop);
+            // Align with the top edge of the parent view (or the bottom edge when the submenu is
+            // flipped vertically).
+            popupWindow.setOverlapAnchor(true);
+            popupWindow.setVerticalOffset(0);
         } else {
             if (mHasXOffset) {
                 popupWindow.setHorizontalOffset(mXOffset);
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index a8d6830..de5e505 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -621,7 +621,7 @@
     const uint8_t* s = (const uint8_t*)src;
     do {
         uint8_t c = *s++;
-        *dst++ = SkColorSetARGB(c, c, c, c);
+        *dst++ = SkColorSetARGB(c, 0, 0, 0);
     } while (--width != 0);
 }
 
@@ -727,6 +727,50 @@
     return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable));
 }
 
+static bool bitmapCopyTo(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src,
+        SkBitmap::Allocator* alloc) {
+    // Skia does not support copying from kAlpha8 to types that are not alpha only.
+    // We will handle this case here.
+    if (kAlpha_8_SkColorType == src.colorType() && kAlpha_8_SkColorType != dstCT) {
+        SkAutoPixmapUnlock srcUnlocker;
+        if (!src.requestLock(&srcUnlocker)) {
+            return false;
+        }
+        SkPixmap srcPixmap = srcUnlocker.pixmap();
+
+        SkImageInfo dstInfo = src.info().makeColorType(dstCT);
+        if (!dst->setInfo(dstInfo)) {
+            return false;
+        }
+        if (!dst->tryAllocPixels(alloc, nullptr)) {
+            return false;
+        }
+
+        switch (dstCT) {
+            case kRGBA_8888_SkColorType:
+            case kBGRA_8888_SkColorType: {
+                for (int y = 0; y < src.height(); y++) {
+                    const uint8_t* srcRow = srcPixmap.addr8(0, y);
+                    uint32_t* dstRow = dst->getAddr32(0, y);
+                    ToColor_SA8(dstRow, srcRow, src.width(), nullptr);
+                }
+                return true;
+            }
+            case kRGB_565_SkColorType: {
+                for (int y = 0; y < src.height(); y++) {
+                    uint16_t* dstRow = dst->getAddr16(0, y);
+                    memset(dstRow, 0, sizeof(uint16_t) * src.width());
+                }
+                return true;
+            }
+            default:
+                return false;
+        }
+    }
+
+    return src.copyTo(dst, dstCT, alloc);
+}
+
 static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
                            jint dstConfigHandle, jboolean isMutable) {
     SkBitmap src;
@@ -743,7 +787,7 @@
     SkBitmap result;
     HeapAllocator allocator;
 
-    if (!src.copyTo(&result, dstCT, &allocator)) {
+    if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
         return NULL;
     }
     auto bitmap = allocator.getStorageObjAndReset();
@@ -754,7 +798,7 @@
     SkBitmap result;
 
     AshmemPixelAllocator allocator(env);
-    if (!src.copyTo(&result, dstCT, &allocator)) {
+    if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
         return NULL;
     }
     auto bitmap = allocator.getStorageObjAndReset();
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index c28aa5e..6808b57 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1971,10 +1971,11 @@
          * channel is not locked thus the user is not prompted to enter passcode If not specified,
          * this value is set to 0 (not locked) by default.
          *
+         * <p>This column can only be set by applications having proper system permission to
+         * modify parental control settings. For other applications, this is a read-only column.
+
          * <p>Type: INTEGER (boolean)
-         * @hide
          */
-        @SystemApi
         public static final String COLUMN_LOCKED = "locked";
 
         /**
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8dc694c..d6d01d8a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1382,11 +1382,15 @@
         of notifications.  Replaces the channel name and only appears when there is more than one channel. -->
     <string name="notification_num_channels"> <xliff:g id="number">%d</xliff:g> notification categories</string>
 
+    <!-- Notification: Control panel: Label that shows when an app has not upgraded to use channels.
+        Hints that the user's only option is to block all of the app's notifications. -->
+    <string name="notification_default_channel_desc">This app doesn\'t have notification categories</string>
+
     <!-- Notification: Control panel: Label that shows how many channels this application has
-        defined, describing the current notification channel as "1 out of n categories from this app". -->
+        defined, describing the current notification channel as "1 out of n notification categories from this app". -->
     <plurals name="notification_num_channels_desc">
-        <item quantity="one">1 out of <xliff:g id="number">%d</xliff:g> category from this app</item>
-        <item quantity="other">1 out of <xliff:g id="number">%d</xliff:g> categories from this app</item>
+        <item quantity="one">1 out of <xliff:g id="number">%d</xliff:g> notification category from this app</item>
+        <item quantity="other">1 out of <xliff:g id="number">%d</xliff:g> notification categories from this app</item>
     </plurals>
 
     <!-- Notification: Control panel: For bundles of notifications, this label that lists the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index a9043e4..54921a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -99,11 +99,14 @@
         mINotificationManager = iNotificationManager;
         mPkg = pkg;
         mNotificationChannels = notificationChannels;
+        boolean isSingleDefaultChannel = false;
         if (mNotificationChannels.isEmpty()) {
             throw new IllegalArgumentException("bindNotification requires at least one channel");
         } else if (mNotificationChannels.size() == 1) {
             mSingleNotificationChannel = mNotificationChannels.get(0);
             mStartingUserImportance = mSingleNotificationChannel.getImportance();
+            isSingleDefaultChannel = mSingleNotificationChannel.getId()
+                    .equals(NotificationChannel.DEFAULT_CHANNEL_ID);
         } else {
             mSingleNotificationChannel = null;
         }
@@ -135,24 +138,30 @@
 
         String channelsDescText;
         mNumChannelsView = (TextView) (findViewById(R.id.num_channels_desc));
-        switch (mNotificationChannels.size()) {
-            case 1:
-                channelsDescText = String.format(mContext.getResources().getQuantityString(
-                        R.plurals.notification_num_channels_desc, numChannels), numChannels);
-                break;
-            case 2:
-                channelsDescText = mContext.getString(R.string.notification_channels_list_desc_2,
-                        mNotificationChannels.get(0).getName(),
-                        mNotificationChannels.get(1).getName());
-                break;
-            default:
-                final int numOthers = mNotificationChannels.size() - 2;
-                channelsDescText = String.format(
-                        mContext.getResources().getQuantityString(
-                                R.plurals.notification_channels_list_desc_2_and_others, numOthers),
-                        mNotificationChannels.get(0).getName(),
-                        mNotificationChannels.get(1).getName(),
-                        numOthers);
+        if (isSingleDefaultChannel) {
+            channelsDescText = mContext.getString(R.string.notification_default_channel_desc);
+        } else {
+            switch (mNotificationChannels.size()) {
+                case 1:
+                    channelsDescText = String.format(mContext.getResources().getQuantityString(
+                            R.plurals.notification_num_channels_desc, numChannels), numChannels);
+                    break;
+                case 2:
+                    channelsDescText = mContext.getString(
+                            R.string.notification_channels_list_desc_2,
+                            mNotificationChannels.get(0).getName(),
+                            mNotificationChannels.get(1).getName());
+                    break;
+                default:
+                    final int numOthers = mNotificationChannels.size() - 2;
+                    channelsDescText = String.format(
+                            mContext.getResources().getQuantityString(
+                                    R.plurals.notification_channels_list_desc_2_and_others,
+                                    numOthers),
+                            mNotificationChannels.get(0).getName(),
+                            mNotificationChannels.get(1).getName(),
+                            numOthers);
+            }
         }
         mNumChannelsView.setText(channelsDescText);
 
@@ -160,9 +169,8 @@
             // Multiple channels don't use a channel name for the title.
             channelNameText = mContext.getString(R.string.notification_num_channels,
                     mNotificationChannels.size());
-        } else if (mSingleNotificationChannel.getId()
-                .equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
-            // If this is the placeholder channel, don't use our channel-specific text.
+        } else if (isSingleDefaultChannel) {
+            // If this is the default channel, don't use our channel-specific text.
             channelNameText = mContext.getString(R.string.notification_header_default_channel);
         } else {
             channelNameText = mSingleNotificationChannel.getName();
@@ -282,15 +290,9 @@
     }
 
     private void updateSecondaryText() {
-        final boolean defaultChannel = mSingleNotificationChannel != null &&
-                mSingleNotificationChannel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID);
         final boolean disabled = mSingleNotificationChannel != null &&
                 getSelectedImportance() == NotificationManager.IMPORTANCE_NONE;
-        if (defaultChannel) {
-            // Don't show any secondary text if this is from the default channel.
-            mChannelDisabledView.setVisibility(View.GONE);
-            mNumChannelsView.setVisibility(View.GONE);
-        } else if (disabled) {
+        if (disabled) {
             mChannelDisabledView.setVisibility(View.VISIBLE);
             mNumChannelsView.setVisibility(View.GONE);
         } else {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 8aca546..5632b71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -260,12 +260,14 @@
     }
 
     @Test
-    public void testBindNotification_NumChannelsTextHiddenWhenDefaultChannel() throws Exception {
+    public void testBindNotification_NumChannelsTextUniqueWhenDefaultChannel() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel), null, null, null);
         final TextView numChannelsView =
                 (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
-        assertTrue(numChannelsView.getVisibility() != View.VISIBLE);
+        assertEquals(View.VISIBLE, numChannelsView.getVisibility());
+        assertEquals(mContext.getString(R.string.notification_default_channel_desc),
+                numChannelsView.getText());
     }
 
     @Test
@@ -390,13 +392,14 @@
 
     @Test
     @UiThreadTest
-    public void testBindNotification_ChannelDisabledTextHiddenWhenDefaultChannel()
+    public void testBindNotification_ChannelDisabledTextShowsForDefaultChannel()
             throws Exception {
+        mDefaultNotificationChannel.setImportance(NotificationManager.IMPORTANCE_NONE);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel), null, null, null);
         final TextView channelDisabledView =
                 (TextView) mNotificationInfo.findViewById(R.id.channel_disabled);
-        assertTrue(channelDisabledView.getVisibility() != View.VISIBLE);
+        assertEquals(View.VISIBLE, channelDisabledView.getVisibility());
     }
 
     @Test
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3d18160..ede5a5e 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -179,6 +179,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -3116,8 +3117,19 @@
                         + " - notification=" + notification);
                 return;
             }
-            throw new IllegalArgumentException("No Channel found for channelId=" + channelId
-                    + ", notification=" + notification);
+            final String noChannelStr = "No Channel found for "
+                    + "pkg=" + pkg
+                    + ", channelId=" + channelId
+                    + ", opPkg=" + opPkg
+                    + ", callingUid=" + callingUid
+                    + ", userId=" + userId
+                    + ", incomingUserId=" + incomingUserId
+                    + ", notificationUid=" + notificationUid
+                    + ", notification=" + notification;
+            // STOPSHIP TODO: should throw instead of logging.
+            // throw new IllegalArgumentException(noChannelStr);
+            Log.e(TAG, noChannelStr);
+            return;
         }
         final StatusBarNotification n = new StatusBarNotification(
                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
@@ -3640,6 +3652,10 @@
             mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
                     effect, record.getAudioAttributes());
             return true;
+        } catch (IllegalArgumentException e) {
+            Slog.e(TAG, "Error creating vibration waveform with pattern: " +
+                    Arrays.toString(vibration));
+            return false;
         } finally{
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index db23a6a..342ec4b 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -29,9 +29,10 @@
     private static final boolean DEBUG = false;
 
     private final Context mContext;
-    private final LegacyGlobalActions mLegacyGlobalActions;
     private final StatusBarManagerInternal mStatusBarInternal;
     private final Handler mHandler;
+    private final WindowManagerFuncs mWindowManagerFuncs;
+    private LegacyGlobalActions mLegacyGlobalActions;
     private boolean mKeyguardShowing;
     private boolean mDeviceProvisioned;
     private boolean mStatusBarConnected;
@@ -40,8 +41,7 @@
     public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) {
         mContext = context;
         mHandler = new Handler();
-        mLegacyGlobalActions = new LegacyGlobalActions(context, windowManagerFuncs,
-                this::onGlobalActionsDismissed);
+        mWindowManagerFuncs = windowManagerFuncs;
         mStatusBarInternal = LocalServices.getService(StatusBarManagerInternal.class);
 
         // Some form factors do not have a status bar.
@@ -50,6 +50,12 @@
         }
     }
 
+    private void ensureLegacyCreated() {
+        if (mLegacyGlobalActions != null) return;
+        mLegacyGlobalActions = new LegacyGlobalActions(mContext, mWindowManagerFuncs,
+                this::onGlobalActionsDismissed);
+    }
+
     public void showDialog(boolean keyguardShowing, boolean deviceProvisioned) {
         if (DEBUG) Slog.d(TAG, "showDialog " + keyguardShowing + " " + deviceProvisioned);
         mKeyguardShowing = keyguardShowing;
@@ -60,6 +66,7 @@
             mHandler.postDelayed(mShowTimeout, 5000);
         } else {
             // SysUI isn't alive, show legacy menu.
+            ensureLegacyCreated();
             mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
         }
     }
@@ -83,6 +90,7 @@
         mStatusBarConnected = connected;
         if (mShowing && !mStatusBarConnected) {
             // Status bar died but we need to be showing global actions still, show the legacy.
+            ensureLegacyCreated();
             mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
         }
     }
@@ -92,6 +100,7 @@
         public void run() {
             if (DEBUG) Slog.d(TAG, "Global actions timeout");
             // We haven't heard from sysui, show the legacy dialog.
+            ensureLegacyCreated();
             mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
         }
     };
diff --git a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
index 0b80d81..ab9ab67 100644
--- a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
+++ b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
@@ -21,6 +21,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Binder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.security.keymaster.KeyAttestationPackageInfo;
@@ -45,14 +46,19 @@
 
     public KeyAttestationApplicationId getKeyAttestationApplicationId(int uid)
             throws RemoteException {
-        String[] packageNames = mPackageManager.getPackagesForUid(uid);
-        if (packageNames == null) {
-            throw new RemoteException("No packages for uid");
+        if (Binder.getCallingUid() != android.os.Process.KEYSTORE_UID) {
+            throw new SecurityException("This service can only be used by Keystore");
         }
-        int userId = UserHandle.getUserId(uid);
-        KeyAttestationPackageInfo[] keyAttestationPackageInfos =
-                new KeyAttestationPackageInfo[packageNames.length];
+        KeyAttestationPackageInfo[] keyAttestationPackageInfos = null;
+        final long token = Binder.clearCallingIdentity();
         try {
+            String[] packageNames = mPackageManager.getPackagesForUid(uid);
+            if (packageNames == null) {
+                throw new RemoteException("No packages for uid");
+            }
+            int userId = UserHandle.getUserId(uid);
+            keyAttestationPackageInfos = new KeyAttestationPackageInfo[packageNames.length];
+
             for (int i = 0; i < packageNames.length; ++i) {
                 PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(packageNames[i],
                         PackageManager.GET_SIGNATURES, userId);
@@ -61,6 +67,8 @@
             }
         } catch (NameNotFoundException nnfe) {
             throw new RemoteException(nnfe.getMessage());
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
         return new KeyAttestationApplicationId(keyAttestationPackageInfos);
     }
diff --git a/wifi/java/android/net/wifi/IconInfo.aidl b/wifi/java/android/net/wifi/IconInfo.aidl
deleted file mode 100644
index a7bb2ef..0000000
--- a/wifi/java/android/net/wifi/IconInfo.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-parcelable IconInfo;
diff --git a/wifi/java/android/net/wifi/IconInfo.java b/wifi/java/android/net/wifi/IconInfo.java
deleted file mode 100644
index 0eae363..0000000
--- a/wifi/java/android/net/wifi/IconInfo.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.os.Parcel;
-
-import java.util.Arrays;
-import java.util.Objects;
-
-/**
- * A class representing icon information.
- */
-public final class IconInfo implements Parcelable {
-    /**
-     * Name of the icon file.
-     */
-    private final String mFilename;
-
-    /**
-     * Raw binary data of the icon.
-     */
-    private final byte[] mData;
-
-    public IconInfo(String filename, byte[] data) {
-        mFilename = filename;
-        mData = data;
-    }
-
-    public IconInfo(IconInfo source) {
-        if (source == null) {
-            mFilename = null;
-            mData = null;
-            return;
-        }
-
-        mFilename = source.mFilename;
-        if (source.mData != null) {
-            mData = Arrays.copyOf(source.mData, source.mData.length);
-        } else {
-            mData = null;
-        }
-    }
-
-    public String getFilename() {
-        return mFilename;
-    }
-
-    public byte[] getData() {
-        return mData;
-    }
-
-    @Override
-    public boolean equals(Object thatObject) {
-        if (this == thatObject) {
-            return true;
-        }
-        if (!(thatObject instanceof IconInfo)) {
-            return false;
-        }
-        IconInfo that = (IconInfo) thatObject;
-        return TextUtils.equals(mFilename, that.mFilename)
-                && Arrays.equals(mData, that.mData);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mFilename, mData);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mFilename);
-        dest.writeByteArray(mData);
-    }
-
-    public static final Creator<IconInfo> CREATOR =
-        new Creator<IconInfo>() {
-            @Override
-            public IconInfo createFromParcel(Parcel in) {
-                String filename = in.readString();
-                byte[] data = in.createByteArray();
-                return new IconInfo(filename, data);
-            }
-
-            @Override
-            public IconInfo[] newArray(int size) {
-                return new IconInfo[size];
-            }
-        };
-}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 4f2881b..824c436 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -120,7 +120,8 @@
      *
      * Included extras:
      * {@link #EXTRA_BSSID_LONG}
-     * {@link #EXTRA_ICON_INFO}
+     * {@link #EXTRA_FILENAME}
+     * {@link #EXTRA_ICON}
      *
      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
      *
@@ -136,12 +137,18 @@
      */
     public static final String EXTRA_BSSID_LONG = "android.net.wifi.extra.BSSID_LONG";
     /**
-     * Icon information.
+     * Icon data.
      *
      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)} and cast into
-     * {@link IconInfo}.
+     * {@link android.graphics.drawable.Icon}.
      */
-    public static final String EXTRA_ICON_INFO = "android.net.wifi.extra.ICON_INFO";
+    public static final String EXTRA_ICON = "android.net.wifi.extra.ICON";
+    /**
+     * Name of a file.
+     *
+     * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
+     */
+    public static final String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
 
     /**
      * Broadcast intent action indicating a Passpoint OSU Providers List element has been received.
@@ -984,9 +991,9 @@
 
     /**
      * Query for a Hotspot 2.0 release 2 OSU icon file. An {@link #ACTION_PASSPOINT_ICON} intent
-     * will be broadcasted once the request is completed.  The return value of
-     * {@link IconInfo#getData} from the intent extra will indicate the result of the request.
-     * A value of {@code null} will indicate a failure.
+     * will be broadcasted once the request is completed.  The presence of the intent extra
+     * {@link #EXTRA_ICON} will indicate the result of the request.
+     * A missing intent extra {@link #EXTRA_ICON} will indicate a failure.
      *
      * @param bssid The BSSID of the AP
      * @param fileName Name of the icon file (remote file) to query from the AP
diff --git a/wifi/tests/src/android/net/wifi/IconInfoTest.java b/wifi/tests/src/android/net/wifi/IconInfoTest.java
deleted file mode 100644
index 2fdb484..0000000
--- a/wifi/tests/src/android/net/wifi/IconInfoTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net.wifi;
-
-import static org.junit.Assert.assertEquals;
-
-import android.net.wifi.IconInfo;
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Unit tests for {@link android.net.wifi.IconInfo}.
- */
-@SmallTest
-public class IconInfoTest {
-    private static final String TEST_FILENAME = "testIcon";
-    private static final byte[] TEST_DATA = new byte[] {0x12, 0x23, 0x34, 0x45, 0x56, 0x67};
-
-    /**
-     * Verify parcel write and read consistency for the given {@link IconInfo}
-     *
-     * @param writeIcon the {@link IconInfo} to write and verify
-     * @throws Exception
-     */
-    private static void verifyParcel(IconInfo writeIcon) throws Exception {
-        Parcel parcel = Parcel.obtain();
-        writeIcon.writeToParcel(parcel, 0);
-
-        parcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
-        IconInfo readIcon = IconInfo.CREATOR.createFromParcel(parcel);
-        assertEquals(writeIcon, readIcon);
-    }
-
-    /**
-     * Verify parcel serialization for a {@link IconInfo} with null data.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void verifyParcelWithNullData() throws Exception {
-        verifyParcel(new IconInfo(TEST_FILENAME, (byte[]) null));
-    }
-
-    /**
-     * Verify parcel serialization for a {@link IconInfo} with zero length data.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void verifyParcelWithZeroLengthData() throws Exception {
-        verifyParcel(new IconInfo(TEST_FILENAME, new byte[0]));
-    }
-
-    /**
-     * Verify parcel serialization for a {@link IconInfo} with non-zero length data.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void verifyParcelWithNonZeroLengthData() throws Exception {
-        verifyParcel(new IconInfo(TEST_FILENAME, TEST_DATA));
-    }
-
-    /**
-     * Verify parcel serialization for a {@link IconInfo} with a null filename.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void verifyParcelWithNullFilename() throws Exception {
-        verifyParcel(new IconInfo(null, TEST_DATA));
-    }
-
-    /**
-     * Verify the copy constructor with non-null filename and data.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void verifyCopyConstructor() throws Exception {
-        IconInfo source = new IconInfo(TEST_FILENAME, TEST_DATA);
-        assertEquals(source, new IconInfo(source));
-    }
-
-    /**
-     * Verify the copy constructor with null data.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void verifyCopyConstructorWithNullData() throws Exception {
-        IconInfo source = new IconInfo(TEST_FILENAME, (byte[]) null);
-        assertEquals(source, new IconInfo(source));
-    }
-
-    /**
-     * Verify the copy constructor with null file name.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void verifyCopyConstructorWithNullFilename() throws Exception {
-        IconInfo source = new IconInfo(null, TEST_DATA);
-        assertEquals(source, new IconInfo(source));
-    }
-}