Merge "Protect against null detail record." into mnc-dev
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 667ed02..48be749 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -234,6 +234,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/lib/libinputflingerhost.so $(PRODUCT_OUT)/obj_arm/lib/libinputflingerhost.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libinputflingerhost_intermediates $(PRODUCT_OUT)/obj_arm/SHARED_LIBRARIES/libinputflingerhost_intermediates)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/target/common/obj/framework.aidl)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
 
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/api/current.txt b/api/current.txt
index 567b172..cfb9398 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5681,23 +5681,6 @@
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
   }
 
-  public class DeviceInitializerStatus {
-    field public static final int FLAG_STATUS_CUSTOM = 33554432; // 0x2000000
-    field public static final int FLAG_STATUS_ERROR = 16777216; // 0x1000000
-    field public static final int FLAG_STATUS_HIGH_PRIORITY = 134217728; // 0x8000000
-    field public static final int FLAG_STATUS_RESERVED = 67108864; // 0x4000000
-    field public static final int STATUS_ERROR_CONNECT_WIFI = 16777237; // 0x1000015
-    field public static final int STATUS_ERROR_DELETE_APPS = 16777242; // 0x100001a
-    field public static final int STATUS_ERROR_DOUBLE_BUMP = 16777246; // 0x100001e
-    field public static final int STATUS_ERROR_DOWNLOAD_PACKAGE = 16777239; // 0x1000017
-    field public static final int STATUS_ERROR_INSTALL_PACKAGE = 16777240; // 0x1000018
-    field public static final int STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING = 16777238; // 0x1000016
-    field public static final int STATUS_ERROR_SET_DEVICE_POLICY = 16777241; // 0x1000019
-    field public static final int STATUS_STATE_CONNECTING_BLUETOOTH_PROXY = 134217736; // 0x8000008
-    field public static final int STATUS_STATE_DEVICE_PROVISIONED = 134217738; // 0x800000a
-    field public static final int STATUS_STATE_DISCONNECTING_BLUETOOTH_PROXY = 134217737; // 0x8000009
-  }
-
   public class DevicePolicyManager {
     method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
     method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
@@ -5765,7 +5748,6 @@
     method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
     method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
     method public boolean resetPassword(java.lang.String, int);
-    method public void sendDeviceInitializerStatus(int, java.lang.String);
     method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
     method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
@@ -5829,10 +5811,6 @@
     field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
     field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
     field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
-    field public static final java.lang.String EXTRA_PROVISIONING_BT_DEVICE_ID = "android.app.extra.PROVISIONING_BT_DEVICE_ID";
-    field public static final java.lang.String EXTRA_PROVISIONING_BT_MAC_ADDRESS = "android.app.extra.PROVISIONING_BT_MAC_ADDRESS";
-    field public static final java.lang.String EXTRA_PROVISIONING_BT_USE_PROXY = "android.app.extra.PROVISIONING_BT_USE_PROXY";
-    field public static final java.lang.String EXTRA_PROVISIONING_BT_UUID = "android.app.extra.PROVISIONING_BT_UUID";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE";
diff --git a/api/system-current.txt b/api/system-current.txt
index a4e4848..6035ef2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5781,23 +5781,6 @@
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
   }
 
-  public class DeviceInitializerStatus {
-    field public static final int FLAG_STATUS_CUSTOM = 33554432; // 0x2000000
-    field public static final int FLAG_STATUS_ERROR = 16777216; // 0x1000000
-    field public static final int FLAG_STATUS_HIGH_PRIORITY = 134217728; // 0x8000000
-    field public static final int FLAG_STATUS_RESERVED = 67108864; // 0x4000000
-    field public static final int STATUS_ERROR_CONNECT_WIFI = 16777237; // 0x1000015
-    field public static final int STATUS_ERROR_DELETE_APPS = 16777242; // 0x100001a
-    field public static final int STATUS_ERROR_DOUBLE_BUMP = 16777246; // 0x100001e
-    field public static final int STATUS_ERROR_DOWNLOAD_PACKAGE = 16777239; // 0x1000017
-    field public static final int STATUS_ERROR_INSTALL_PACKAGE = 16777240; // 0x1000018
-    field public static final int STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING = 16777238; // 0x1000016
-    field public static final int STATUS_ERROR_SET_DEVICE_POLICY = 16777241; // 0x1000019
-    field public static final int STATUS_STATE_CONNECTING_BLUETOOTH_PROXY = 134217736; // 0x8000008
-    field public static final int STATUS_STATE_DEVICE_PROVISIONED = 134217738; // 0x800000a
-    field public static final int STATUS_STATE_DISCONNECTING_BLUETOOTH_PROXY = 134217737; // 0x8000009
-  }
-
   public class DevicePolicyManager {
     method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
     method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
@@ -5874,7 +5857,6 @@
     method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
     method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
     method public boolean resetPassword(java.lang.String, int);
-    method public void sendDeviceInitializerStatus(int, java.lang.String);
     method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
     method public deprecated boolean setActiveProfileOwner(android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException;
     method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
@@ -5927,7 +5909,6 @@
     field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
-    field public static final java.lang.String ACTION_SEND_DEVICE_INITIALIZER_STATUS = "android.app.action.SEND_DEVICE_INITIALIZER_STATUS";
     field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final java.lang.String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
     field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
@@ -5939,15 +5920,9 @@
     field public static final int ENCRYPTION_STATUS_UNSUPPORTED = 0; // 0x0
     field public static final java.lang.String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
     field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
-    field public static final java.lang.String EXTRA_DEVICE_INITIALIZER_STATUS_CODE = "android.app.extra.DEVICE_INITIALIZER_STATUS_CODE";
-    field public static final java.lang.String EXTRA_DEVICE_INITIALIZER_STATUS_DESCRIPTION = "android.app.extra.DEVICE_INITIALIZER_STATUS_DESCRIPTION";
     field public static final java.lang.String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
     field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
-    field public static final java.lang.String EXTRA_PROVISIONING_BT_DEVICE_ID = "android.app.extra.PROVISIONING_BT_DEVICE_ID";
-    field public static final java.lang.String EXTRA_PROVISIONING_BT_MAC_ADDRESS = "android.app.extra.PROVISIONING_BT_MAC_ADDRESS";
-    field public static final java.lang.String EXTRA_PROVISIONING_BT_USE_PROXY = "android.app.extra.PROVISIONING_BT_USE_PROXY";
-    field public static final java.lang.String EXTRA_PROVISIONING_BT_UUID = "android.app.extra.PROVISIONING_BT_UUID";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE";
diff --git a/core/java/android/app/admin/DeviceInitializerStatus.java b/core/java/android/app/admin/DeviceInitializerStatus.java
deleted file mode 100644
index 7de518b..0000000
--- a/core/java/android/app/admin/DeviceInitializerStatus.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.admin;
-
-/**
- * Defines constants designating device provisioning status used with {@link
- * android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}.
- *
- * This class contains flag constants that define special status codes:
- * <ul>
- * <li>{@link #FLAG_STATUS_ERROR} is used to define provisioning error status codes
- * <li>{@link #FLAG_STATUS_CUSTOM} is used to define custom status codes
- * <li>{@link #FLAG_STATUS_HIGH_PRIORITY} is used to define high priority status codes
- * </ul>
- *
- * <p>Status codes used by ManagedProvisioning are also defined in this class. These status codes
- * include provisioning errors and status codes.
- * <ul>
- * <li>{@link #STATUS_ERROR_CONNECT_WIFI}
- * <li>{@link #STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING}
- * <li>{@link #STATUS_ERROR_DOWNLOAD_PACKAGE}
- * <li>{@link #STATUS_ERROR_INSTALL_PACKAGE}
- * <li>{@link #STATUS_ERROR_SET_DEVICE_POLICY}
- * <li>{@link #STATUS_ERROR_DELETE_APPS}
- * <li>{@link #STATUS_ERROR_DOUBLE_BUMP}
- * <li>{@link #STATUS_STATE_CONNECTING_BLUETOOTH_PROXY}
- * <li>{@link #STATUS_STATE_DISCONNECTING_BLUETOOTH_PROXY}
- * <li>{@link #STATUS_STATE_DEVICE_PROVISIONED}
- * </ul>
- */
-public class DeviceInitializerStatus {
-    /**
-     * A flag used to designate an error status.
-     *
-     * <p>This flag is used with {@code statusCode} values sent through
-     * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}
-     * @see #isErrorStatus(int)
-     */
-    public static final int FLAG_STATUS_ERROR = 0x01000000;
-
-    /**
-     * A flag used to designate a custom status. Custom status codes will be defined by device
-     * initializer agents.
-     *
-     * <p>This flag is used with {@code statusCode} values sent through
-     * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}
-     * @see #isCustomStatus(int)
-     */
-    public static final int FLAG_STATUS_CUSTOM = 0x02000000;
-
-    /**
-     * A bit flag used to designate a reserved status. Reserved status codes will not be defined
-     * in AOSP.
-     *
-     * <p>This flag is used with {@code statusCode} values sent through
-     * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}
-     */
-    public static final int FLAG_STATUS_RESERVED = 0x04000000;
-
-    /**
-     * A flag used to indicate that a status message is high priority.
-     *
-     * <p>This flag is used with {@code statusCode} values sent through
-     * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}
-     * @see #isHighPriority(int)
-     */
-    public static final int FLAG_STATUS_HIGH_PRIORITY = 0x08000000;
-
-    /**
-     * Device provisioning status code that indicates that a device is connecting to establish
-     * a Bluetooth network proxy.
-     */
-    public static final int STATUS_STATE_CONNECTING_BLUETOOTH_PROXY = FLAG_STATUS_HIGH_PRIORITY | 8;
-
-    /**
-     * Device provisioning status code that indicates that a connected Bluetooth network proxy
-     * is being shut down.
-     */
-    public static final int STATUS_STATE_DISCONNECTING_BLUETOOTH_PROXY = FLAG_STATUS_HIGH_PRIORITY | 9;
-
-    /**
-     * Device provisioning status code that indicates that a device has been successfully
-     * provisioned.
-     */
-    public static final int STATUS_STATE_DEVICE_PROVISIONED = FLAG_STATUS_HIGH_PRIORITY | 10;
-
-    /**
-     * Device provisioning error status code that indicates that a device could not connect to
-     * a Wi-Fi network.
-     */
-    public static final int STATUS_ERROR_CONNECT_WIFI = FLAG_STATUS_ERROR | 21;
-
-    /**
-     * Device provisioning error status indicating that factory reset protection is enabled on
-     * the provisioned device and cannot be disabled with the provided data.
-     */
-    public static final int STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING =
-            FLAG_STATUS_ERROR | 22;
-
-    /**
-     * Device provisioning error status indicating that device administrator and device initializer
-     * packages could not be downloaded and verified successfully.
-     */
-    public static final int STATUS_ERROR_DOWNLOAD_PACKAGE = FLAG_STATUS_ERROR | 23;
-
-    /**
-     * Device provisioning error status indicating that device owner and device initializer packages
-     * could not be installed.
-     */
-    public static final int STATUS_ERROR_INSTALL_PACKAGE = FLAG_STATUS_ERROR | 24;
-
-    /**
-     * Device provisioning error status indicating that the device owner or device initializer
-     * components could not be set.
-     */
-    public static final int STATUS_ERROR_SET_DEVICE_POLICY = FLAG_STATUS_ERROR | 25;
-
-    /**
-     * Device provisioning error status indicating that deleting non-required applications during
-     * provisioning failed.
-     */
-    public static final int STATUS_ERROR_DELETE_APPS = FLAG_STATUS_ERROR | 26;
-
-    /**
-     * Device provisioning error status code that indicates that a provisioning attempt has failed
-     * because the device has already been provisioned or that provisioning has already started.
-     */
-    public static final int STATUS_ERROR_DOUBLE_BUMP = FLAG_STATUS_ERROR | 30;
-
-    private DeviceInitializerStatus() {}
-}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index bf44746..996748a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -540,50 +540,6 @@
         = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM";
 
     /**
-     * A String extra holding the MAC address of the Bluetooth device to connect to with status
-     * updates during provisioning.
-     *
-     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
-     * provisioning via an NFC bump.
-     */
-    public static final String EXTRA_PROVISIONING_BT_MAC_ADDRESS
-            = "android.app.extra.PROVISIONING_BT_MAC_ADDRESS";
-
-    /**
-     * A String extra holding the Bluetooth service UUID on the device to connect to with status
-     * updates during provisioning.
-     *
-     * <p>This value must be specified when {@code #EXTRA_PROVISIONING_BT_MAC_ADDRESS} is present.
-     *
-     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
-     * provisioning via an NFC bump.
-     */
-    public static final String EXTRA_PROVISIONING_BT_UUID
-            = "android.app.extra.PROVISIONING_BT_UUID";
-
-    /**
-     * A String extra holding a unique identifier used to identify the device connecting over
-     * Bluetooth. This identifier will be part of every status message sent to the remote device.
-     *
-     * <p>This value must be specified when {@code #EXTRA_PROVISIONING_BT_MAC_ADDRESS} is present.
-     *
-     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
-     * provisioning via an NFC bump.
-     */
-    public static final String EXTRA_PROVISIONING_BT_DEVICE_ID
-            = "android.app.extra.PROVISIONING_BT_DEVICE_ID";
-
-    /**
-     * A Boolean extra that that will cause a provisioned device to temporarily proxy network
-     * traffic over Bluetooth. When a Wi-Fi network is available, the network proxy will stop.
-     *
-     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
-     * provisioning via an NFC bump.
-     */
-    public static final String EXTRA_PROVISIONING_BT_USE_PROXY
-            = "android.app.extra.PROVISIONING_BT_USE_PROXY";
-
-    /**
      * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
      * holds data needed by the system to wipe factory reset protection. The data needed to wipe
      * the device depend on the installed factory reset protection implementation. For example,
@@ -665,11 +621,7 @@
      * Replaces {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}. The value of the property
      * should be converted to a String via
      * {@link android.content.ComponentName#flattenToString()}</li>
-     * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE}, optional</li>
-     * <li>{@link #EXTRA_PROVISIONING_BT_MAC_ADDRESS}, optional</li>
-     * <li>{@link #EXTRA_PROVISIONING_BT_UUID}, optional</li>
-     * <li>{@link #EXTRA_PROVISIONING_BT_DEVICE_ID}, optional</li>
-     * <li>{@link #EXTRA_PROVISIONING_BT_USE_PROXY}, optional</li></ul>
+     * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE}, optional</li></ul>
      *
      * <p> When device owner provisioning has completed, an intent of the type
      * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the
@@ -727,45 +679,6 @@
             = "android.app.action.SET_PROFILE_OWNER";
 
     /**
-     * Protected broadcast action that will be sent to managed provisioning to notify it that a
-     * status update has been reported by the device initializer. The status update will be
-     * reported to the remote setup device over Bluetooth.
-     *
-     * <p>Broadcasts with this action must supply a
-     * {@linkplain DeviceInitializerStatus#FLAG_STATUS_CUSTOM custom} status code in the
-     * {@link EXTRA_DEVICE_INITIALIZER_STATUS_CODE} extra.
-     *
-     * <p>Broadcasts may optionally contain a description in the
-     * {@link EXTRA_DEVICE_INITIALIZER_STATUS_DESCRIPTION} extra.
-     * @hide
-     */
-    @SystemApi
-    public static final String ACTION_SEND_DEVICE_INITIALIZER_STATUS
-            = "android.app.action.SEND_DEVICE_INITIALIZER_STATUS";
-
-    /**
-     * An integer extra that contains the status code that defines a status update. This extra must
-     * sent as part of a broadcast with an action of {@code ACTION_SEND_DEVICE_INITIALIZER_STATUS}.
-     *
-     * <p>The status code sent with this extra must be a custom status code as defined by
-     * {@link DeviceInitializerStatus#FLAG_STATUS_CUSTOM}.
-     * @hide
-     */
-    @SystemApi
-    public static final String EXTRA_DEVICE_INITIALIZER_STATUS_CODE
-            = "android.app.extra.DEVICE_INITIALIZER_STATUS_CODE";
-
-    /**
-     * A {@code String} extra that contains an optional description accompanying a status update.
-     * This extra my be sent as part of a broadcast with an action of
-     * {@code ACTION_SEND_DEVICE_INITIALIZER_STATUS}.
-     * @hide
-     */
-    @SystemApi
-    public static final String EXTRA_DEVICE_INITIALIZER_STATUS_DESCRIPTION
-            = "android.app.extra.DEVICE_INITIALIZER_STATUS_DESCRIPTION";
-
-    /**
      * @hide
      * Name of the profile owner admin that controls the user.
      */
@@ -3975,6 +3888,9 @@
      * <p>Any packages that shares uid with an allowed package will also be allowed
      * to activate lock task.
      *
+     * From {@link android.os.Build.VERSION_CODES#MNC} removing packages from the lock task
+     * package list results in locked tasks belonging to those packages to be finished.
+     *
      * This function can only be called by the device owner.
      * @param packages The list of packages allowed to enter lock task mode
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -4288,21 +4204,6 @@
     }
 
     /**
-     * Called by device initializer to send a provisioning status update to the remote setup device.
-     *
-     * @param statusCode a custom status code value as defined by
-     *    {@link DeviceInitializerStatus#FLAG_STATUS_CUSTOM}.
-     * @param description custom description of the status code sent
-     */
-    public void sendDeviceInitializerStatus(int statusCode, String description) {
-        try {
-            mService.sendDeviceInitializerStatus(statusCode, description);
-        } catch (RemoteException re) {
-            Log.w(TAG, "Could not send device initializer status", re);
-        }
-    }
-
-    /**
      * Called by device owners to set a local system update policy. When a new policy is set,
      * {@link #ACTION_SYSTEM_UPDATE_POLICY_CHANGED} is broadcasted.
      *
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index a700806..376a3d8 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -220,7 +220,6 @@
 
     void setUserIcon(in ComponentName admin, in Bitmap icon);
 
-    void sendDeviceInitializerStatus(int statusCode, String description);
     void setSystemUpdatePolicy(in ComponentName who, in SystemUpdatePolicy policy);
     SystemUpdatePolicy getSystemUpdatePolicy();
 
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 1c9c713..135f369 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -621,6 +621,9 @@
             final int fd = getFd();
             Parcel.clearFileDescriptor(mFd);
             writeCommStatusAndClose(Status.DETACHED, null);
+            mClosed = true;
+            mGuard.close();
+            releaseResources();
             return fd;
         }
     }
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index 04e54aa..5bc45d5 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -80,6 +80,12 @@
         if (label.toLowerCase().contains("generic")) {
             return false;
         }
+        if (label.toLowerCase().startsWith("usb")) {
+            return false;
+        }
+        if (label.toLowerCase().startsWith("multiple")) {
+            return false;
+        }
         return true;
     }
 
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 4bd085f..979c828 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.app.NotificationManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -31,6 +32,7 @@
 import android.os.Message;
 import android.preference.VolumePreference.VolumeStore;
 import android.provider.Settings;
+import android.provider.Settings.Global;
 import android.provider.Settings.System;
 import android.util.Log;
 import android.widget.SeekBar;
@@ -46,7 +48,7 @@
     public interface Callback {
         void onSampleStarting(SeekBarVolumizer sbv);
         void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch);
-        void onMuted(boolean muted);
+        void onMuted(boolean muted, boolean zenMuted);
     }
 
     private final Context mContext;
@@ -54,6 +56,7 @@
     private final Callback mCallback;
     private final Uri mDefaultUri;
     private final AudioManager mAudioManager;
+    private final NotificationManager mNotificationManager;
     private final int mStreamType;
     private final int mMaxStreamVolume;
     private boolean mAffectedByRingerMode;
@@ -63,12 +66,14 @@
     private Handler mHandler;
     private Observer mVolumeObserver;
     private int mOriginalStreamVolume;
+    private int mLastAudibleStreamVolume;
     private Ringtone mRingtone;
     private int mLastProgress = -1;
     private boolean mMuted;
     private SeekBar mSeekBar;
     private int mVolumeBeforeMute = -1;
     private int mRingerMode;
+    private int mZenMode;
 
     private static final int MSG_SET_STREAM_VOLUME = 0;
     private static final int MSG_START_SAMPLE = 1;
@@ -78,19 +83,22 @@
 
     public SeekBarVolumizer(Context context, int streamType, Uri defaultUri, Callback callback) {
         mContext = context;
-        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        mAudioManager = context.getSystemService(AudioManager.class);
+        mNotificationManager = context.getSystemService(NotificationManager.class);
         mStreamType = streamType;
         mAffectedByRingerMode = mAudioManager.isStreamAffectedByRingerMode(mStreamType);
         mNotificationOrRing = isNotificationOrRing(mStreamType);
         if (mNotificationOrRing) {
             mRingerMode = mAudioManager.getRingerModeInternal();
         }
+        mZenMode = mNotificationManager.getZenMode();
         mMaxStreamVolume = mAudioManager.getStreamMaxVolume(mStreamType);
         mCallback = callback;
         mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
+        mLastAudibleStreamVolume = mAudioManager.getLastAudibleStreamVolume(mStreamType);
         mMuted = mAudioManager.isStreamMute(mStreamType);
         if (mCallback != null) {
-            mCallback.onMuted(mMuted);
+            mCallback.onMuted(mMuted, isZenMuted());
         }
         if (defaultUri == null) {
             if (mStreamType == AudioManager.STREAM_RING) {
@@ -119,8 +127,17 @@
         mSeekBar.setOnSeekBarChangeListener(this);
     }
 
+    private boolean isZenMuted() {
+        return mNotificationOrRing && mZenMode == Global.ZEN_MODE_ALARMS
+                || mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
+    }
+
     protected void updateSeekBar() {
-        if (mNotificationOrRing && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
+        final boolean zenMuted = isZenMuted();
+        mSeekBar.setEnabled(!zenMuted);
+        if (zenMuted) {
+            mSeekBar.setProgress(mLastAudibleStreamVolume);
+        } else if (mNotificationOrRing && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
             mSeekBar.setProgress(0);
         } else if (mMuted) {
             mSeekBar.setProgress(0);
@@ -316,11 +333,12 @@
             if (msg.what == UPDATE_SLIDER) {
                 if (mSeekBar != null) {
                     mLastProgress = msg.arg1;
-                    final boolean muted = msg.arg2 != 0;
+                    mLastAudibleStreamVolume = Math.abs(msg.arg2);
+                    final boolean muted = msg.arg2 < 0;
                     if (muted != mMuted) {
                         mMuted = muted;
                         if (mCallback != null) {
-                            mCallback.onMuted(mMuted);
+                            mCallback.onMuted(mMuted, isZenMuted());
                         }
                     }
                     updateSeekBar();
@@ -328,16 +346,18 @@
             }
         }
 
-        public void postUpdateSlider(int volume, boolean mute) {
-            obtainMessage(UPDATE_SLIDER, volume, mute ? 1 : 0).sendToTarget();
+        public void postUpdateSlider(int volume, int lastAudibleVolume, boolean mute) {
+            final int arg2 = lastAudibleVolume * (mute ? -1 : 1);
+            obtainMessage(UPDATE_SLIDER, volume, arg2).sendToTarget();
         }
     }
 
     private void updateSlider() {
         if (mSeekBar != null && mAudioManager != null) {
             final int volume = mAudioManager.getStreamVolume(mStreamType);
+            final int lastAudibleVolume = mAudioManager.getLastAudibleStreamVolume(mStreamType);
             final boolean mute = mAudioManager.isStreamMute(mStreamType);
-            mUiHandler.postUpdateSlider(volume, mute);
+            mUiHandler.postUpdateSlider(volume, lastAudibleVolume, mute);
         }
     }
 
@@ -362,6 +382,7 @@
             if (listening) {
                 final IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
                 filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
+                filter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
                 mContext.registerReceiver(this, filter);
             } else {
                 mContext.unregisterReceiver(this);
@@ -379,7 +400,7 @@
                 if (mSeekBar != null && streamMatch && streamValue != -1) {
                     final boolean muted = mAudioManager.isStreamMute(mStreamType)
                             || streamValue == 0;
-                    mUiHandler.postUpdateSlider(streamValue, muted);
+                    mUiHandler.postUpdateSlider(streamValue, mLastAudibleStreamVolume, muted);
                 }
             } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
                 if (mNotificationOrRing) {
@@ -388,6 +409,9 @@
                 if (mAffectedByRingerMode) {
                     updateSlider();
                 }
+            } else if (NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED.equals(action)) {
+                mZenMode = mNotificationManager.getZenMode();
+                updateSlider();
             }
         }
     }
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 573499a..8a66c24 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -161,7 +161,7 @@
     }
 
     @Override
-    public void onMuted(boolean muted) {
+    public void onMuted(boolean muted, boolean zenMuted) {
         // noop
     }
 
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 6c4d8fd..d51aa79 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1790,6 +1790,15 @@
         }
     }
 
+    /**
+     * Return localized string representing the given number of selected items.
+     *
+     * @hide
+     */
+    public static CharSequence formatSelectedCount(int count) {
+        return Resources.getSystem().getQuantityString(R.plurals.selected_count, count, count);
+    }
+
     private static Object sLock = new Object();
 
     private static char[] sTemp = null;
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index d2b6533..a865307 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -22,6 +22,7 @@
 import android.os.Message;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.util.Log;
 import android.util.TimeUtils;
 
@@ -160,6 +161,14 @@
     FrameInfo mFrameInfo = new FrameInfo();
 
     /**
+     * Must be kept in sync with CALLBACK_* ints below, used to index into this array.
+     * @hide
+     */
+    private static final String[] CALLBACK_TRACE_TITLES = {
+            "input", "animation", "traversal", "commit"
+    };
+
+    /**
      * Callback type: Input callback.  Runs first.
      * @hide
      */
@@ -584,16 +593,22 @@
             mLastFrameTimeNanos = frameTimeNanos;
         }
 
-        mFrameInfo.markInputHandlingStart();
-        doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
 
-        mFrameInfo.markAnimationsStart();
-        doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
+            mFrameInfo.markInputHandlingStart();
+            doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
 
-        mFrameInfo.markPerformTraversalsStart();
-        doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
+            mFrameInfo.markAnimationsStart();
+            doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
 
-        doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
+            mFrameInfo.markPerformTraversalsStart();
+            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
+
+            doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
 
         if (DEBUG_FRAMES) {
             final long endNanos = System.nanoTime();
@@ -627,6 +642,7 @@
             // safe by ensuring the commit time is always at least one frame behind.
             if (callbackType == Choreographer.CALLBACK_COMMIT) {
                 final long jitterNanos = now - frameTimeNanos;
+                Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
                 if (jitterNanos >= 2 * mFrameIntervalNanos) {
                     final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
                             + mFrameIntervalNanos;
@@ -644,6 +660,7 @@
             }
         }
         try {
+            Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
             for (CallbackRecord c = callbacks; c != null; c = c.next) {
                 if (DEBUG_FRAMES) {
                     Log.d(TAG, "RunCallback: type=" + callbackType
@@ -661,6 +678,7 @@
                     callbacks = next;
                 } while (callbacks != null);
             }
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
         }
     }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e1e0154..e2f42db 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1105,12 +1105,7 @@
                 Debug.startMethodTracing("ViewAncestor");
             }
 
-            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
-            try {
-                performTraversals();
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-            }
+            performTraversals();
 
             if (mProfile) {
                 Debug.stopMethodTracing();
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index 42668f1..585cdf1 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -45,7 +45,7 @@
 class ResolverComparator implements Comparator<ResolvedComponentInfo> {
     private static final String TAG = "ResolverComparator";
 
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     // Two weeks
     private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 08d61d5..b9e48a0 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -49,6 +49,12 @@
 };
 static fields_t fields;
 
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+    static volatile int32_t globalCounter = 0;
+    return android_atomic_inc(&globalCounter);
+}
+
 // ----------------------------------------------------------------------------
 
 static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
@@ -253,6 +259,11 @@
                 "Unable to create native SurfaceTexture");
         return;
     }
+    surfaceTexture->setName(String8::format("SurfaceTexture-%d-%d-%d",
+            (isDetached ? 0 : texName),
+            getpid(),
+            createProcessUniqueId()));
+
     SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
     SurfaceTexture_setProducer(env, thiz, producer);
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0911d42..54123f5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -90,7 +90,6 @@
     <protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
     <protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
     <protected-broadcast android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
-    <protected-broadcast android:name="android.app.action.SEND_DEVICE_INITIALIZER_STATUS" />
 
     <protected-broadcast android:name="android.appwidget.action.APPWIDGET_UPDATE_OPTIONS" />
     <protected-broadcast android:name="android.appwidget.action.APPWIDGET_DELETED" />
@@ -1603,24 +1602,6 @@
     <permission android:name="android.permission.WRITE_APN_SETTINGS"
         android:protectionLevel="signature|system" />
 
-    <!-- Allows an application to allow access the subscribed feeds ContentProvider.
-         @hide
-         @removed
-     -->
-    <permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
-        android:label="@string/permlab_subscribedFeedsRead"
-        android:description="@string/permdesc_subscribedFeedsRead"
-        android:protectionLevel="normal" />
-
-    <!--
-        @hide
-        @removed
-    -->
-    <permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE"
-        android:label="@string/permlab_subscribedFeedsWrite"
-        android:description="@string/permdesc_subscribedFeedsWrite"
-        android:protectionLevel="dangerous" />
-
     <!-- Allows applications to change network connectivity state -->
     <permission android:name="android.permission.CHANGE_NETWORK_STATE"
         android:description="@string/permdesc_changeNetworkState"
@@ -2450,11 +2431,6 @@
     <permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS"
         android:protectionLevel="signature" />
 
-    <!-- Allows receiving status updates from a device initializer.
-         @hide Not for use by third-party applications. -->
-    <permission android:name="android.permission.RECEIVE_DEVICE_INITIALIZER_STATUS"
-        android:protectionLevel="signature" />
-
     <!-- The system process that is allowed to bind to services in carrier apps will
          have this permission. Carrier apps should use this permission to protect
          their services that only the system is allowed to bind to. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 470e345..f31c1d6 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1058,18 +1058,20 @@
          lockTask mode is disabled.
          <p>While in lockTask mode with multiple permitted tasks running, each launched task is
          permitted to finish, transitioning to the previous locked task, until there is only one
-         task remaining. At that point the last task running is not permitted to finish. -->
+         task remaining. At that point the last task running is not permitted to finish, unless it
+         uses the value always. -->
     <attr name="lockTaskMode">
         <!-- This is the default value. Tasks will not launch into lockTask mode but can be
              placed there by calling {@link android.app.Activity#startLockTask}. If a task with
              this mode has been whitelisted using {@link
-             android.app.admin.DevicePolicyManager#setLockTaskPackages} then calling startLockTask
-             will enter lockTask mode immediately, otherwise the user will be presented with a
-             dialog to approve entering lockTask mode.
+             android.app.admin.DevicePolicyManager#setLockTaskPackages} then calling
+             {@link android.app.Activity#startLockTask} will enter lockTask mode immediately,
+             otherwise the user will be presented with a dialog to approve entering pinned mode.
              <p>If the system is already in lockTask mode when a new task rooted at this activity
              is launched that task will or will not start depending on whether the package of this
              activity has been whitelisted.
-             <p>Tasks rooted at this activity can only exit lockTask mode using stopLockTask(). -->
+             <p>Tasks rooted at this activity can only exit lockTask mode using
+             {@link android.app.Activity#stopLockTask}. -->
         <enum name="normal" value="0"/>
         <!-- Tasks will not launch into lockTask mode and cannot be placed there using
              {@link android.app.Activity#startLockTask} or be pinned from the Overview screen.
@@ -1082,16 +1084,17 @@
         <!-- Tasks rooted at this activity will always launch into lockTask mode. If the system is
              already in lockTask mode when this task is launched then the new task will be launched
              on top of the current task. Tasks launched in this mode are capable of exiting
-             lockTask mode using finish(), whereas tasks entering lockTask mode using
-             startLockTask() must use stopLockTask() to exit.
+             lockTask mode using {@link android.app.Activity#finish()}.
              <p>Note: This mode is only available to system and privileged applications.
              Non-privileged apps with this value will be treated as normal.
              -->
         <enum name="always" value="2"/>
         <!-- If the DevicePolicyManager (DPM) authorizes this package ({@link
              android.app.admin.DevicePolicyManager#setLockTaskPackages}) then this mode is
-             identical to always. If the DPM does not authorize this package then this
-             mode is identical to normal. -->
+             identical to always, except that the activity needs to call
+             {@link android.app.Activity#stopLockTask} before being able to finish if it is the last
+             locked task.
+             If the DPM does not authorize this package then this mode is identical to normal. -->
         <enum name="if_whitelisted" value="3"/>
     </attr>
     <!-- When set installer will extract native libraries. If set to false
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 28274ae..675d3e2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1302,12 +1302,6 @@
     <string name="permdesc_readSyncStats">Allows an app to read the sync stats for an account, including the history of sync events and how much data is synced. </string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_subscribedFeedsWrite">write subscribed feeds</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_subscribedFeedsWrite">Allows the app to modify
-        your currently synced feeds. Malicious apps may change your synced feeds.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readDictionary">read terms you added to the dictionary</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readDictionary">Allows the app to read all words,
@@ -4207,4 +4201,9 @@
          notification_template_material_inbox.xml.
          DO NOT TRANSLATE -->
     <string name="notification_inbox_ellipsis">\u2026</string>
+
+    <!-- Label describing the number of selected items [CHAR LIMIT=48] -->
+    <plurals name="selected_count">
+        <item quantity="other"><xliff:g id="count" example="3">%1$d</xliff:g> selected</item>
+    </plurals>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8900688..b019adb 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2306,5 +2306,6 @@
   <java-symbol type="string" name="ext_media_status_missing" />
   <java-symbol type="string" name="ext_media_unsupported_notification_message" />
   <java-symbol type="string" name="ext_media_unsupported_notification_title" />
+  <java-symbol type="plurals" name="selected_count" />
 
 </resources>
diff --git a/docs/html/robots.txt b/docs/html/robots.txt
index ab379bb..f522220 100644
--- a/docs/html/robots.txt
+++ b/docs/html/robots.txt
@@ -15,5 +15,4 @@
 Disallow: /guide/tutorials/
 Disallow: /guide/samples/
 Disallow: /community/
-Disallow: /preview/
 Sitemap: http://developer.android.com/sitemap.txt
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index bdc60a2..fed3f47 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -5,28 +5,28 @@
 header.hide=1
 page.metaDescription=Download the official Android IDE and developer tools to build apps for Android phones, tablets, wearables, TVs, and more.
 
-studio.version=1.2.1.1
+studio.version=1.2.2.0
 
-studio.linux_bundle_download=android-studio-ide-141.1903250-linux.zip
-studio.linux_bundle_bytes=258634089 
-studio.linux_bundle_checksum=61f576a24ac9aa00d498bb62942c028ef4a8905b
+studio.linux_bundle_download=android-studio-ide-141.1980579-linux.zip
+studio.linux_bundle_bytes=258628239
+studio.linux_bundle_checksum=1fcb226bcf71760296b07dc0db74216563ce83f7
 
-studio.mac_bundle_download=android-studio-ide-141.1903250-mac.dmg
-studio.mac_bundle_bytes=260877150
-studio.mac_bundle_checksum=a5a6ba50e3590de0973230a238d17726a1d9395c
+studio.mac_bundle_download=android-studio-ide-141.1980579-mac.dmg
+studio.mac_bundle_bytes=260363204
+studio.mac_bundle_checksum=811a868958f8799a1c86a3acfab0fc5dc8de2f41
 
-studio.win_bundle_download=android-studio-ide-141.1903250-windows.zip
-studio.win_bundle_bytes=261042465
-studio.win_bundle_checksum=ce924e0e4cff4b7f24df3f7ce0c1ce2379347d72
+studio.win_bundle_download=android-studio-ide-141.1980579-windows.zip
+studio.win_bundle_bytes=261036618
+studio.win_bundle_checksum=e61c9c27a92eff943f6bfdcdec3827199dd0c63d
 
 
-studio.win_bundle_exe_download=android-studio-bundle-141.1903250-windows.exe
-studio.win_bundle_exe_bytes=930462136
-studio.win_bundle_exe_checksum=680668b6b4a51c519efda814b96c2b61541a50f2
+studio.win_bundle_exe_download=android-studio-bundle-141.1980579-windows.exe
+studio.win_bundle_exe_bytes=930456592
+studio.win_bundle_exe_checksum=964959e5165e90aaf693e868d5d1c2f7b38e8754
 
-studio.win_notools_exe_download=android-studio-ide-141.1903250-windows.exe
-studio.win_notools_exe_bytes=243747312
-studio.win_notools_exe_checksum=d89917dd044e0559c87d6a05d49780ab110269f7
+studio.win_notools_exe_download=android-studio-ide-141.1980579-windows.exe
+studio.win_notools_exe_bytes=243741776
+studio.win_notools_exe_checksum=ae09797db2537afb572a00b7eacc292bb66d539e
 
 
 
diff --git a/docs/html/tools/revisions/studio.jd b/docs/html/tools/revisions/studio.jd
index 7138efe..b727d96 100644
--- a/docs/html/tools/revisions/studio.jd
+++ b/docs/html/tools/revisions/studio.jd
@@ -43,10 +43,24 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Android Studio v1.2.2</a> <em>(June 2015)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <p>Fixes and enhancements:</p>
+    <ul>
+      <li>Fixed build issues that were blocking builds from completing. </li>
+    </ul>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Android Studio v1.2.1</a> <em>(May 2015)</em>
   </p>
   <div class="toggle-content-toggleme">
-    <p>Various fixes and enhancements:</p>
+    <p>Fixes and enhancements:</p>
     <ul>
       <li>Fixed minor performance and feature issues. </li>
     </ul>
@@ -62,7 +76,7 @@
   </p>
 
   <div class="toggle-content-toggleme">
-    <p>Various fixes and enhancements:</p>
+    <p>Fixes and enhancements:</p>
     <ul>
       <li>Updated the Android runtime window to include the
         <a href="{@docRoot}tools/studio/index.html#mem-cpu">Memory Monitor</a> tool
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 059d8e6..f482bf0 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -29,15 +29,14 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.security.keystore.KeyInfo;
+import android.security.keystore.AndroidKeyStoreProvider;
 import android.security.keystore.KeyProperties;
 
 import java.io.ByteArrayInputStream;
 import java.io.Closeable;
-import java.security.InvalidKeyException;
-import java.security.KeyFactory;
 import java.security.Principal;
 import java.security.PrivateKey;
+import java.security.UnrecoverableKeyException;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
@@ -47,7 +46,6 @@
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 
-import com.android.org.conscrypt.OpenSSLEngine;
 import com.android.org.conscrypt.TrustedCertificateStore;
 
 /**
@@ -90,8 +88,6 @@
 // TODO reference intent for credential installation when public
 public final class KeyChain {
 
-    private static final String TAG = "KeyChain";
-
     /**
      * @hide Also used by KeyChainService implementation
      */
@@ -372,15 +368,14 @@
             if (keyId == null) {
                 throw new KeyChainException("keystore had a problem");
             }
-
-            final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
-            return engine.getPrivateKeyById(keyId);
+            return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
+                    KeyStore.getInstance(), keyId);
         } catch (RemoteException e) {
             throw new KeyChainException(e);
         } catch (RuntimeException e) {
             // only certain RuntimeExceptions can be propagated across the IKeyChainService call
             throw new KeyChainException(e);
-        } catch (InvalidKeyException e) {
+        } catch (UnrecoverableKeyException e) {
             throw new KeyChainException(e);
         } finally {
             keyChainConnection.close();
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index efbce41..d849317 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -331,7 +331,9 @@
             if (keyType == null) {
                 throw new NullPointerException("keyType == null");
             } else {
-                if (KeyStore.getKeyTypeForAlgorithm(keyType) == -1) {
+                try {
+                    KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(keyType);
+                } catch (IllegalArgumentException e) {
                     throw new NoSuchAlgorithmException("Unsupported key type: " + keyType);
                 }
             }
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 893771a..35fcda6 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -19,7 +19,6 @@
 import android.app.ActivityThread;
 import android.app.Application;
 import android.app.KeyguardManager;
-import com.android.org.conscrypt.NativeConstants;
 
 import android.content.Context;
 import android.hardware.fingerprint.FingerprintManager;
@@ -38,7 +37,6 @@
 import android.security.keystore.KeyExpiredException;
 import android.security.keystore.KeyNotYetValidException;
 import android.security.keystore.KeyPermanentlyInvalidatedException;
-import android.security.keystore.KeyProperties;
 import android.security.keystore.UserNotAuthenticatedException;
 import android.util.Log;
 
@@ -136,16 +134,6 @@
         return mToken;
     }
 
-    public static int getKeyTypeForAlgorithm(@KeyProperties.KeyAlgorithmEnum String keyType) {
-        if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyType)) {
-            return NativeConstants.EVP_PKEY_RSA;
-        } else if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyType)) {
-            return NativeConstants.EVP_PKEY_EC;
-        } else {
-            return -1;
-        }
-    }
-
     public State state(int userId) {
         final int ret;
         try {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
new file mode 100644
index 0000000..5dbcd68
--- /dev/null
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import java.security.PrivateKey;
+import java.security.interfaces.ECKey;
+import java.security.spec.ECParameterSpec;
+
+/**
+ * EC private key (instance of {@link PrivateKey} and {@link ECKey}) backed by keystore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreECPrivateKey extends AndroidKeyStorePrivateKey implements ECKey {
+    private final ECParameterSpec mParams;
+
+    public AndroidKeyStoreECPrivateKey(String alias, ECParameterSpec params) {
+        super(alias, KeyProperties.KEY_ALGORITHM_EC);
+        mParams = params;
+    }
+
+    @Override
+    public ECParameterSpec getParams() {
+        return mParams;
+    }
+}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
index 1751aa5..e76802f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
@@ -52,4 +52,42 @@
         // This key does not export its key material
         return null;
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((mAlgorithm == null) ? 0 : mAlgorithm.hashCode());
+        result = prime * result + ((mAlias == null) ? 0 : mAlias.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        AndroidKeyStoreKey other = (AndroidKeyStoreKey) obj;
+        if (mAlgorithm == null) {
+            if (other.mAlgorithm != null) {
+                return false;
+            }
+        } else if (!mAlgorithm.equals(other.mAlgorithm)) {
+            return false;
+        }
+        if (mAlias == null) {
+            if (other.mAlias != null) {
+                return false;
+            }
+        } else if (!mAlias.equals(other.mAlias)) {
+            return false;
+        }
+        return true;
+    }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 69155a8..35af34f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -20,7 +20,6 @@
 import android.security.Credentials;
 import android.security.KeyPairGeneratorSpec;
 import android.security.KeyStore;
-import android.security.keymaster.ExportResult;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
@@ -44,29 +43,24 @@
 import com.android.org.bouncycastle.jce.X509Principal;
 import com.android.org.bouncycastle.jce.provider.X509CertificateObject;
 import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
-import com.android.org.conscrypt.OpenSSLEngine;
 
 import libcore.util.EmptyArray;
 
 import java.math.BigInteger;
 import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.KeyPairGeneratorSpi;
-import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.ProviderException;
 import java.security.PublicKey;
 import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
 import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.ECGenParameterSpec;
-import java.security.spec.InvalidKeySpecException;
 import java.security.spec.RSAKeyGenParameterSpec;
-import java.security.spec.X509EncodedKeySpec;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
@@ -147,6 +141,7 @@
         SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet());
         Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES);
     }
+
     private final int mOriginalKeymasterAlgorithm;
 
     private KeyStore mKeyStore;
@@ -431,24 +426,6 @@
         args.addInts(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
         args.addInts(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
 
-        // TODO: Remove the digest and padding NONE workaround below once Android Keystore returns
-        // keys which are backed by AndroidKeyStoreBCWorkaround provider instead of Conscrypt. The
-        // workaround is needed because Conscrypt (via keystore-engine) uses old KeyStore API which
-        // translates into digest NONE and padding NONE in the new API. keystore-engine cannot be
-        // updated to pass in the correct padding and digest values because it uses
-        // OpenSSL/BoringSSL engine which performs digesting and padding prior before invoking
-        // KeyStore API.
-        if (!com.android.internal.util.ArrayUtils.contains(
-                mKeymasterDigests, KeymasterDefs.KM_DIGEST_NONE)) {
-            args.addInt(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
-        }
-        if ((!com.android.internal.util.ArrayUtils.contains(
-                mKeymasterSignaturePaddings, KeymasterDefs.KM_PAD_NONE))
-                && (!com.android.internal.util.ArrayUtils.contains(
-                        mKeymasterEncryptionPaddings, KeymasterDefs.KM_PAD_NONE))) {
-            args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
-        }
-
         KeymasterUtils.addUserAuthArgs(args,
                 mSpec.isUserAuthenticationRequired(),
                 mSpec.getUserAuthenticationValidityDurationSeconds());
@@ -483,40 +460,23 @@
                         "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
             }
 
-            final PrivateKey privKey;
-            final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
+            KeyPair result;
             try {
-                privKey = engine.getPrivateKeyById(privateKeyAlias);
-            } catch (InvalidKeyException e) {
-                throw new ProviderException("Failed to obtain generated private key", e);
+                result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
+                        mKeyStore, privateKeyAlias);
+            } catch (UnrecoverableKeyException e) {
+                throw new ProviderException("Failed to load generated key pair from keystore", e);
             }
 
-            ExportResult exportResult =
-                    mKeyStore.exportKey(
-                            privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
-            if (exportResult == null) {
-                throw new KeyStoreConnectException();
-            } else if (exportResult.resultCode != KeyStore.NO_ERROR) {
+            if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
                 throw new ProviderException(
-                        "Failed to obtain X.509 form of generated public key",
-                        KeyStore.getKeyStoreException(exportResult.resultCode));
-            }
-            final byte[] pubKeyBytes = exportResult.exportData;
-
-            final PublicKey pubKey;
-            try {
-                final KeyFactory keyFact = KeyFactory.getInstance(mJcaKeyAlgorithm);
-                pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
-            } catch (NoSuchAlgorithmException e) {
-                throw new ProviderException(
-                        "Failed to obtain " + mJcaKeyAlgorithm + " KeyFactory", e);
-            } catch (InvalidKeySpecException e) {
-                throw new ProviderException("Invalid X.509 encoding of generated public key", e);
+                        "Generated key pair algorithm does not match requested algorithm: "
+                        + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
             }
 
             final X509Certificate cert;
             try {
-                cert = generateSelfSignedCertificate(privKey, pubKey);
+                cert = generateSelfSignedCertificate(result.getPrivate(), result.getPublic());
             } catch (Exception e) {
                 throw new ProviderException("Failed to generate self-signed certificate", e);
             }
@@ -539,7 +499,6 @@
                         KeyStore.getKeyStoreException(insertErrorCode));
             }
 
-            KeyPair result = new KeyPair(pubKey, privKey);
             success = true;
             return result;
         } finally {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index cb270bb..967319a 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -16,11 +16,28 @@
 
 package android.security.keystore;
 
+import android.annotation.NonNull;
 import android.security.KeyStore;
+import android.security.keymaster.ExportResult;
+import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterDefs;
 
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
 import java.security.Provider;
+import java.security.ProviderException;
+import java.security.PublicKey;
 import java.security.Security;
 import java.security.Signature;
+import java.security.UnrecoverableKeyException;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.List;
 
 import javax.crypto.Cipher;
 import javax.crypto.Mac;
@@ -146,4 +163,145 @@
         }
         return ((KeyStoreCryptoOperation) spi).getOperationHandle();
     }
+
+    @NonNull
+    public static AndroidKeyStorePublicKey getAndroidKeyStorePublicKey(
+            @NonNull String alias,
+            @NonNull @KeyProperties.KeyAlgorithmEnum String keyAlgorithm,
+            @NonNull byte[] x509EncodedForm) {
+        PublicKey publicKey;
+        try {
+            KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
+            publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(x509EncodedForm));
+        } catch (NoSuchAlgorithmException e) {
+            throw new ProviderException(
+                    "Failed to obtain " + keyAlgorithm + " KeyFactory", e);
+        } catch (InvalidKeySpecException e) {
+            throw new ProviderException("Invalid X.509 encoding of public key", e);
+        }
+        if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
+            return new AndroidKeyStoreECPublicKey(alias, (ECPublicKey) publicKey);
+        } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
+            return new AndroidKeyStoreRSAPublicKey(alias, (RSAPublicKey) publicKey);
+        } else {
+            throw new ProviderException("Unsupported Android Keystore public key algorithm: "
+                    + keyAlgorithm);
+        }
+    }
+
+    @NonNull
+    public static AndroidKeyStorePrivateKey getAndroidKeyStorePrivateKey(
+            @NonNull AndroidKeyStorePublicKey publicKey) {
+        String keyAlgorithm = publicKey.getAlgorithm();
+        if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
+            return new AndroidKeyStoreECPrivateKey(
+                    publicKey.getAlias(), ((ECKey) publicKey).getParams());
+        } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
+            return new AndroidKeyStoreRSAPrivateKey(
+                    publicKey.getAlias(), ((RSAKey) publicKey).getModulus());
+        } else {
+            throw new ProviderException("Unsupported Android Keystore public key algorithm: "
+                    + keyAlgorithm);
+        }
+    }
+
+    @NonNull
+    public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
+            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+            throws UnrecoverableKeyException {
+        KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
+        int errorCode = keyStore.getKeyCharacteristics(
+                privateKeyAlias, null, null, keyCharacteristics);
+        if (errorCode != KeyStore.NO_ERROR) {
+            throw (UnrecoverableKeyException)
+                    new UnrecoverableKeyException("Failed to obtain information about private key")
+                    .initCause(KeyStore.getKeyStoreException(errorCode));
+        }
+        ExportResult exportResult = keyStore.exportKey(
+                privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
+        if (exportResult.resultCode != KeyStore.NO_ERROR) {
+            throw (UnrecoverableKeyException)
+                    new UnrecoverableKeyException("Failed to obtain X.509 form of public key")
+                    .initCause(KeyStore.getKeyStoreException(errorCode));
+        }
+        final byte[] x509EncodedPublicKey = exportResult.exportData;
+
+        int keymasterAlgorithm = keyCharacteristics.getInt(KeymasterDefs.KM_TAG_ALGORITHM, -1);
+        if (keymasterAlgorithm == -1) {
+            throw new UnrecoverableKeyException("Key algorithm unknown");
+        }
+
+        String jcaKeyAlgorithm;
+        try {
+            jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
+                    keymasterAlgorithm);
+        } catch (IllegalArgumentException e) {
+            throw (UnrecoverableKeyException)
+                    new UnrecoverableKeyException("Failed to load private key")
+                    .initCause(e);
+        }
+
+        return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
+                privateKeyAlias, jcaKeyAlgorithm, x509EncodedPublicKey);
+    }
+
+    @NonNull
+    public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
+            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+            throws UnrecoverableKeyException {
+        AndroidKeyStorePublicKey publicKey =
+                loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias);
+        AndroidKeyStorePrivateKey privateKey =
+                AndroidKeyStoreProvider.getAndroidKeyStorePrivateKey(publicKey);
+        return new KeyPair(publicKey, privateKey);
+    }
+
+    @NonNull
+    public static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
+            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+            throws UnrecoverableKeyException {
+        KeyPair keyPair = loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias);
+        return (AndroidKeyStorePrivateKey) keyPair.getPrivate();
+    }
+
+    @NonNull
+    public static AndroidKeyStoreSecretKey loadAndroidKeyStoreSecretKeyFromKeystore(
+            @NonNull KeyStore keyStore, @NonNull String secretKeyAlias)
+            throws UnrecoverableKeyException {
+        KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
+        int errorCode = keyStore.getKeyCharacteristics(
+                secretKeyAlias, null, null, keyCharacteristics);
+        if (errorCode != KeyStore.NO_ERROR) {
+            throw (UnrecoverableKeyException)
+                    new UnrecoverableKeyException("Failed to obtain information about key")
+                            .initCause(KeyStore.getKeyStoreException(errorCode));
+        }
+
+        int keymasterAlgorithm = keyCharacteristics.getInt(KeymasterDefs.KM_TAG_ALGORITHM, -1);
+        if (keymasterAlgorithm == -1) {
+            throw new UnrecoverableKeyException("Key algorithm unknown");
+        }
+
+        List<Integer> keymasterDigests =
+                keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST);
+        int keymasterDigest;
+        if (keymasterDigests.isEmpty()) {
+            keymasterDigest = -1;
+        } else {
+            // More than one digest can be permitted for this key. Use the first one to form the
+            // JCA key algorithm name.
+            keymasterDigest = keymasterDigests.get(0);
+        }
+
+        @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
+        try {
+            keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
+                    keymasterAlgorithm, keymasterDigest);
+        } catch (IllegalArgumentException e) {
+            throw (UnrecoverableKeyException)
+                    new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
+        }
+
+        return new AndroidKeyStoreSecretKey(secretKeyAlias, keyAlgorithmString);
+    }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
index 8133d46..9fea30d 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
@@ -17,6 +17,7 @@
 package android.security.keystore;
 
 import java.security.PublicKey;
+import java.util.Arrays;
 
 /**
  * {@link PublicKey} backed by Android Keystore.
@@ -41,4 +42,30 @@
     public byte[] getEncoded() {
         return ArrayUtils.cloneIfNotEmpty(mEncoded);
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + Arrays.hashCode(mEncoded);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        AndroidKeyStorePublicKey other = (AndroidKeyStorePublicKey) obj;
+        if (!Arrays.equals(mEncoded, other.mEncoded)) {
+            return false;
+        }
+        return true;
+    }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
new file mode 100644
index 0000000..179ffd8
--- /dev/null
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.interfaces.RSAKey;
+
+/**
+ * RSA private key (instance of {@link PrivateKey} and {@link RSAKey}) backed by keystore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreRSAPrivateKey extends AndroidKeyStorePrivateKey implements RSAKey {
+
+    private final BigInteger mModulus;
+
+    public AndroidKeyStoreRSAPrivateKey(String alias, BigInteger modulus) {
+        super(alias, KeyProperties.KEY_ALGORITHM_RSA);
+        mModulus = modulus;
+    }
+
+    @Override
+    public BigInteger getModulus() {
+        return mModulus;
+    }
+}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
index 4c4062f..f072ae7 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
@@ -25,7 +25,7 @@
 import android.security.keymaster.KeymasterDefs;
 import android.security.keymaster.OperationResult;
 
-import com.android.org.conscrypt.util.EmptyArray;
+import libcore.util.EmptyArray;
 
 import java.nio.ByteBuffer;
 import java.security.InvalidKeyException;
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index c03be63..831a106 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -16,9 +16,6 @@
 
 package android.security.keystore;
 
-import com.android.org.conscrypt.OpenSSLEngine;
-import com.android.org.conscrypt.OpenSSLKeyHolder;
-
 import libcore.util.EmptyArray;
 
 import android.security.Credentials;
@@ -35,7 +32,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.security.InvalidKeyException;
 import java.security.Key;
 import java.security.KeyStore.Entry;
 import java.security.KeyStore.PrivateKeyEntry;
@@ -45,6 +41,7 @@
 import java.security.KeyStoreSpi;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateEncodingException;
@@ -59,7 +56,6 @@
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Set;
 
 import javax.crypto.SecretKey;
@@ -92,59 +88,17 @@
     public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException,
             UnrecoverableKeyException {
         if (isPrivateKeyEntry(alias)) {
-            final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
-            try {
-                return engine.getPrivateKeyById(Credentials.USER_PRIVATE_KEY + alias);
-            } catch (InvalidKeyException e) {
-                UnrecoverableKeyException t = new UnrecoverableKeyException("Can't get key");
-                t.initCause(e);
-                throw t;
-            }
+            String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
+            return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
+                    mKeyStore, privateKeyAlias);
         } else if (isSecretKeyEntry(alias)) {
-            KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
-            String keyAliasInKeystore = Credentials.USER_SECRET_KEY + alias;
-            int errorCode = mKeyStore.getKeyCharacteristics(
-                    keyAliasInKeystore, null, null, keyCharacteristics);
-            if (errorCode != KeyStore.NO_ERROR) {
-                throw (UnrecoverableKeyException)
-                        new UnrecoverableKeyException("Failed to load information about key")
-                                .initCause(mKeyStore.getInvalidKeyException(alias, errorCode));
-            }
-
-            int keymasterAlgorithm =
-                    keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_ALGORITHM, -1);
-            if (keymasterAlgorithm == -1) {
-                keymasterAlgorithm =
-                        keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_ALGORITHM, -1);
-            }
-            if (keymasterAlgorithm == -1) {
-                throw new UnrecoverableKeyException("Key algorithm unknown");
-            }
-
-            List<Integer> keymasterDigests =
-                    keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST);
-            int keymasterDigest;
-            if (keymasterDigests.isEmpty()) {
-                keymasterDigest = -1;
-            } else {
-                // More than one digest can be permitted for this key. Use the first one to form the
-                // JCA key algorithm name.
-                keymasterDigest = keymasterDigests.get(0);
-            }
-
-            @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
-            try {
-                keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
-                        keymasterAlgorithm, keymasterDigest);
-            } catch (IllegalArgumentException e) {
-                throw (UnrecoverableKeyException)
-                        new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
-            }
-
-            return new AndroidKeyStoreSecretKey(keyAliasInKeystore, keyAlgorithmString);
+            String secretKeyAlias = Credentials.USER_SECRET_KEY + alias;
+            return AndroidKeyStoreProvider.loadAndroidKeyStoreSecretKeyFromKeystore(
+                    mKeyStore, secretKeyAlias);
+        } else {
+            // Key not found
+            return null;
         }
-
-        return null;
     }
 
     @Override
@@ -188,22 +142,36 @@
 
         byte[] certificate = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
         if (certificate != null) {
-            return toCertificate(certificate);
+            return wrapIntoKeyStoreCertificate(
+                    Credentials.USER_PRIVATE_KEY + alias, toCertificate(certificate));
         }
 
         certificate = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
         if (certificate != null) {
-            return toCertificate(certificate);
+            return wrapIntoKeyStoreCertificate(
+                    Credentials.USER_PRIVATE_KEY + alias, toCertificate(certificate));
         }
 
         return null;
     }
 
+    /**
+     * Wraps the provided cerificate into {@link KeyStoreX509Certificate} so that the public key
+     * returned by the certificate contains information about the alias of the private key in
+     * keystore. This is needed so that Android Keystore crypto operations using public keys can
+     * find out which key alias to use. These operations cannot work without an alias.
+     */
+    private static KeyStoreX509Certificate wrapIntoKeyStoreCertificate(
+            String privateKeyAlias, X509Certificate certificate) {
+        return (certificate != null)
+                ? new KeyStoreX509Certificate(privateKeyAlias, certificate) : null;
+    }
+
     private static X509Certificate toCertificate(byte[] bytes) {
         try {
             final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
-            return (X509Certificate) certFactory
-                    .generateCertificate(new ByteArrayInputStream(bytes));
+            return (X509Certificate) certFactory.generateCertificate(
+                    new ByteArrayInputStream(bytes));
         } catch (CertificateException e) {
             Log.w(NAME, "Couldn't parse certificate in keystore", e);
             return null;
@@ -214,8 +182,8 @@
     private static Collection<X509Certificate> toCertificates(byte[] bytes) {
         try {
             final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
-            return (Collection<X509Certificate>) certFactory
-                    .generateCertificates(new ByteArrayInputStream(bytes));
+            return (Collection<X509Certificate>) certFactory.generateCertificates(
+                            new ByteArrayInputStream(bytes));
         } catch (CertificateException e) {
             Log.w(NAME, "Couldn't parse certificates in keystore", e);
             return new ArrayList<X509Certificate>();
@@ -406,9 +374,7 @@
         }
 
         final String pkeyAlias;
-        if (key instanceof OpenSSLKeyHolder) {
-            pkeyAlias = ((OpenSSLKeyHolder) key).getOpenSSLKey().getAlias();
-        } else if (key instanceof AndroidKeyStorePrivateKey) {
+        if (key instanceof AndroidKeyStorePrivateKey) {
             pkeyAlias = ((AndroidKeyStoreKey) key).getAlias();
         } else {
             pkeyAlias = null;
@@ -851,6 +817,19 @@
         if (cert == null) {
             return null;
         }
+        if (!"X.509".equalsIgnoreCase(cert.getType())) {
+            // Only X.509 certificates supported
+            return null;
+        }
+        byte[] targetCertBytes;
+        try {
+            targetCertBytes = cert.getEncoded();
+        } catch (CertificateEncodingException e) {
+            return null;
+        }
+        if (targetCertBytes == null) {
+            return null;
+        }
 
         final Set<String> nonCaEntries = new HashSet<String>();
 
@@ -868,10 +847,9 @@
                     continue;
                 }
 
-                final Certificate c = toCertificate(certBytes);
                 nonCaEntries.add(alias);
 
-                if (cert.equals(c)) {
+                if (Arrays.equals(certBytes, targetCertBytes)) {
                     return alias;
                 }
             }
@@ -893,9 +871,7 @@
                     continue;
                 }
 
-                final Certificate c =
-                        toCertificate(mKeyStore.get(Credentials.CA_CERTIFICATE + alias));
-                if (cert.equals(c)) {
+                if (Arrays.equals(certBytes, targetCertBytes)) {
                     return alias;
                 }
             }
@@ -954,4 +930,25 @@
         }
     }
 
+    /**
+     * {@link X509Certificate} which returns {@link AndroidKeyStorePublicKey} from
+     * {@link #getPublicKey()}. This is so that crypto operations on these public keys contain
+     * can find out which keystore private key entry to use. This is needed so that Android Keystore
+     * crypto operations using public keys can find out which key alias to use. These operations
+     * require an alias.
+     */
+    static class KeyStoreX509Certificate extends DelegatingX509Certificate {
+        private final String mPrivateKeyAlias;
+        KeyStoreX509Certificate(String privateKeyAlias, X509Certificate delegate) {
+            super(delegate);
+            mPrivateKeyAlias = privateKeyAlias;
+        }
+
+        @Override
+        public PublicKey getPublicKey() {
+            PublicKey original = super.getPublicKey();
+            return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
+                    mPrivateKeyAlias, original.getAlgorithm(), original.getEncoded());
+        }
+    }
 }
diff --git a/keystore/java/android/security/keystore/DelegatingX509Certificate.java b/keystore/java/android/security/keystore/DelegatingX509Certificate.java
new file mode 100644
index 0000000..03d202f
--- /dev/null
+++ b/keystore/java/android/security/keystore/DelegatingX509Certificate.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+class DelegatingX509Certificate extends X509Certificate {
+    private final X509Certificate mDelegate;
+
+    DelegatingX509Certificate(X509Certificate delegate) {
+        mDelegate = delegate;
+    }
+
+    @Override
+    public Set<String> getCriticalExtensionOIDs() {
+        return mDelegate.getCriticalExtensionOIDs();
+    }
+
+    @Override
+    public byte[] getExtensionValue(String oid) {
+        return mDelegate.getExtensionValue(oid);
+    }
+
+    @Override
+    public Set<String> getNonCriticalExtensionOIDs() {
+        return mDelegate.getNonCriticalExtensionOIDs();
+    }
+
+    @Override
+    public boolean hasUnsupportedCriticalExtension() {
+        return mDelegate.hasUnsupportedCriticalExtension();
+    }
+
+    @Override
+    public void checkValidity() throws CertificateExpiredException,
+            CertificateNotYetValidException {
+        mDelegate.checkValidity();
+    }
+
+    @Override
+    public void checkValidity(Date date) throws CertificateExpiredException,
+            CertificateNotYetValidException {
+        mDelegate.checkValidity(date);
+    }
+
+    @Override
+    public int getBasicConstraints() {
+        return mDelegate.getBasicConstraints();
+    }
+
+    @Override
+    public Principal getIssuerDN() {
+        return mDelegate.getIssuerDN();
+    }
+
+    @Override
+    public boolean[] getIssuerUniqueID() {
+        return mDelegate.getIssuerUniqueID();
+    }
+
+    @Override
+    public boolean[] getKeyUsage() {
+        return mDelegate.getKeyUsage();
+    }
+
+    @Override
+    public Date getNotAfter() {
+        return mDelegate.getNotAfter();
+    }
+
+    @Override
+    public Date getNotBefore() {
+        return mDelegate.getNotBefore();
+    }
+
+    @Override
+    public BigInteger getSerialNumber() {
+        return mDelegate.getSerialNumber();
+    }
+
+    @Override
+    public String getSigAlgName() {
+        return mDelegate.getSigAlgName();
+    }
+
+    @Override
+    public String getSigAlgOID() {
+        return mDelegate.getSigAlgOID();
+    }
+
+    @Override
+    public byte[] getSigAlgParams() {
+        return mDelegate.getSigAlgParams();
+    }
+
+    @Override
+    public byte[] getSignature() {
+        return mDelegate.getSignature();
+    }
+
+    @Override
+    public Principal getSubjectDN() {
+        return mDelegate.getSubjectDN();
+    }
+
+    @Override
+    public boolean[] getSubjectUniqueID() {
+        return mDelegate.getSubjectUniqueID();
+    }
+
+    @Override
+    public byte[] getTBSCertificate() throws CertificateEncodingException {
+        return mDelegate.getTBSCertificate();
+    }
+
+    @Override
+    public int getVersion() {
+        return mDelegate.getVersion();
+    }
+
+    @Override
+    public byte[] getEncoded() throws CertificateEncodingException {
+        return mDelegate.getEncoded();
+    }
+
+    @Override
+    public PublicKey getPublicKey() {
+        return mDelegate.getPublicKey();
+    }
+
+    @Override
+    public String toString() {
+        return mDelegate.toString();
+    }
+
+    @Override
+    public void verify(PublicKey key)
+            throws CertificateException,
+            NoSuchAlgorithmException,
+            InvalidKeyException,
+            NoSuchProviderException,
+            SignatureException {
+        mDelegate.verify(key);
+    }
+
+    @Override
+    public void verify(PublicKey key, String sigProvider)
+            throws CertificateException,
+            NoSuchAlgorithmException,
+            InvalidKeyException,
+            NoSuchProviderException,
+            SignatureException {
+        mDelegate.verify(key, sigProvider);
+    }
+
+    @Override
+    public List<String> getExtendedKeyUsage() throws CertificateParsingException {
+        return mDelegate.getExtendedKeyUsage();
+    }
+
+    @Override
+    public Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException {
+        return mDelegate.getIssuerAlternativeNames();
+    }
+
+    @Override
+    public X500Principal getIssuerX500Principal() {
+        return mDelegate.getIssuerX500Principal();
+    }
+
+    @Override
+    public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
+        return mDelegate.getSubjectAlternativeNames();
+    }
+
+    @Override
+    public X500Principal getSubjectX500Principal() {
+        return mDelegate.getSubjectX500Principal();
+    }
+}
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index 44fb826..0b60c62 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -20,7 +20,6 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Process;
-import android.os.ServiceManager;
 import android.security.keymaster.ExportResult;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
@@ -34,13 +33,9 @@
 import com.android.org.conscrypt.NativeConstants;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
-import java.util.Date;
 import java.util.HashSet;
 import java.security.spec.RSAKeyGenParameterSpec;
 
-import android.util.Log;
-import android.util.Base64;
-
 /**
  * Junit / Instrumentation test case for KeyStore class
  *
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
index 8488acd..e5c15c5 100644
--- a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
+++ b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
@@ -26,17 +26,21 @@
 import java.io.ByteArrayInputStream;
 import java.math.BigInteger;
 import java.security.KeyPair;
+import java.security.KeyPairGenerator;
 import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.SecureRandom;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
+import java.security.interfaces.ECKey;
 import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAKey;
 import java.security.interfaces.RSAPublicKey;
 import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.RSAKeyGenParameterSpec;
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
 import java.util.Date;
 
 import javax.security.auth.x500.X500Principal;
@@ -158,6 +162,26 @@
     }
 
     public void testKeyPairGenerator_GenerateKeyPair_EC_Unencrypted_Success() throws Exception {
+        KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "AndroidKeyStore");
+        generator.initialize(new KeyGenParameterSpec.Builder(
+                TEST_ALIAS_1,
+                KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
+                .setCertificateSubject(TEST_DN_1)
+                .setCertificateSerialNumber(TEST_SERIAL_1)
+                .setCertificateNotBefore(NOW)
+                .setCertificateNotAfter(NOW_PLUS_10_YEARS)
+                .setDigests(KeyProperties.DIGEST_SHA256)
+                .build());
+
+        final KeyPair pair = generator.generateKeyPair();
+        assertNotNull("The KeyPair returned should not be null", pair);
+
+        assertKeyPairCorrect(pair, TEST_ALIAS_1, "EC", 256, null, TEST_DN_1, TEST_SERIAL_1, NOW,
+                NOW_PLUS_10_YEARS);
+    }
+
+    public void testKeyPairGenerator_Legacy_GenerateKeyPair_EC_Unencrypted_Success()
+            throws Exception {
         mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
                 .setAlias(TEST_ALIAS_1)
                 .setKeyType("EC")
@@ -328,19 +352,40 @@
         assertNotNull("The PrivateKey for the KeyPair should be not null", privKey);
         assertEquals(keyType, privKey.getAlgorithm());
 
+        if ("EC".equalsIgnoreCase(keyType)) {
+            assertTrue("EC private key must be instanceof ECKey: " + privKey.getClass().getName(),
+                    privKey instanceof ECKey);
+            assertEquals("Private and public key must have the same EC parameters",
+                    ((ECKey) pubKey).getParams(), ((ECKey) privKey).getParams());
+        } else if ("RSA".equalsIgnoreCase(keyType)) {
+            assertTrue("RSA private key must be instance of RSAKey: "
+                    + privKey.getClass().getName(),
+                    privKey instanceof RSAKey);
+            assertEquals("Private and public key must have the same RSA modulus",
+                    ((RSAKey) pubKey).getModulus(), ((RSAKey) privKey).getModulus());
+        }
+
         final byte[] userCertBytes = mAndroidKeyStore.get(Credentials.USER_CERTIFICATE + alias);
         assertNotNull("The user certificate should exist for the generated entry", userCertBytes);
 
         final CertificateFactory cf = CertificateFactory.getInstance("X.509");
-        final Certificate userCert = cf
-                .generateCertificate(new ByteArrayInputStream(userCertBytes));
+        final Certificate userCert =
+                cf.generateCertificate(new ByteArrayInputStream(userCertBytes));
 
         assertTrue("Certificate should be in X.509 format", userCert instanceof X509Certificate);
 
         final X509Certificate x509userCert = (X509Certificate) userCert;
 
+        assertEquals(
+                "Public key used to sign certificate should have the same algorithm as in KeyPair",
+                pubKey.getAlgorithm(), x509userCert.getPublicKey().getAlgorithm());
+
         assertEquals("PublicKey used to sign certificate should match one returned in KeyPair",
-                pubKey, x509userCert.getPublicKey());
+                pubKey,
+                AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
+                        Credentials.USER_PRIVATE_KEY + alias,
+                        x509userCert.getPublicKey().getAlgorithm(),
+                        x509userCert.getPublicKey().getEncoded()));
 
         assertEquals("The Subject DN should be the one passed into the params", dn,
                 x509userCert.getSubjectDN());
@@ -357,7 +402,10 @@
         assertDateEquals("The notAfter date should be the one passed into the params", end,
                 x509userCert.getNotAfter());
 
+        // Assert that the cert's signature verifies using the public key from generated KeyPair
         x509userCert.verify(pubKey);
+        // Assert that the cert's signature verifies using the public key from the cert itself.
+        x509userCert.verify(x509userCert.getPublicKey());
 
         final byte[] caCerts = mAndroidKeyStore.get(Credentials.CA_CERTIFICATE + alias);
         assertNull("A list of CA certificates should not exist for the generated entry", caCerts);
@@ -368,6 +416,8 @@
         final byte[] pubKeyBytes = exportResult.exportData;
         assertNotNull("The keystore should return the public key for the generated key",
                 pubKeyBytes);
+        assertTrue("Public key X.509 format should be as expected",
+                Arrays.equals(pubKey.getEncoded(), pubKeyBytes));
     }
 
     private static void assertDateEquals(String message, Date date1, Date date2) throws Exception {
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
index 336fa40..c3b731b 100644
--- a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
+++ b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
@@ -19,38 +19,31 @@
 import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
 
 import com.android.org.conscrypt.NativeConstants;
-import com.android.org.conscrypt.OpenSSLEngine;
 
 import android.security.Credentials;
 import android.security.KeyStore;
 import android.security.KeyStoreParameter;
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeymasterDefs;
 import android.test.AndroidTestCase;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.OutputStream;
 import java.math.BigInteger;
-import java.security.InvalidKeyException;
 import java.security.Key;
 import java.security.KeyFactory;
+import java.security.KeyPair;
 import java.security.KeyStore.Entry;
 import java.security.KeyStore.PrivateKeyEntry;
 import java.security.KeyStore.TrustedCertificateEntry;
 import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
-import java.security.interfaces.ECPrivateKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.spec.InvalidKeySpecException;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.RSAKey;
 import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.X509EncodedKeySpec;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
@@ -1203,14 +1196,14 @@
 
     private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, PrivateKey expectedKey,
             Certificate expectedCert, Collection<Certificate> expectedChain) throws Exception {
-        if (expectedKey instanceof ECPrivateKey) {
+        if (expectedKey instanceof ECKey) {
             assertEquals("Returned PrivateKey should be what we inserted",
-                    ((ECPrivateKey) expectedKey).getParams().getCurve(),
-                    ((ECPublicKey) keyEntry.getCertificate().getPublicKey()).getParams().getCurve());
-        } else if (expectedKey instanceof RSAPrivateKey) {
+                    ((ECKey) expectedKey).getParams().getCurve(),
+                    ((ECKey) keyEntry.getCertificate().getPublicKey()).getParams().getCurve());
+        } else if (expectedKey instanceof RSAKey) {
             assertEquals("Returned PrivateKey should be what we inserted",
-                    ((RSAPrivateKey) expectedKey).getModulus(),
-                    ((RSAPrivateKey) keyEntry.getPrivateKey()).getModulus());
+                    ((RSAKey) expectedKey).getModulus(),
+                    ((RSAKey) keyEntry.getPrivateKey()).getModulus());
         }
 
         assertEquals("Returned Certificate should be what we inserted", expectedCert,
@@ -1263,15 +1256,14 @@
         Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
         assertNotNull("Key should exist", key);
 
-        assertTrue("Should be a RSAPrivateKey", key instanceof RSAPrivateKey);
-
-        RSAPrivateKey actualKey = (RSAPrivateKey) key;
+        assertTrue("Should be a PrivateKey", key instanceof PrivateKey);
+        assertTrue("Should be a RSAKey", key instanceof RSAKey);
 
         KeyFactory keyFact = KeyFactory.getInstance("RSA");
         PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
 
         assertEquals("Inserted key should be same as retrieved key",
-                ((RSAPrivateKey) expectedKey).getModulus(), actualKey.getModulus());
+                ((RSAKey) expectedKey).getModulus(), ((RSAKey) key).getModulus());
     }
 
     public void testKeyStore_GetKey_NoPassword_Unencrypted_Success() throws Exception {
@@ -1287,15 +1279,14 @@
         Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
         assertNotNull("Key should exist", key);
 
-        assertTrue("Should be a RSAPrivateKey", key instanceof RSAPrivateKey);
-
-        RSAPrivateKey actualKey = (RSAPrivateKey) key;
+        assertTrue("Should be a PrivateKey", key instanceof PrivateKey);
+        assertTrue("Should be a RSAKey", key instanceof RSAKey);
 
         KeyFactory keyFact = KeyFactory.getInstance("RSA");
         PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
 
         assertEquals("Inserted key should be same as retrieved key",
-                ((RSAPrivateKey) expectedKey).getModulus(), actualKey.getModulus());
+                ((RSAKey) expectedKey).getModulus(), ((RSAKey) key).getModulus());
     }
 
     public void testKeyStore_GetKey_Certificate_Encrypted_Failure() throws Exception {
@@ -1926,31 +1917,11 @@
             Date notAfter) throws Exception {
         final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
 
-        final PrivateKey privKey;
-        final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
-        try {
-            privKey = engine.getPrivateKeyById(privateKeyAlias);
-        } catch (InvalidKeyException e) {
-            throw new RuntimeException("Can't get key", e);
-        }
-
-        ExportResult exportResult =
-                keyStore.exportKey(privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
-        assertEquals(KeyStore.NO_ERROR, exportResult.resultCode);
-        final byte[] pubKeyBytes = exportResult.exportData;
-
-        final PublicKey pubKey;
-        try {
-            final KeyFactory keyFact = KeyFactory.getInstance("RSA");
-            pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
-        } catch (NoSuchAlgorithmException e) {
-            throw new IllegalStateException("Can't instantiate RSA key generator", e);
-        } catch (InvalidKeySpecException e) {
-            throw new IllegalStateException("keystore returned invalid key encoding", e);
-        }
+        KeyPair keyPair = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
+                keyStore, privateKeyAlias);
 
         final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
-        certGen.setPublicKey(pubKey);
+        certGen.setPublicKey(keyPair.getPublic());
         certGen.setSerialNumber(serialNumber);
         certGen.setSubjectDN(subjectDN);
         certGen.setIssuerDN(subjectDN);
@@ -1958,7 +1929,7 @@
         certGen.setNotAfter(notAfter);
         certGen.setSignatureAlgorithm("sha1WithRSA");
 
-        final X509Certificate cert = certGen.generate(privKey);
+        final X509Certificate cert = certGen.generate(keyPair.getPrivate());
 
         return cert;
     }
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 49614bd..635fa11 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -72,6 +72,12 @@
     jmethodID ctor;
 } gSurfacePlaneClassInfo;
 
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+    static volatile int32_t globalCounter = 0;
+    return android_atomic_inc(&globalCounter);
+}
+
 // ----------------------------------------------------------------------------
 
 class JNIImageReaderContext : public ConsumerBase::FrameAvailableListener
@@ -808,6 +814,9 @@
     sp<ConsumerBase> consumer;
     sp<CpuConsumer> cpuConsumer;
     sp<BufferItemConsumer> opaqueConsumer;
+    String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
+            width, height, format, maxImages, getpid(),
+            createProcessUniqueId());
     if (isFormatOpaque(nativeFormat)) {
         // Use the SW_READ_NEVER usage to tell producer that this format is not for preview or video
         // encoding. The only possibility will be ZSL output.
@@ -819,6 +828,7 @@
             return;
         }
         ctx->setOpaqueConsumer(opaqueConsumer);
+        opaqueConsumer->setName(consumerName);
         consumer = opaqueConsumer;
     } else {
         cpuConsumer = new CpuConsumer(gbConsumer, maxImages, /*controlledByApp*/true);
@@ -828,6 +838,7 @@
             return;
         }
         ctx->setCpuConsumer(cpuConsumer);
+        cpuConsumer->setName(consumerName);
         consumer = cpuConsumer;
     }
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
index bcfcbf3..8f7d6ac 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
@@ -60,6 +60,7 @@
     private static boolean onPrepareSuccess = false;
     public static boolean onCompleteSuccess = false;
     public static boolean mPlaybackError = false;
+    public static boolean mFailedToCompleteWithNoError = true;
     public static int mMediaInfoUnknownCount = 0;
     public static int mMediaInfoVideoTrackLaggingCount = 0;
     public static int mMediaInfoBadInterleavingCount = 0;
@@ -801,6 +802,7 @@
         mMediaInfoNotSeekableCount = 0;
         mMediaInfoMetdataUpdateCount = 0;
         mPlaybackError = false;
+        mFailedToCompleteWithNoError = true;
         String testResult;
 
         initializeMessageLooper();
@@ -843,6 +845,9 @@
         } catch (Exception e) {
             Log.v(TAG, "playMediaSamples:" + e.getMessage());
         }
+        // Check if playback state is unknown (neither completed nor erroneous) unless
+        // it's not interrupted in the middle. If true, that is an exceptional case to investigate.
+        mFailedToCompleteWithNoError = !(onCompleteSuccess || mPlaybackError);
         return onCompleteSuccess;
     }
 }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
index e289812..4221f1b 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
@@ -65,6 +65,7 @@
     private int mTotalBadInterleaving = 0;
     private int mTotalNotSeekable = 0;
     private int mTotalMetaDataUpdate = 0;
+    private int mTotalFailedToCompleteWithNoError = 0;
 
     //Test result output file
     private static final String PLAYBACK_RESULT = "PlaybackTestResult.txt";
@@ -78,6 +79,8 @@
         output.write(" Bad Interleaving: " + CodecTest.mMediaInfoBadInterleavingCount);
         output.write(" Not Seekable: " + CodecTest.mMediaInfoNotSeekableCount);
         output.write(" Info Meta data update: " + CodecTest.mMediaInfoMetdataUpdateCount);
+        output.write(" Failed To Complete With No Error: " +
+                CodecTest.mFailedToCompleteWithNoError);
         output.write("\n");
     }
 
@@ -90,16 +93,21 @@
         output.write("Total Bad Interleaving: " + mTotalBadInterleaving + "\n");
         output.write("Total Not Seekable: " + mTotalNotSeekable + "\n");
         output.write("Total Info Meta data update: " + mTotalMetaDataUpdate + "\n");
+        output.write("Total Failed To Complete With No Error: " +
+                mTotalFailedToCompleteWithNoError);
         output.write("\n");
     }
 
     private void updateTestResult(){
-        if (CodecTest.onCompleteSuccess){
+        if (CodecTest.onCompleteSuccess) {
             mTotalComplete++;
         }
-        else if (CodecTest.mPlaybackError){
+        else if (CodecTest.mPlaybackError) {
             mTotalPlaybackError++;
         }
+        else if (CodecTest.mFailedToCompleteWithNoError) {
+            mTotalFailedToCompleteWithNoError++;
+        }
         mTotalInfoUnknown += CodecTest.mMediaInfoUnknownCount;
         mTotalVideoTrackLagging += CodecTest.mMediaInfoVideoTrackLaggingCount;
         mTotalBadInterleaving += CodecTest.mMediaInfoBadInterleavingCount;
@@ -149,4 +157,4 @@
             assertTrue("testMediaSamples", testResult);
        }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 943104d..a4e6ce7 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -68,9 +68,6 @@
     <!-- Button label that copies files to the current directory [CHAR LIMIT=24] -->
     <string name="button_copy">Copy</string>
 
-    <!-- Action mode title summarizing the number of documents selected [CHAR LIMIT=32] -->
-    <string name="mode_selected_count"><xliff:g id="count" example="3">%1$d</xliff:g> selected</string>
-
     <!-- Mode that sorts documents by their display name alphabetically [CHAR LIMIT=24] -->
     <string name="sort_name">By name</string>
     <!-- Mode that sorts documents by their last modified time in descending order; most recent first [CHAR LIMIT=24] -->
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index a789da8..f4be9c5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -54,6 +54,7 @@
 import android.os.Parcelable;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
+import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.text.format.Formatter;
 import android.text.format.Time;
@@ -474,8 +475,7 @@
         @Override
         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
             mode.getMenuInflater().inflate(R.menu.mode_directory, menu);
-            mode.setTitle(getResources()
-                    .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount()));
+            mode.setTitle(TextUtils.formatSelectedCount(mCurrentView.getCheckedItemCount()));
             return true;
         }
 
@@ -571,8 +571,7 @@
                 }
             }
 
-            mode.setTitle(getResources()
-                    .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount()));
+            mode.setTitle(TextUtils.formatSelectedCount(mCurrentView.getCheckedItemCount()));
         }
     };
 
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java b/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java
index 3b59fd6..fe9b99a 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java
@@ -90,7 +90,7 @@
      * Creates a new StatementRetriever that directly retrieves statements from the asset.
      *
      * <p> For web assets, {@link AbstractStatementRetriever} will try to retrieve the statement
-     * file from URL: {@code [webAsset.site]/.well-known/statements.json"} where {@code
+     * file from URL: {@code [webAsset.site]/.well-known/assetlinks.json"} where {@code
      * [webAsset.site]} is in the form {@code http{s}://[hostname]:[optional_port]}. The file
      * should contain one JSON array of statements.
      *
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java b/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
index 2ca85e9..e4feb90 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
@@ -38,7 +38,7 @@
     private static final int HTTP_CONNECTION_TIMEOUT_MILLIS = 5000;
     private static final long HTTP_CONTENT_SIZE_LIMIT_IN_BYTES = 1024 * 1024;
     private static final int MAX_INCLUDE_LEVEL = 1;
-    private static final String WELL_KNOWN_STATEMENT_PATH = "/.well-known/statements.json";
+    private static final String WELL_KNOWN_STATEMENT_PATH = "/.well-known/assetlinks.json";
 
     private final URLFetcher mUrlFetcher;
     private final AndroidPackageInfoFetcher mAndroidFetcher;
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/Statement.java b/packages/StatementService/src/com/android/statementservice/retriever/Statement.java
index da3c355..0f40a62 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/Statement.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/Statement.java
@@ -21,7 +21,7 @@
 /**
  * An immutable value type representing a statement, consisting of a source, target, and relation.
  * This reflects an assertion that the relation holds for the source, target pair. For example, if a
- * web site has the following in its statements.json file:
+ * web site has the following in its assetlinks.json file:
  *
  * <pre>
  * {
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java b/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
index 969aa88..225e26c 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
@@ -60,33 +60,36 @@
             throw new IllegalArgumentException("The url protocol should be on http or https.");
         }
 
-        HttpURLConnection connection;
-        connection = (HttpURLConnection) url.openConnection();
-        connection.setInstanceFollowRedirects(true);
-        connection.setConnectTimeout(connectionTimeoutMillis);
-        connection.setReadTimeout(connectionTimeoutMillis);
-        connection.setUseCaches(true);
-        connection.setInstanceFollowRedirects(false);
-        connection.addRequestProperty("Cache-Control", "max-stale=60");
-
-        if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
-            Log.e(TAG, "The responses code is not 200 but "  + connection.getResponseCode());
-            return new WebContent("", DO_NOT_CACHE_RESULT);
-        }
-
-        if (connection.getContentLength() > fileSizeLimit) {
-            Log.e(TAG, "The content size of the url is larger than "  + fileSizeLimit);
-            return new WebContent("", DO_NOT_CACHE_RESULT);
-        }
-
-        Long expireTimeMillis = getExpirationTimeMillisFromHTTPHeader(connection.getHeaderFields());
-
+        HttpURLConnection connection = null;
         try {
+            connection = (HttpURLConnection) url.openConnection();
+            connection.setInstanceFollowRedirects(true);
+            connection.setConnectTimeout(connectionTimeoutMillis);
+            connection.setReadTimeout(connectionTimeoutMillis);
+            connection.setUseCaches(true);
+            connection.setInstanceFollowRedirects(false);
+            connection.addRequestProperty("Cache-Control", "max-stale=60");
+
+            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
+                Log.e(TAG, "The responses code is not 200 but "  + connection.getResponseCode());
+                return new WebContent("", DO_NOT_CACHE_RESULT);
+            }
+
+            if (connection.getContentLength() > fileSizeLimit) {
+                Log.e(TAG, "The content size of the url is larger than "  + fileSizeLimit);
+                return new WebContent("", DO_NOT_CACHE_RESULT);
+            }
+
+            Long expireTimeMillis = getExpirationTimeMillisFromHTTPHeader(
+                    connection.getHeaderFields());
+
             return new WebContent(inputStreamToString(
                     connection.getInputStream(), connection.getContentLength(), fileSizeLimit),
                 expireTimeMillis);
         } finally {
-            connection.disconnect();
+            if (connection != null) {
+                connection.disconnect();
+            }
         }
     }
 
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index a996260..38ea6e1 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -35,6 +35,7 @@
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
         android:layout_weight="1"
+        android:contentDescription="@string/accessibility_brightness"
         systemui:text="@string/status_bar_settings_auto_brightness_label" />
 
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
index a5bf68e..062e6cb 100644
--- a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
+++ b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
@@ -45,7 +45,6 @@
         android:paddingBottom="16dp"
         android:thumb="@drawable/ic_brightness_thumb"
         android:splitTrack="false"
-        android:contentDescription="@string/accessibility_brightness"
         />
     <TextView
         android:id="@+id/label"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 7c378f0..915867b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -73,6 +73,10 @@
                 : mController.isRotationLocked();
         final boolean userInitiated = arg != null ? ((UserBoolean) arg).userInitiated : false;
         state.visible = mController.isRotationLockAffordanceVisible();
+        if (state.value == rotationLocked) {
+            // No change, no need to update all the values.
+            return;
+        }
         state.value = rotationLocked;
         final boolean portrait = mContext.getResources().getConfiguration().orientation
                 != Configuration.ORIENTATION_LANDSCAPE;
diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
index 8abfe03..cdb8e69 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
@@ -74,6 +74,8 @@
         mLabel = (TextView) findViewById(R.id.label);
         mLabel.setText(a.getString(R.styleable.ToggleSlider_text));
 
+        setLabelFor(R.id.slider); // use our a11y text to annotate, not replace, the slider's
+
         a.recycle();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 03d0482..296538c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -134,6 +134,14 @@
     }
 
     @Override
+    public boolean dispatchGenericMotionEvent(MotionEvent ev) {
+        if (filterMotionEvent(ev)) {
+            return super.dispatchGenericMotionEvent(ev);
+        }
+        return false;
+    }
+
+    @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
         if (filterMotionEvent(ev)) {
             return super.dispatchTouchEvent(ev);
@@ -143,6 +151,8 @@
 
     protected boolean filterMotionEvent(MotionEvent event) {
         return event.getActionMasked() != MotionEvent.ACTION_DOWN
+                && event.getActionMasked() != MotionEvent.ACTION_HOVER_ENTER
+                && event.getActionMasked() != MotionEvent.ACTION_HOVER_MOVE
                 || event.getY() > mClipTopAmount && event.getY() < mActualHeight;
     }
 
@@ -344,6 +354,7 @@
     public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
         super.getBoundsOnScreen(outRect, clipToParent);
         outRect.bottom = (int) (outRect.top + getActualHeight());
+        outRect.top += getClipTopAmount();
     }
 
     public int getContentHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 7f1fea1..634270c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -83,6 +83,10 @@
             insets.top = 0;
             insets.right = 0;
         } else {
+            if (mRightInset != 0) {
+                mRightInset = 0;
+                applyMargins();
+            }
             boolean changed = getPaddingLeft() != 0
                     || getPaddingRight() != 0
                     || getPaddingTop() != 0
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0d08c2a..27656d4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -32,6 +32,7 @@
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -4197,9 +4198,9 @@
             if (rootR == null) {
                 Slog.w(TAG, "Finishing task with all activities already finished");
             }
-            // Do not allow task to finish if last task in lockTask mode. Launchable apps can
-            // finish themselves.
-            if (tr.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE && rootR == r &&
+            // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps can
+            // finish.
+            if (tr.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV && rootR == r &&
                     mStackSupervisor.isLastLockedTask(tr)) {
                 Slog.i(TAG, "Not finishing task in lock task mode");
                 mStackSupervisor.showLockTaskToast();
@@ -4361,9 +4362,10 @@
                     return false;
                 }
 
-                // Do not allow the last non-launchable task to finish in Lock Task mode.
+                // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps
+                // can finish.
                 final TaskRecord task = r.task;
-                if (task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE &&
+                if (task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV &&
                         mStackSupervisor.isLastLockedTask(task) && task.getRootActivity() == r) {
                     mStackSupervisor.showLockTaskToast();
                     return false;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 23e62e2..9e33f2a 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -35,6 +35,7 @@
 import static com.android.server.am.ActivityStack.ActivityState.*;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
 
@@ -1179,7 +1180,8 @@
         mService.updateOomAdjLocked();
 
         final TaskRecord task = r.task;
-        if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
+        if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE ||
+                task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV) {
             setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", false);
         }
 
@@ -3785,6 +3787,7 @@
         switch (lockTaskAuth) {
             case LOCK_TASK_AUTH_DONT_LOCK:
                 return !mLockTaskModeTasks.isEmpty();
+            case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
             case LOCK_TASK_AUTH_LAUNCHABLE:
             case LOCK_TASK_AUTH_WHITELISTED:
                 return false;
@@ -3801,12 +3804,14 @@
         boolean didSomething = false;
         for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord lockedTask = mLockTaskModeTasks.get(taskNdx);
-            if (lockedTask.mLockTaskMode != LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED) {
-                continue;
-            }
-            final boolean wasLaunchable = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE;
+            final boolean wasWhitelisted =
+                    (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) ||
+                    (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED);
             lockedTask.setLockTaskAuth();
-            if (wasLaunchable && lockedTask.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE) {
+            final boolean isWhitelisted =
+                    (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) ||
+                    (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED);
+            if (wasWhitelisted && !isWhitelisted) {
                 // Lost whitelisting authorization. End it now.
                 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
                         lockedTask + " mLockTaskAuth=" + lockedTask.lockTaskAuthToString());
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index f966bcf..78f9f18 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -134,12 +134,15 @@
 
     /** Can't be put in lockTask mode. */
     final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
-    /** Can enter lockTask with user approval. Can never start over existing lockTask task. */
+    /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
     final static int LOCK_TASK_AUTH_PINNABLE = 1;
     /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
     final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
-    /** Can enter lockTask with user approval. Can start over existing lockTask task. */
+    /** Can enter lockTask without user approval. Can start over existing lockTask task. */
     final static int LOCK_TASK_AUTH_WHITELISTED = 3;
+    /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
+     * lockTask task. */
+    final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
     int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
 
     int mLockTaskUid = -1;  // The uid of the application that called startLockTask().
@@ -747,11 +750,18 @@
             case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
             case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
             case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
+            case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
             default: return "unknown=" + mLockTaskAuth;
         }
     }
 
     void setLockTaskAuth() {
+        if (!mPrivileged &&
+                (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS ||
+                        mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
+            // Non-priv apps are not allowed to use always or never, fall back to default
+            mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
+        }
         switch (mLockTaskMode) {
             case LOCK_TASK_LAUNCH_MODE_DEFAULT:
                 mLockTaskAuth = isLockTaskWhitelistedLocked() ?
@@ -759,13 +769,11 @@
                 break;
 
             case LOCK_TASK_LAUNCH_MODE_NEVER:
-                mLockTaskAuth = mPrivileged ?
-                        LOCK_TASK_AUTH_DONT_LOCK : LOCK_TASK_AUTH_PINNABLE;
+                mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
                 break;
 
             case LOCK_TASK_LAUNCH_MODE_ALWAYS:
-                mLockTaskAuth = mPrivileged ?
-                        LOCK_TASK_AUTH_LAUNCHABLE: LOCK_TASK_AUTH_PINNABLE;
+                mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
                 break;
 
             case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ab1206b..2753700 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5975,40 +5975,6 @@
     }
 
     @Override
-    public void sendDeviceInitializerStatus(int statusCode, String description) {
-        synchronized (this) {
-            String packageName = getDeviceInitializer();
-            if (packageName == null) {
-                throw new SecurityException("No device initializers");
-            }
-            UserHandle callingUser = Binder.getCallingUserHandle();
-            int deviceInitializerUid = -1;
-            try {
-                deviceInitializerUid = mContext.getPackageManager().getPackageUid(
-                        packageName, callingUser.getIdentifier());
-            } catch (NameNotFoundException e) {
-                throw new SecurityException(e);
-            }
-            if (Binder.getCallingUid() != deviceInitializerUid) {
-                throw new SecurityException("Caller must be a device initializer");
-            }
-            long id = Binder.clearCallingIdentity();
-            try {
-                Intent intent = new Intent(
-                        DevicePolicyManager.ACTION_SEND_DEVICE_INITIALIZER_STATUS);
-                intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_INITIALIZER_STATUS_CODE,
-                        statusCode);
-                intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_INITIALIZER_STATUS_DESCRIPTION,
-                        description);
-                mContext.sendBroadcastAsUser(intent, callingUser,
-                        android.Manifest.permission.RECEIVE_DEVICE_INITIALIZER_STATUS);
-            } finally {
-                restoreCallingIdentity(id);
-            }
-        }
-    }
-
-    @Override
     public boolean setKeyguardDisabled(ComponentName who, boolean disabled) {
         Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 6de438c..da0c547 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -114,11 +114,6 @@
      * (Some carriers require that emergency calls *not* be logged, presumably to avoid the risk of
      * accidental redialing from the call log UI. This is a good idea, so the default here is
      * false.)
-     * <p>
-     * TODO: on the other hand, it might still be useful to have some record of the emergency calls
-     * you've made, or to be able to look up the exact date/time of an emergency call. So perhaps we
-     * <b>should</b> log those calls, but instead fix the call log to disable the "call" button for
-     * emergency numbers.
      */
     public static final String
             KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";