Merge "Actually relabel emergency affordance"
diff --git a/Android.mk b/Android.mk
index 3e049f7..f4b9551 100644
--- a/Android.mk
+++ b/Android.mk
@@ -195,7 +195,6 @@
 	core/java/android/os/IBatteryPropertiesListener.aidl \
 	core/java/android/os/IBatteryPropertiesRegistrar.aidl \
 	core/java/android/os/ICancellationSignal.aidl \
-	core/java/android/os/IHardwareService.aidl \
 	core/java/android/os/IMessenger.aidl \
 	core/java/android/os/INetworkActivityListener.aidl \
 	core/java/android/os/INetworkManagementService.aidl \
diff --git a/api/current.txt b/api/current.txt
index 66c0447..6de9a03 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5615,6 +5615,26 @@
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
   }
 
+  public class DeviceInitializerStatus {
+    method public static boolean isCustomStatus(int);
+    method public static boolean isErrorStatus(int);
+    method public static boolean isHighPriority(int);
+    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_CONNECT_BLUETOOTH_PROXY = 134217736; // 0x8000008
+    field public static final int STATUS_STATE_DEVICE_PROVISIONED = 134217738; // 0x800000a
+    field public static final int STATUS_STATE_DISCONNECT_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);
@@ -5678,6 +5698,7 @@
     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);
@@ -28040,6 +28061,43 @@
 
 package android.security {
 
+  public class CryptoOperationException extends java.lang.RuntimeException {
+    ctor public CryptoOperationException();
+    ctor public CryptoOperationException(java.lang.String);
+    ctor public CryptoOperationException(java.lang.String, java.lang.Throwable);
+    ctor public CryptoOperationException(java.lang.Throwable);
+  }
+
+  public class EcIesParameterSpec implements java.security.spec.AlgorithmParameterSpec {
+    method public int getDemCipherKeySize();
+    method public java.lang.String getDemCipherTransformation();
+    method public java.lang.String getDemMacAlgorithm();
+    method public int getDemMacKeySize();
+    method public java.lang.String getKemKdfAlgorithm();
+    method public int getKemPointFormat();
+    field public static final android.security.EcIesParameterSpec DEFAULT;
+  }
+
+  public static class EcIesParameterSpec.Builder {
+    ctor public EcIesParameterSpec.Builder();
+    method public android.security.EcIesParameterSpec build();
+    method public android.security.EcIesParameterSpec.Builder setDemCipherKeySize(int);
+    method public android.security.EcIesParameterSpec.Builder setDemCipherTransformation(java.lang.String);
+    method public android.security.EcIesParameterSpec.Builder setDemMacAlgorithm(java.lang.String);
+    method public android.security.EcIesParameterSpec.Builder setDemMacKeySize(int);
+    method public android.security.EcIesParameterSpec.Builder setKemKdfAlgorithm(java.lang.String);
+    method public android.security.EcIesParameterSpec.Builder setKemPointFormat(int);
+  }
+
+  public static abstract class EcIesParameterSpec.PointFormat {
+    field public static final int COMPRESSED = 1; // 0x1
+    field public static final int UNCOMPRESSED = 0; // 0x0
+    field public static final int UNSPECIFIED = -1; // 0xffffffff
+  }
+
+  public static abstract class EcIesParameterSpec.PointFormatEnum implements java.lang.annotation.Annotation {
+  }
+
   public final class KeyChain {
     ctor public KeyChain();
     method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String);
@@ -28066,17 +28124,77 @@
     ctor public KeyChainException(java.lang.Throwable);
   }
 
+  public class KeyExpiredException extends android.security.CryptoOperationException {
+    ctor public KeyExpiredException();
+    ctor public KeyExpiredException(java.lang.String);
+    ctor public KeyExpiredException(java.lang.String, java.lang.Throwable);
+  }
+
+  public class KeyGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
+    method public java.lang.String[] getBlockModes();
+    method public android.content.Context getContext();
+    method public java.lang.String[] getEncryptionPaddings();
+    method public int getKeySize();
+    method public java.util.Date getKeyValidityForConsumptionEnd();
+    method public java.util.Date getKeyValidityForOriginationEnd();
+    method public java.util.Date getKeyValidityStart();
+    method public java.lang.String getKeystoreAlias();
+    method public int getPurposes();
+    method public int getUserAuthenticationValidityDurationSeconds();
+    method public int getUserAuthenticators();
+    method public boolean isEncryptionRequired();
+    method public boolean isInvalidatedOnNewFingerprintEnrolled();
+    method public boolean isRandomizedEncryptionRequired();
+  }
+
+  public static class KeyGeneratorSpec.Builder {
+    ctor public KeyGeneratorSpec.Builder(android.content.Context);
+    method public android.security.KeyGeneratorSpec build();
+    method public android.security.KeyGeneratorSpec.Builder setAlias(java.lang.String);
+    method public android.security.KeyGeneratorSpec.Builder setBlockModes(java.lang.String...);
+    method public android.security.KeyGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...);
+    method public android.security.KeyGeneratorSpec.Builder setEncryptionRequired(boolean);
+    method public android.security.KeyGeneratorSpec.Builder setInvalidatedOnNewFingerprintEnrolled(boolean);
+    method public android.security.KeyGeneratorSpec.Builder setKeySize(int);
+    method public android.security.KeyGeneratorSpec.Builder setKeyValidityEnd(java.util.Date);
+    method public android.security.KeyGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
+    method public android.security.KeyGeneratorSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
+    method public android.security.KeyGeneratorSpec.Builder setKeyValidityStart(java.util.Date);
+    method public android.security.KeyGeneratorSpec.Builder setPurposes(int);
+    method public android.security.KeyGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean);
+    method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
+    method public android.security.KeyGeneratorSpec.Builder setUserAuthenticators(int);
+  }
+
+  public class KeyNotYetValidException extends android.security.CryptoOperationException {
+    ctor public KeyNotYetValidException();
+    ctor public KeyNotYetValidException(java.lang.String);
+    ctor public KeyNotYetValidException(java.lang.String, java.lang.Throwable);
+  }
+
   public final class KeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
     method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
+    method public java.lang.String[] getBlockModes();
     method public android.content.Context getContext();
+    method public java.lang.String[] getDigests();
+    method public java.lang.String[] getEncryptionPaddings();
     method public java.util.Date getEndDate();
     method public int getKeySize();
     method public java.lang.String getKeyType();
+    method public java.util.Date getKeyValidityForConsumptionEnd();
+    method public java.util.Date getKeyValidityForOriginationEnd();
+    method public java.util.Date getKeyValidityStart();
     method public java.lang.String getKeystoreAlias();
+    method public int getPurposes();
     method public java.math.BigInteger getSerialNumber();
+    method public java.lang.String[] getSignaturePaddings();
     method public java.util.Date getStartDate();
     method public javax.security.auth.x500.X500Principal getSubjectDN();
+    method public int getUserAuthenticationValidityDurationSeconds();
+    method public int getUserAuthenticators();
     method public boolean isEncryptionRequired();
+    method public boolean isInvalidatedOnNewFingerprintEnrolled();
+    method public boolean isRandomizedEncryptionRequired();
   }
 
   public static final class KeyPairGeneratorSpec.Builder {
@@ -28084,23 +28202,110 @@
     method public android.security.KeyPairGeneratorSpec build();
     method public android.security.KeyPairGeneratorSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
     method public android.security.KeyPairGeneratorSpec.Builder setAlias(java.lang.String);
+    method public android.security.KeyPairGeneratorSpec.Builder setBlockModes(java.lang.String...);
+    method public android.security.KeyPairGeneratorSpec.Builder setDigests(java.lang.String...);
+    method public android.security.KeyPairGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...);
     method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired();
     method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setInvalidatedOnNewFingerprintEnrolled(boolean);
     method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int);
     method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException;
+    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityEnd(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityStart(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setPurposes(int);
+    method public android.security.KeyPairGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean);
     method public android.security.KeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger);
+    method public android.security.KeyPairGeneratorSpec.Builder setSignaturePaddings(java.lang.String...);
     method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date);
     method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal);
+    method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
+    method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticators(int);
+  }
+
+  public abstract class KeyStoreKeyProperties {
+  }
+
+  public static abstract class KeyStoreKeyProperties.Origin {
+    field public static final int GENERATED = 1; // 0x1
+    field public static final int IMPORTED = 2; // 0x2
+  }
+
+  public static abstract class KeyStoreKeyProperties.OriginEnum implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class KeyStoreKeyProperties.Purpose {
+    field public static final int DECRYPT = 2; // 0x2
+    field public static final int ENCRYPT = 1; // 0x1
+    field public static final int SIGN = 4; // 0x4
+    field public static final int VERIFY = 8; // 0x8
+  }
+
+  public static abstract class KeyStoreKeyProperties.PurposeEnum implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class KeyStoreKeyProperties.UserAuthenticator {
+    field public static final int FINGERPRINT_READER = 2; // 0x2
+    field public static final int LOCK_SCREEN = 1; // 0x1
+  }
+
+  public static abstract class KeyStoreKeyProperties.UserAuthenticatorEnum implements java.lang.annotation.Annotation {
+  }
+
+  public class KeyStoreKeySpec implements java.security.spec.KeySpec {
+    method public java.lang.String[] getBlockModes();
+    method public java.lang.String[] getDigests();
+    method public java.lang.String[] getEncryptionPaddings();
+    method public int getKeySize();
+    method public java.util.Date getKeyValidityForConsumptionEnd();
+    method public java.util.Date getKeyValidityForOriginationEnd();
+    method public java.util.Date getKeyValidityStart();
+    method public java.lang.String getKeystoreAlias();
+    method public int getOrigin();
+    method public int getPurposes();
+    method public java.lang.String[] getSignaturePaddings();
+    method public int getTeeEnforcedUserAuthenticators();
+    method public int getUserAuthenticationValidityDurationSeconds();
+    method public int getUserAuthenticators();
+    method public boolean isInvalidatedOnNewFingerprintEnrolled();
+    method public boolean isTeeBacked();
   }
 
   public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
+    method public java.lang.String[] getBlockModes();
+    method public java.lang.String[] getDigests();
+    method public java.lang.String[] getEncryptionPaddings();
+    method public java.util.Date getKeyValidityForConsumptionEnd();
+    method public java.util.Date getKeyValidityForOriginationEnd();
+    method public java.util.Date getKeyValidityStart();
+    method public int getPurposes();
+    method public java.lang.String[] getSignaturePaddings();
+    method public int getUserAuthenticationValidityDurationSeconds();
+    method public int getUserAuthenticators();
+    method public boolean isDigestsSpecified();
     method public boolean isEncryptionRequired();
+    method public boolean isInvalidatedOnNewFingerprintEnrolled();
+    method public boolean isRandomizedEncryptionRequired();
   }
 
   public static final class KeyStoreParameter.Builder {
     ctor public KeyStoreParameter.Builder(android.content.Context);
     method public android.security.KeyStoreParameter build();
+    method public android.security.KeyStoreParameter.Builder setBlockModes(java.lang.String...);
+    method public android.security.KeyStoreParameter.Builder setDigests(java.lang.String...);
+    method public android.security.KeyStoreParameter.Builder setEncryptionPaddings(java.lang.String...);
     method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
+    method public android.security.KeyStoreParameter.Builder setInvalidatedOnNewFingerprintEnrolled(boolean);
+    method public android.security.KeyStoreParameter.Builder setKeyValidityEnd(java.util.Date);
+    method public android.security.KeyStoreParameter.Builder setKeyValidityForConsumptionEnd(java.util.Date);
+    method public android.security.KeyStoreParameter.Builder setKeyValidityForOriginationEnd(java.util.Date);
+    method public android.security.KeyStoreParameter.Builder setKeyValidityStart(java.util.Date);
+    method public android.security.KeyStoreParameter.Builder setPurposes(int);
+    method public android.security.KeyStoreParameter.Builder setRandomizedEncryptionRequired(boolean);
+    method public android.security.KeyStoreParameter.Builder setSignaturePaddings(java.lang.String...);
+    method public android.security.KeyStoreParameter.Builder setUserAuthenticationValidityDurationSeconds(int);
+    method public android.security.KeyStoreParameter.Builder setUserAuthenticators(int);
   }
 
   public class NetworkSecurityPolicy {
@@ -28108,6 +28313,17 @@
     method public boolean isCleartextTrafficPermitted();
   }
 
+  public class NewFingerprintEnrolledException extends android.security.CryptoOperationException {
+    ctor public NewFingerprintEnrolledException();
+    ctor public NewFingerprintEnrolledException(java.lang.String);
+  }
+
+  public class UserNotAuthenticatedException extends android.security.CryptoOperationException {
+    ctor public UserNotAuthenticatedException();
+    ctor public UserNotAuthenticatedException(java.lang.String);
+    ctor public UserNotAuthenticatedException(java.lang.String, java.lang.Throwable);
+  }
+
 }
 
 package android.service.carrier {
@@ -35617,10 +35833,10 @@
     method public int indexOfChild(android.view.View);
     method public final void invalidateChild(android.view.View, android.graphics.Rect);
     method public android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
-    method public boolean isAlwaysDrawnWithCacheEnabled();
-    method public boolean isAnimationCacheEnabled();
+    method public deprecated boolean isAlwaysDrawnWithCacheEnabled();
+    method public deprecated boolean isAnimationCacheEnabled();
     method protected boolean isChildrenDrawingOrderEnabled();
-    method protected boolean isChildrenDrawnWithCacheEnabled();
+    method protected deprecated boolean isChildrenDrawnWithCacheEnabled();
     method public boolean isMotionEventSplittingEnabled();
     method public boolean isTransitionGroup();
     method public final void layout(int, int, int, int);
@@ -35659,11 +35875,11 @@
     method public void requestTransparentRegion(android.view.View);
     method public void scheduleLayoutAnimation();
     method public void setAddStatesFromChildren(boolean);
-    method public void setAlwaysDrawnWithCacheEnabled(boolean);
-    method public void setAnimationCacheEnabled(boolean);
+    method public deprecated void setAlwaysDrawnWithCacheEnabled(boolean);
+    method public deprecated void setAnimationCacheEnabled(boolean);
     method protected void setChildrenDrawingCacheEnabled(boolean);
     method protected void setChildrenDrawingOrderEnabled(boolean);
-    method protected void setChildrenDrawnWithCacheEnabled(boolean);
+    method protected deprecated void setChildrenDrawnWithCacheEnabled(boolean);
     method public void setClipChildren(boolean);
     method public void setClipToPadding(boolean);
     method public void setDescendantFocusability(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 7694bf5..708394c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5710,6 +5710,26 @@
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
   }
 
+  public class DeviceInitializerStatus {
+    method public static boolean isCustomStatus(int);
+    method public static boolean isErrorStatus(int);
+    method public static boolean isHighPriority(int);
+    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_CONNECT_BLUETOOTH_PROXY = 134217736; // 0x8000008
+    field public static final int STATUS_STATE_DEVICE_PROVISIONED = 134217738; // 0x800000a
+    field public static final int STATUS_STATE_DISCONNECT_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);
@@ -5781,6 +5801,7 @@
     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);
@@ -5826,6 +5847,7 @@
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
     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_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";
@@ -5836,6 +5858,8 @@
     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";
@@ -28973,7 +28997,6 @@
 
   public static final class VoicemailContract.Status implements android.provider.BaseColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
-    method public static void setStatus(android.content.Context, android.telecom.PhoneAccountHandle, int, int, int);
     field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
     field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
     field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
@@ -28997,9 +29020,6 @@
 
   public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
-    method public static int deleteAll(android.content.Context);
-    method public static android.net.Uri insert(android.content.Context, android.telecom.Voicemail);
-    method public static int insert(android.content.Context, java.util.List<android.telecom.Voicemail>);
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATE = "date";
     field public static final java.lang.String DELETED = "deleted";
@@ -30040,6 +30060,43 @@
 
 package android.security {
 
+  public class CryptoOperationException extends java.lang.RuntimeException {
+    ctor public CryptoOperationException();
+    ctor public CryptoOperationException(java.lang.String);
+    ctor public CryptoOperationException(java.lang.String, java.lang.Throwable);
+    ctor public CryptoOperationException(java.lang.Throwable);
+  }
+
+  public class EcIesParameterSpec implements java.security.spec.AlgorithmParameterSpec {
+    method public int getDemCipherKeySize();
+    method public java.lang.String getDemCipherTransformation();
+    method public java.lang.String getDemMacAlgorithm();
+    method public int getDemMacKeySize();
+    method public java.lang.String getKemKdfAlgorithm();
+    method public int getKemPointFormat();
+    field public static final android.security.EcIesParameterSpec DEFAULT;
+  }
+
+  public static class EcIesParameterSpec.Builder {
+    ctor public EcIesParameterSpec.Builder();
+    method public android.security.EcIesParameterSpec build();
+    method public android.security.EcIesParameterSpec.Builder setDemCipherKeySize(int);
+    method public android.security.EcIesParameterSpec.Builder setDemCipherTransformation(java.lang.String);
+    method public android.security.EcIesParameterSpec.Builder setDemMacAlgorithm(java.lang.String);
+    method public android.security.EcIesParameterSpec.Builder setDemMacKeySize(int);
+    method public android.security.EcIesParameterSpec.Builder setKemKdfAlgorithm(java.lang.String);
+    method public android.security.EcIesParameterSpec.Builder setKemPointFormat(int);
+  }
+
+  public static abstract class EcIesParameterSpec.PointFormat {
+    field public static final int COMPRESSED = 1; // 0x1
+    field public static final int UNCOMPRESSED = 0; // 0x0
+    field public static final int UNSPECIFIED = -1; // 0xffffffff
+  }
+
+  public static abstract class EcIesParameterSpec.PointFormatEnum implements java.lang.annotation.Annotation {
+  }
+
   public final class KeyChain {
     ctor public KeyChain();
     method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String);
@@ -30066,17 +30123,77 @@
     ctor public KeyChainException(java.lang.Throwable);
   }
 
+  public class KeyExpiredException extends android.security.CryptoOperationException {
+    ctor public KeyExpiredException();
+    ctor public KeyExpiredException(java.lang.String);
+    ctor public KeyExpiredException(java.lang.String, java.lang.Throwable);
+  }
+
+  public class KeyGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
+    method public java.lang.String[] getBlockModes();
+    method public android.content.Context getContext();
+    method public java.lang.String[] getEncryptionPaddings();
+    method public int getKeySize();
+    method public java.util.Date getKeyValidityForConsumptionEnd();
+    method public java.util.Date getKeyValidityForOriginationEnd();
+    method public java.util.Date getKeyValidityStart();
+    method public java.lang.String getKeystoreAlias();
+    method public int getPurposes();
+    method public int getUserAuthenticationValidityDurationSeconds();
+    method public int getUserAuthenticators();
+    method public boolean isEncryptionRequired();
+    method public boolean isInvalidatedOnNewFingerprintEnrolled();
+    method public boolean isRandomizedEncryptionRequired();
+  }
+
+  public static class KeyGeneratorSpec.Builder {
+    ctor public KeyGeneratorSpec.Builder(android.content.Context);
+    method public android.security.KeyGeneratorSpec build();
+    method public android.security.KeyGeneratorSpec.Builder setAlias(java.lang.String);
+    method public android.security.KeyGeneratorSpec.Builder setBlockModes(java.lang.String...);
+    method public android.security.KeyGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...);
+    method public android.security.KeyGeneratorSpec.Builder setEncryptionRequired(boolean);
+    method public android.security.KeyGeneratorSpec.Builder setInvalidatedOnNewFingerprintEnrolled(boolean);
+    method public android.security.KeyGeneratorSpec.Builder setKeySize(int);
+    method public android.security.KeyGeneratorSpec.Builder setKeyValidityEnd(java.util.Date);
+    method public android.security.KeyGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
+    method public android.security.KeyGeneratorSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
+    method public android.security.KeyGeneratorSpec.Builder setKeyValidityStart(java.util.Date);
+    method public android.security.KeyGeneratorSpec.Builder setPurposes(int);
+    method public android.security.KeyGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean);
+    method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
+    method public android.security.KeyGeneratorSpec.Builder setUserAuthenticators(int);
+  }
+
+  public class KeyNotYetValidException extends android.security.CryptoOperationException {
+    ctor public KeyNotYetValidException();
+    ctor public KeyNotYetValidException(java.lang.String);
+    ctor public KeyNotYetValidException(java.lang.String, java.lang.Throwable);
+  }
+
   public final class KeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
     method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
+    method public java.lang.String[] getBlockModes();
     method public android.content.Context getContext();
+    method public java.lang.String[] getDigests();
+    method public java.lang.String[] getEncryptionPaddings();
     method public java.util.Date getEndDate();
     method public int getKeySize();
     method public java.lang.String getKeyType();
+    method public java.util.Date getKeyValidityForConsumptionEnd();
+    method public java.util.Date getKeyValidityForOriginationEnd();
+    method public java.util.Date getKeyValidityStart();
     method public java.lang.String getKeystoreAlias();
+    method public int getPurposes();
     method public java.math.BigInteger getSerialNumber();
+    method public java.lang.String[] getSignaturePaddings();
     method public java.util.Date getStartDate();
     method public javax.security.auth.x500.X500Principal getSubjectDN();
+    method public int getUserAuthenticationValidityDurationSeconds();
+    method public int getUserAuthenticators();
     method public boolean isEncryptionRequired();
+    method public boolean isInvalidatedOnNewFingerprintEnrolled();
+    method public boolean isRandomizedEncryptionRequired();
   }
 
   public static final class KeyPairGeneratorSpec.Builder {
@@ -30084,23 +30201,110 @@
     method public android.security.KeyPairGeneratorSpec build();
     method public android.security.KeyPairGeneratorSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
     method public android.security.KeyPairGeneratorSpec.Builder setAlias(java.lang.String);
+    method public android.security.KeyPairGeneratorSpec.Builder setBlockModes(java.lang.String...);
+    method public android.security.KeyPairGeneratorSpec.Builder setDigests(java.lang.String...);
+    method public android.security.KeyPairGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...);
     method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired();
     method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setInvalidatedOnNewFingerprintEnrolled(boolean);
     method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int);
     method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException;
+    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityEnd(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityStart(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setPurposes(int);
+    method public android.security.KeyPairGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean);
     method public android.security.KeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger);
+    method public android.security.KeyPairGeneratorSpec.Builder setSignaturePaddings(java.lang.String...);
     method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date);
     method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal);
+    method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
+    method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticators(int);
+  }
+
+  public abstract class KeyStoreKeyProperties {
+  }
+
+  public static abstract class KeyStoreKeyProperties.Origin {
+    field public static final int GENERATED = 1; // 0x1
+    field public static final int IMPORTED = 2; // 0x2
+  }
+
+  public static abstract class KeyStoreKeyProperties.OriginEnum implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class KeyStoreKeyProperties.Purpose {
+    field public static final int DECRYPT = 2; // 0x2
+    field public static final int ENCRYPT = 1; // 0x1
+    field public static final int SIGN = 4; // 0x4
+    field public static final int VERIFY = 8; // 0x8
+  }
+
+  public static abstract class KeyStoreKeyProperties.PurposeEnum implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class KeyStoreKeyProperties.UserAuthenticator {
+    field public static final int FINGERPRINT_READER = 2; // 0x2
+    field public static final int LOCK_SCREEN = 1; // 0x1
+  }
+
+  public static abstract class KeyStoreKeyProperties.UserAuthenticatorEnum implements java.lang.annotation.Annotation {
+  }
+
+  public class KeyStoreKeySpec implements java.security.spec.KeySpec {
+    method public java.lang.String[] getBlockModes();
+    method public java.lang.String[] getDigests();
+    method public java.lang.String[] getEncryptionPaddings();
+    method public int getKeySize();
+    method public java.util.Date getKeyValidityForConsumptionEnd();
+    method public java.util.Date getKeyValidityForOriginationEnd();
+    method public java.util.Date getKeyValidityStart();
+    method public java.lang.String getKeystoreAlias();
+    method public int getOrigin();
+    method public int getPurposes();
+    method public java.lang.String[] getSignaturePaddings();
+    method public int getTeeEnforcedUserAuthenticators();
+    method public int getUserAuthenticationValidityDurationSeconds();
+    method public int getUserAuthenticators();
+    method public boolean isInvalidatedOnNewFingerprintEnrolled();
+    method public boolean isTeeBacked();
   }
 
   public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
+    method public java.lang.String[] getBlockModes();
+    method public java.lang.String[] getDigests();
+    method public java.lang.String[] getEncryptionPaddings();
+    method public java.util.Date getKeyValidityForConsumptionEnd();
+    method public java.util.Date getKeyValidityForOriginationEnd();
+    method public java.util.Date getKeyValidityStart();
+    method public int getPurposes();
+    method public java.lang.String[] getSignaturePaddings();
+    method public int getUserAuthenticationValidityDurationSeconds();
+    method public int getUserAuthenticators();
+    method public boolean isDigestsSpecified();
     method public boolean isEncryptionRequired();
+    method public boolean isInvalidatedOnNewFingerprintEnrolled();
+    method public boolean isRandomizedEncryptionRequired();
   }
 
   public static final class KeyStoreParameter.Builder {
     ctor public KeyStoreParameter.Builder(android.content.Context);
     method public android.security.KeyStoreParameter build();
+    method public android.security.KeyStoreParameter.Builder setBlockModes(java.lang.String...);
+    method public android.security.KeyStoreParameter.Builder setDigests(java.lang.String...);
+    method public android.security.KeyStoreParameter.Builder setEncryptionPaddings(java.lang.String...);
     method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
+    method public android.security.KeyStoreParameter.Builder setInvalidatedOnNewFingerprintEnrolled(boolean);
+    method public android.security.KeyStoreParameter.Builder setKeyValidityEnd(java.util.Date);
+    method public android.security.KeyStoreParameter.Builder setKeyValidityForConsumptionEnd(java.util.Date);
+    method public android.security.KeyStoreParameter.Builder setKeyValidityForOriginationEnd(java.util.Date);
+    method public android.security.KeyStoreParameter.Builder setKeyValidityStart(java.util.Date);
+    method public android.security.KeyStoreParameter.Builder setPurposes(int);
+    method public android.security.KeyStoreParameter.Builder setRandomizedEncryptionRequired(boolean);
+    method public android.security.KeyStoreParameter.Builder setSignaturePaddings(java.lang.String...);
+    method public android.security.KeyStoreParameter.Builder setUserAuthenticationValidityDurationSeconds(int);
+    method public android.security.KeyStoreParameter.Builder setUserAuthenticators(int);
   }
 
   public class NetworkSecurityPolicy {
@@ -30108,6 +30312,17 @@
     method public boolean isCleartextTrafficPermitted();
   }
 
+  public class NewFingerprintEnrolledException extends android.security.CryptoOperationException {
+    ctor public NewFingerprintEnrolledException();
+    ctor public NewFingerprintEnrolledException(java.lang.String);
+  }
+
+  public class UserNotAuthenticatedException extends android.security.CryptoOperationException {
+    ctor public UserNotAuthenticatedException();
+    ctor public UserNotAuthenticatedException(java.lang.String);
+    ctor public UserNotAuthenticatedException(java.lang.String, java.lang.Throwable);
+  }
+
 }
 
 package android.service.carrier {
@@ -38239,10 +38454,10 @@
     method public int indexOfChild(android.view.View);
     method public final void invalidateChild(android.view.View, android.graphics.Rect);
     method public android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
-    method public boolean isAlwaysDrawnWithCacheEnabled();
-    method public boolean isAnimationCacheEnabled();
+    method public deprecated boolean isAlwaysDrawnWithCacheEnabled();
+    method public deprecated boolean isAnimationCacheEnabled();
     method protected boolean isChildrenDrawingOrderEnabled();
-    method protected boolean isChildrenDrawnWithCacheEnabled();
+    method protected deprecated boolean isChildrenDrawnWithCacheEnabled();
     method public boolean isMotionEventSplittingEnabled();
     method public boolean isTransitionGroup();
     method public final void layout(int, int, int, int);
@@ -38281,11 +38496,11 @@
     method public void requestTransparentRegion(android.view.View);
     method public void scheduleLayoutAnimation();
     method public void setAddStatesFromChildren(boolean);
-    method public void setAlwaysDrawnWithCacheEnabled(boolean);
-    method public void setAnimationCacheEnabled(boolean);
+    method public deprecated void setAlwaysDrawnWithCacheEnabled(boolean);
+    method public deprecated void setAnimationCacheEnabled(boolean);
     method protected void setChildrenDrawingCacheEnabled(boolean);
     method protected void setChildrenDrawingOrderEnabled(boolean);
-    method protected void setChildrenDrawnWithCacheEnabled(boolean);
+    method protected deprecated void setChildrenDrawnWithCacheEnabled(boolean);
     method public void setClipChildren(boolean);
     method public void setClipToPadding(boolean);
     method public void setDescendantFocusability(int);
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index df5a4cb..224e8e9 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -698,7 +698,7 @@
                 int ordering = a.getInt(R.styleable.AnimatorSet_ordering, TOGETHER);
                 createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering,
                         pixelSize);
-                final int hint = a.getInt(R.styleable.Animator_durationScaleHint,
+                final int hint = a.getInt(R.styleable.AnimatorSet_durationScaleHint,
                         HINT_NO_SCALE);
                 anim.setDurationScaleHint(hint, res);
                 a.recycle();
diff --git a/core/java/android/app/IUserSwitchObserver.aidl b/core/java/android/app/IUserSwitchObserver.aidl
index 845897b..caee14f 100644
--- a/core/java/android/app/IUserSwitchObserver.aidl
+++ b/core/java/android/app/IUserSwitchObserver.aidl
@@ -22,4 +22,5 @@
 oneway interface IUserSwitchObserver {
     void onUserSwitching(int newUserId, IRemoteCallback reply);
     void onUserSwitchComplete(int newUserId);
+    void onForegroundProfileSwitch(int newProfileId);
 }
diff --git a/core/java/android/app/admin/DeviceInitializerStatus.java b/core/java/android/app/admin/DeviceInitializerStatus.java
new file mode 100644
index 0000000..b58711c
--- /dev/null
+++ b/core/java/android/app/admin/DeviceInitializerStatus.java
@@ -0,0 +1,177 @@
+/*
+ * 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_CONNECT_BLUETOOTH_PROXY}
+ * <li>{@link #STATUS_STATE_DISCONNECT_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_CONNECT_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_DISCONNECT_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;
+
+    /**
+     * Determine if the specified status code represents an error status.
+     * @param statusCode status code to check
+     * @return {@code true} if the status code is an error status code
+     */
+    public static boolean isErrorStatus(int statusCode) {
+        return isFlagSet(statusCode, FLAG_STATUS_ERROR);
+    }
+
+    /**
+     * Determine if the specified status code is a custom status. Custom status codes are defined
+     * and sent by device initialization agents.
+     * @param statusCode status code to check
+     * @return {@code true} if the status code is a custom status code
+     */
+    public static boolean isCustomStatus(int statusCode) {
+        return isFlagSet(statusCode, FLAG_STATUS_CUSTOM);
+    }
+
+    /**
+     * Determine if the specified status code is a high priority status code.
+     * @param statusCode status code to check
+     * @return {@code true} if the status code is a high priority status code
+     */
+    public static boolean isHighPriority(int statusCode) {
+        return isFlagSet(statusCode, FLAG_STATUS_HIGH_PRIORITY);
+    }
+
+    private static boolean isFlagSet(int statusCode, int flag) {
+        return (statusCode & flag) != 0;
+    }
+
+    private DeviceInitializerStatus() {}
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 68f4707..88b1f2d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -651,6 +651,45 @@
             = "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#isCustomStatus(int) 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#isCustomStatus(int)}.
+     * @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.
      */
@@ -2170,7 +2209,8 @@
      * Called by a device or profile owner to install a certificate and private key pair. The
      * keypair will be visible to all apps within the profile.
      *
-     * @param who Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param who Which {@link DeviceAdminReceiver} this request is associated with. Use
+     * <code>null</code> if calling from a delegated certificate installer.
      * @param privKey The private key to install.
      * @param cert The certificate to install.
      * @param alias The private key alias under which to install the certificate. If a certificate
@@ -2207,9 +2247,9 @@
 
     /**
      * Called by a profile owner or device owner to grant access to privileged certificate
-     * manipulation APIs to a third-party CA certificate installer app. Granted APIs include
+     * manipulation APIs to a third-party certificate installer app. Granted APIs include
      * {@link #getInstalledCaCerts}, {@link #hasCaCertInstalled}, {@link #installCaCert},
-     * {@link #uninstallCaCert} and {@link #uninstallAllUserCaCerts}.
+     * {@link #uninstallCaCert}, {@link #uninstallAllUserCaCerts} and {@link #installKeyPair}.
      * <p>
      * Delegated certificate installer is a per-user state. The delegated access is persistent until
      * it is later cleared by calling this method with a null value or uninstallling the certificate
@@ -4012,4 +4052,19 @@
             Log.w(TAG, "Could not set the user icon ", re);
         }
     }
+
+    /**
+     * 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#isCustomStatus(int)}.
+     * @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);
+        }
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index c68311e..75b97a8 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -213,4 +213,6 @@
     ComponentName getDeviceInitializerComponent();
 
     void setUserIcon(in ComponentName admin, in Bitmap icon);
+
+    void sendDeviceInitializerStatus(int statusCode, String description);
 }
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 1131ff9..9540eb1 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -399,6 +399,13 @@
      * operation will be skipped (and {@link #finishBackup() invoked} with no data for that
      * package being passed to {@link #sendBackupData}.
      *
+     * <p class="note">The platform does no size-based rejection of full backup attempts on
+     * its own: it is always the responsibility of the transport to implement its own policy.
+     * In particular, even if the preflighted payload size is zero, the platform will still call
+     * this method and will proceed to back up an archive metadata header with no file content
+     * if this method returns TRANSPORT_OK.  To avoid storing such payloads the transport
+     * must recognize this case and return TRANSPORT_PACKAGE_REJECTED.
+     *
      * Added in MNC (API 23).
      *
      * @param size The estimated size of the full-data payload for this app.  This includes
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index f01c540..8f7aed4 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -639,7 +639,8 @@
 
     /**
      * <p>Whether the camera device supports {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock}</p>
-     * <p>LIMITED or FULL devices will always list <code>true</code></p>
+     * <p>Devices with MANUAL_SENSOR capability or BURST_CAPTURE capability will always
+     * list <code>true</code>. This includes FULL devices.</p>
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_AE_LOCK
@@ -650,7 +651,8 @@
 
     /**
      * <p>Whether the camera device supports {@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock}</p>
-     * <p>LIMITED or FULL devices will always list <code>true</code></p>
+     * <p>Devices with MANUAL_POST_PROCESSING capability or BURST_CAPTURE capability will
+     * always list <code>true</code>. This includes FULL devices.</p>
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_AWB_LOCK
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 2192ab7..4a5bd08 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -347,6 +347,10 @@
      * <li>{@link CaptureRequest#BLACK_LEVEL_LOCK android.blackLevel.lock}</li>
      * </ul>
      * </li>
+     * <li>Auto exposure lock<ul>
+     * <li>{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock}</li>
+     * </ul>
+     * </li>
      * </ul>
      * <p>If any of the above 3A algorithms are enabled, then the camera
      * device will accurately report the values applied by 3A in the
@@ -358,6 +362,7 @@
      * zero for each supported size-format combination.</p>
      *
      * @see CaptureRequest#BLACK_LEVEL_LOCK
+     * @see CaptureRequest#CONTROL_AE_LOCK
      * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      * @see CaptureRequest#SENSOR_FRAME_DURATION
@@ -403,6 +408,10 @@
      * <li>{@link CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES android.colorCorrection.availableAberrationModes}</li>
      * </ul>
      * </li>
+     * <li>Auto white balance lock<ul>
+     * <li>{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock}</li>
+     * </ul>
+     * </li>
      * </ul>
      * <p>If auto white balance is enabled, then the camera device
      * will accurately report the values applied by AWB in the result.</p>
@@ -413,6 +422,7 @@
      * @see CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES
      * @see CaptureRequest#COLOR_CORRECTION_GAINS
      * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
+     * @see CaptureRequest#CONTROL_AWB_LOCK
      * @see CaptureRequest#SHADING_MODE
      * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
      * @see CaptureRequest#TONEMAP_CURVE
@@ -530,9 +540,15 @@
      * YUV_420_888 format.</p>
      * </blockquote>
      * <p>In addition, the {@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} field is
-     * guaranted to have a value between 0 and 4, inclusive.</p>
+     * guaranted to have a value between 0 and 4, inclusive.
+     * {@link CameraCharacteristics#CONTROL_AE_LOCK_AVAILABLE android.control.aeLockAvailable} and
+     * {@link CameraCharacteristics#CONTROL_AWB_LOCK_AVAILABLE android.control.awbLockAvailable} are also guaranteed
+     * to be <code>true</code> so burst capture with these two locks ON
+     * yields consistent image output.</p>
      *
      * @see CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES
+     * @see CameraCharacteristics#CONTROL_AE_LOCK_AVAILABLE
+     * @see CameraCharacteristics#CONTROL_AWB_LOCK_AVAILABLE
      * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
      * @see CameraCharacteristics#SYNC_MAX_LATENCY
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
diff --git a/core/java/android/os/IHardwareService.aidl b/core/java/android/os/IHardwareService.aidl
deleted file mode 100644
index 38abfc00..0000000
--- a/core/java/android/os/IHardwareService.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Copyright (c) 2007, 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.os;
-
-/** {@hide} */
-interface IHardwareService
-{
-    // obsolete flashlight support
-    boolean getFlashlightEnabled();
-    void setFlashlightEnabled(boolean on);
-}
-
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 4712f97..879f26c 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -19,7 +19,6 @@
 import android.Manifest;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -258,7 +257,6 @@
          *
          * @hide
          */
-        @SystemApi
         public static Uri insert(Context context, Voicemail voicemail) {
             ContentResolver contentResolver = context.getContentResolver();
             ContentValues contentValues = getContentValues(voicemail);
@@ -274,7 +272,6 @@
          *
          * @hide
          */
-        @SystemApi
         public static int insert(Context context, List<Voicemail> voicemails) {
             ContentResolver contentResolver = context.getContentResolver();
             int count = voicemails.size();
@@ -293,7 +290,6 @@
          *
          * @hide
          */
-        @SystemApi
         public static int deleteAll(Context context) {
             return context.getContentResolver().delete(
                     buildSourceUri(context.getPackageName()), "", new String[0]);
@@ -452,7 +448,6 @@
          *
          * @hide
          */
-        @SystemApi
         public static void setStatus(Context context, PhoneAccountHandle accountHandle,
                 int configurationState, int dataChannelState, int notificationChannelState) {
             ContentResolver contentResolver = context.getContentResolver();
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java
index 0f1d422..b3a3aad 100644
--- a/core/java/android/security/keymaster/KeyCharacteristics.java
+++ b/core/java/android/security/keymaster/KeyCharacteristics.java
@@ -19,6 +19,10 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
 /**
  * @hide
  */
@@ -28,10 +32,12 @@
 
     public static final Parcelable.Creator<KeyCharacteristics> CREATOR = new
             Parcelable.Creator<KeyCharacteristics>() {
+                @Override
                 public KeyCharacteristics createFromParcel(Parcel in) {
                     return new KeyCharacteristics(in);
                 }
 
+                @Override
                 public KeyCharacteristics[] newArray(int length) {
                     return new KeyCharacteristics[length];
                 }
@@ -48,6 +54,7 @@
         return 0;
     }
 
+    @Override
     public void writeToParcel(Parcel out, int flags) {
         swEnforced.writeToParcel(out, flags);
         hwEnforced.writeToParcel(out, flags);
@@ -57,5 +64,53 @@
         swEnforced = KeymasterArguments.CREATOR.createFromParcel(in);
         hwEnforced = KeymasterArguments.CREATOR.createFromParcel(in);
     }
+
+    public Integer getInteger(int tag) {
+        if (hwEnforced.containsTag(tag)) {
+            return hwEnforced.getInt(tag, -1);
+        } else if (swEnforced.containsTag(tag)) {
+            return swEnforced.getInt(tag, -1);
+        } else {
+            return null;
+        }
+    }
+
+    public int getInt(int tag, int defaultValue) {
+        Integer result = getInteger(tag);
+        return (result != null) ? result : defaultValue;
+    }
+
+    public List<Integer> getInts(int tag) {
+        List<Integer> result = new ArrayList<Integer>();
+        result.addAll(hwEnforced.getInts(tag));
+        result.addAll(swEnforced.getInts(tag));
+        return result;
+    }
+
+    public Date getDate(int tag) {
+        Date result = hwEnforced.getDate(tag, null);
+        if (result == null) {
+            result = swEnforced.getDate(tag, null);
+        }
+        return result;
+    }
+
+    public Date getDate(int tag, Date defaultValue) {
+        if (hwEnforced.containsTag(tag)) {
+            return hwEnforced.getDate(tag, null);
+        } else if (hwEnforced.containsTag(tag)) {
+            return swEnforced.getDate(tag, null);
+        } else {
+            return defaultValue;
+        }
+    }
+
+    public boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) {
+        if (keyCharacteristics.hwEnforced.containsTag(tag)) {
+            return keyCharacteristics.hwEnforced.getBoolean(tag, false);
+        } else {
+            return keyCharacteristics.swEnforced.getBoolean(tag, false);
+        }
+    }
 }
 
diff --git a/core/java/android/security/keymaster/KeymasterArguments.java b/core/java/android/security/keymaster/KeymasterArguments.java
index b5fd4bd..8ed288c 100644
--- a/core/java/android/security/keymaster/KeymasterArguments.java
+++ b/core/java/android/security/keymaster/KeymasterArguments.java
@@ -34,9 +34,12 @@
 
     public static final Parcelable.Creator<KeymasterArguments> CREATOR = new
             Parcelable.Creator<KeymasterArguments>() {
+                @Override
                 public KeymasterArguments createFromParcel(Parcel in) {
                     return new KeymasterArguments(in);
                 }
+
+                @Override
                 public KeymasterArguments[] newArray(int size) {
                     return new KeymasterArguments[size];
                 }
@@ -54,6 +57,12 @@
         mArguments.add(new KeymasterIntArgument(tag, value));
     }
 
+    public void addInts(int tag, int... values) {
+        for (int value : values) {
+            addInt(tag, value);
+        }
+    }
+
     public void addBoolean(int tag) {
         mArguments.add(new KeymasterBooleanArgument(tag));
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 60d2ceb..3fa8c81 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15087,7 +15087,7 @@
      * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common
      * case of an active Animation being run on the view.
      */
-    private boolean drawAnimation(ViewGroup parent, long drawingTime,
+    private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime,
             Animation a, boolean scalingRequired) {
         Transformation invalidationTransform;
         final int flags = parent.mGroupFlags;
@@ -15204,23 +15204,13 @@
         Transformation transformToApply = null;
         boolean concatMatrix = false;
 
-        boolean scalingRequired = false;
-        boolean caching;
+        boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired;
         int layerType = getLayerType();
-
         final boolean hardwareAccelerated = canvas.isHardwareAccelerated();
-        if ((flags & ViewGroup.FLAG_CHILDREN_DRAWN_WITH_CACHE) != 0 ||
-                (flags & ViewGroup.FLAG_ALWAYS_DRAWN_WITH_CACHE) != 0) {
-            caching = true;
-            // Auto-scaled apps are not hw-accelerated, no need to set scaling flag on DisplayList
-            if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
-        } else {
-            caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated;
-        }
 
         final Animation a = getAnimation();
         if (a != null) {
-            more = drawAnimation(parent, drawingTime, a, scalingRequired);
+            more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired);
             concatMatrix = a.willChangeTransformationMatrix();
             if (concatMatrix) {
                 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
@@ -15270,34 +15260,32 @@
         RenderNode renderNode = null;
         Bitmap cache = null;
         boolean hasDisplayList = false;
-        if (caching) {
-            if (!hardwareAccelerated) {
-                if (layerType != LAYER_TYPE_NONE) {
-                    layerType = LAYER_TYPE_SOFTWARE;
-                    buildDrawingCache(true);
-                }
-                cache = getDrawingCache(true);
-            } else {
-                switch (layerType) {
-                    case LAYER_TYPE_SOFTWARE:
-                        if (usingRenderNodeProperties) {
-                            hasDisplayList = canHaveDisplayList();
-                        } else {
-                            buildDrawingCache(true);
-                            cache = getDrawingCache(true);
-                        }
-                        break;
-                    case LAYER_TYPE_HARDWARE:
-                        if (usingRenderNodeProperties) {
-                            hasDisplayList = canHaveDisplayList();
-                        }
-                        break;
-                    case LAYER_TYPE_NONE:
-                        // Delay getting the display list until animation-driven alpha values are
-                        // set up and possibly passed on to the view
+        if (!hardwareAccelerated) {
+            if (layerType != LAYER_TYPE_NONE) {
+                layerType = LAYER_TYPE_SOFTWARE;
+                buildDrawingCache(true);
+            }
+            cache = getDrawingCache(true);
+        } else {
+            switch (layerType) {
+                case LAYER_TYPE_SOFTWARE:
+                    if (usingRenderNodeProperties) {
                         hasDisplayList = canHaveDisplayList();
-                        break;
-                }
+                    } else {
+                        buildDrawingCache(true);
+                        cache = getDrawingCache(true);
+                    }
+                    break;
+                case LAYER_TYPE_HARDWARE:
+                    if (usingRenderNodeProperties) {
+                        hasDisplayList = canHaveDisplayList();
+                    }
+                    break;
+                case LAYER_TYPE_NONE:
+                    // Delay getting the display list until animation-driven alpha values are
+                    // set up and possibly passed on to the view
+                    hasDisplayList = canHaveDisplayList();
+                    break;
             }
         }
         usingRenderNodeProperties &= hasDisplayList;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 8d06ce2..98b895d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -245,8 +245,7 @@
     // to clip it, even if FLAG_CLIP_TO_PADDING is set
     private static final int FLAG_PADDING_NOT_NULL = 0x20;
 
-    // When set, this ViewGroup caches its children in a Bitmap before starting a layout animation
-    // Set by default
+    /** @deprecated - functionality removed */
     private static final int FLAG_ANIMATION_CACHE = 0x40;
 
     // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
@@ -292,16 +291,11 @@
      */
     private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
 
-    /**
-     * When set, this ViewGroup tries to always draw its children using their drawing cache.
-     */
-    static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
+    /** @deprecated functionality removed */
+    private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
 
-    /**
-     * When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to
-     * draw its children with their drawing cache.
-     */
-    static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
+    /** @deprecated functionality removed */
+    private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
 
     /**
      * When set, this group will go through its list of children to notify them of
@@ -584,8 +578,6 @@
         mGroupFlags |= FLAG_CLIP_CHILDREN;
         mGroupFlags |= FLAG_CLIP_TO_PADDING;
         mGroupFlags |= FLAG_ANIMATION_DONE;
-        mGroupFlags |= FLAG_ANIMATION_CACHE;
-        mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
 
         if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
             mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
@@ -3088,44 +3080,6 @@
     }
 
     @Override
-    protected void onAnimationStart() {
-        super.onAnimationStart();
-
-        // When this ViewGroup's animation starts, build the cache for the children
-        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
-            final int count = mChildrenCount;
-            final View[] children = mChildren;
-            final boolean buildCache = !isHardwareAccelerated();
-
-            for (int i = 0; i < count; i++) {
-                final View child = children[i];
-                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
-                    child.setDrawingCacheEnabled(true);
-                    if (buildCache) {
-                        child.buildDrawingCache(true);
-                    }
-                }
-            }
-
-            mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
-        }
-    }
-
-    @Override
-    protected void onAnimationEnd() {
-        super.onAnimationEnd();
-
-        // When this ViewGroup's animation ends, destroy the cache of the children
-        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
-            mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
-
-            if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
-                setChildrenDrawingCacheEnabled(false);
-            }
-        }
-    }
-
-    @Override
     Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
         int count = mChildrenCount;
         int[] visibilities = null;
@@ -3295,8 +3249,6 @@
         int flags = mGroupFlags;
 
         if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
-            final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
-
             final boolean buildCache = !isHardwareAccelerated();
             for (int i = 0; i < childrenCount; i++) {
                 final View child = children[i];
@@ -3304,12 +3256,6 @@
                     final LayoutParams params = child.getLayoutParams();
                     attachLayoutAnimationParameters(child, params, i, childrenCount);
                     bindLayoutAnimation(child);
-                    if (cache) {
-                        child.setDrawingCacheEnabled(true);
-                        if (buildCache) {
-                            child.buildDrawingCache(true);
-                        }
-                    }
                 }
             }
 
@@ -3323,10 +3269,6 @@
             mGroupFlags &= ~FLAG_RUN_ANIMATION;
             mGroupFlags &= ~FLAG_ANIMATION_DONE;
 
-            if (cache) {
-                mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
-            }
-
             if (mAnimationListener != null) {
                 mAnimationListener.onAnimationStart(controller.getAnimation());
             }
@@ -3504,13 +3446,6 @@
            post(end);
         }
 
-        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
-            mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
-            if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
-                setChildrenDrawingCacheEnabled(false);
-            }
-        }
-
         invalidate(true);
     }
 
@@ -5278,8 +5213,10 @@
      *
      * @see #setAnimationCacheEnabled(boolean)
      * @see View#setDrawingCacheEnabled(boolean)
+     *
+     * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
+     * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
      */
-    @ViewDebug.ExportedProperty
     public boolean isAnimationCacheEnabled() {
         return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
     }
@@ -5294,6 +5231,9 @@
      *
      * @see #isAnimationCacheEnabled()
      * @see View#setDrawingCacheEnabled(boolean)
+     *
+     * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
+     * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
      */
     public void setAnimationCacheEnabled(boolean enabled) {
         setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
@@ -5308,8 +5248,10 @@
      * @see #setAlwaysDrawnWithCacheEnabled(boolean)
      * @see #setChildrenDrawnWithCacheEnabled(boolean)
      * @see View#setDrawingCacheEnabled(boolean)
+     *
+     * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
+     * Child views may no longer have their caching behavior disabled by parents.
      */
-    @ViewDebug.ExportedProperty(category = "drawing")
     public boolean isAlwaysDrawnWithCacheEnabled() {
         return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
     }
@@ -5330,6 +5272,9 @@
      * @see #setChildrenDrawnWithCacheEnabled(boolean)
      * @see View#setDrawingCacheEnabled(boolean)
      * @see View#setDrawingCacheQuality(int)
+     *
+     * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
+     * Child views may no longer have their caching behavior disabled by parents.
      */
     public void setAlwaysDrawnWithCacheEnabled(boolean always) {
         setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
@@ -5343,8 +5288,11 @@
      *
      * @see #setAlwaysDrawnWithCacheEnabled(boolean)
      * @see #setChildrenDrawnWithCacheEnabled(boolean)
+     *
+     * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
+     * Child views may no longer be forced to cache their rendering state by their parents.
+     * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
      */
-    @ViewDebug.ExportedProperty(category = "drawing")
     protected boolean isChildrenDrawnWithCacheEnabled() {
         return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
     }
@@ -5361,6 +5309,10 @@
      *
      * @see #setAlwaysDrawnWithCacheEnabled(boolean)
      * @see #isChildrenDrawnWithCacheEnabled()
+     *
+     * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
+     * Child views may no longer be forced to cache their rendering state by their parents.
+     * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
      */
     protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
         setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index a157087..06a5bd2 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -534,22 +534,23 @@
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
-        SavedState ss = (SavedState) state;
+        final SavedState ss = (SavedState) state;
 
         // TODO: Move instance state into DayPickerView, YearPickerView.
         mCurrentDate.set(ss.getSelectedYear(), ss.getSelectedMonth(), ss.getSelectedDay());
-        mCurrentView = ss.getCurrentView();
         mMinDate.setTimeInMillis(ss.getMinDate());
         mMaxDate.setTimeInMillis(ss.getMaxDate());
 
         onCurrentDateChanged(false);
-        setCurrentView(mCurrentView);
+
+        final int currentView = ss.getCurrentView();
+        setCurrentView(currentView);
 
         final int listPosition = ss.getListPosition();
         if (listPosition != -1) {
-            if (mCurrentView == VIEW_MONTH_DAY) {
+            if (currentView == VIEW_MONTH_DAY) {
                 mDayPickerView.setCurrentItem(listPosition);
-            } else if (mCurrentView == VIEW_YEAR) {
+            } else if (currentView == VIEW_YEAR) {
                 final int listPositionOffset = ss.getListPositionOffset();
                 mYearPickerView.setSelectionFromTop(listPosition, listPositionOffset);
             }
@@ -601,7 +602,6 @@
      * Class for managing state storing/restoring.
      */
     private static class SavedState extends View.BaseSavedState {
-
         private final int mSelectedYear;
         private final int mSelectedMonth;
         private final int mSelectedDay;
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index ec2528f..0e0b2d3 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -22,9 +22,12 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.MathUtils;
+import android.view.View;
 
+import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Locale;
 
@@ -41,6 +44,8 @@
     private final Calendar mMinDate = Calendar.getInstance();
     private final Calendar mMaxDate = Calendar.getInstance();
 
+    private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
+
     private final DayPickerAdapter mAdapter;
 
     /** Temporary calendar used for date calculations. */
@@ -140,6 +145,93 @@
         });
     }
 
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        populate();
+
+        // Everything below is mostly copied from FrameLayout.
+        int count = getChildCount();
+
+        final boolean measureMatchParentChildren =
+                MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
+                        MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
+
+        int maxHeight = 0;
+        int maxWidth = 0;
+        int childState = 0;
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                measureChild(child, widthMeasureSpec, heightMeasureSpec);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
+                maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
+                childState = combineMeasuredStates(childState, child.getMeasuredState());
+                if (measureMatchParentChildren) {
+                    if (lp.width == LayoutParams.MATCH_PARENT ||
+                            lp.height == LayoutParams.MATCH_PARENT) {
+                        mMatchParentChildren.add(child);
+                    }
+                }
+            }
+        }
+
+        // Account for padding too
+        maxWidth += getPaddingLeft() + getPaddingRight();
+        maxHeight += getPaddingTop() + getPaddingBottom();
+
+        // Check against our minimum height and width
+        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
+        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
+
+        // Check against our foreground's minimum height and width
+        final Drawable drawable = getForeground();
+        if (drawable != null) {
+            maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
+            maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
+        }
+
+        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+                resolveSizeAndState(maxHeight, heightMeasureSpec,
+                        childState << MEASURED_HEIGHT_STATE_SHIFT));
+
+        count = mMatchParentChildren.size();
+        if (count > 1) {
+            for (int i = 0; i < count; i++) {
+                final View child = mMatchParentChildren.get(i);
+
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                final int childWidthMeasureSpec;
+                final int childHeightMeasureSpec;
+
+                if (lp.width == LayoutParams.MATCH_PARENT) {
+                    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                            getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
+                            MeasureSpec.EXACTLY);
+                } else {
+                    childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
+                            getPaddingLeft() + getPaddingRight(),
+                            lp.width);
+                }
+
+                if (lp.height == LayoutParams.MATCH_PARENT) {
+                    childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                            getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
+                            MeasureSpec.EXACTLY);
+                } else {
+                    childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
+                            getPaddingTop() + getPaddingBottom(),
+                            lp.height);
+                }
+
+                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+            }
+        }
+
+        mMatchParentChildren.clear();
+    }
+
     public void setDayOfWeekTextAppearance(int resId) {
         mAdapter.setDayOfWeekTextAppearance(resId);
     }
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index d9f1f0e..aa7f0b6 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -585,7 +585,6 @@
                 mToday = day;
             }
         }
-        mNumWeeks = calculateNumRows();
 
         // Invalidate the old title.
         mTitle = null;
@@ -616,18 +615,6 @@
         }
     }
 
-    public void reuse() {
-        mNumWeeks = MAX_WEEKS_IN_MONTH;
-        requestLayout();
-    }
-
-    private int calculateNumRows() {
-        final int offset = findDayOffset();
-        final int dividend = (offset + mDaysInMonth) / DAYS_IN_WEEK;
-        final int remainder = (offset + mDaysInMonth) % DAYS_IN_WEEK;
-        return dividend + (remainder > 0 ? 1 : 0);
-    }
-
     private boolean sameDay(int day, Calendar today) {
         return mYear == today.get(Calendar.YEAR) && mMonth == today.get(Calendar.MONTH)
                 && day == today.get(Calendar.DAY_OF_MONTH);
@@ -635,8 +622,9 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int preferredHeight = mDesiredDayHeight * mNumWeeks + mDesiredDayOfWeekHeight
-                + mDesiredMonthHeight + getPaddingTop() + getPaddingBottom();
+        final int preferredHeight = mDesiredDayHeight * MAX_WEEKS_IN_MONTH
+                + mDesiredDayOfWeekHeight + mDesiredMonthHeight
+                + getPaddingTop() + getPaddingBottom();
         final int preferredWidth = mDesiredCellWidth * DAYS_IN_WEEK
                 + getPaddingStart() + getPaddingEnd();
         final int resolvedWidth = resolveSize(preferredWidth, widthMeasureSpec);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5d60f99..9bbf375 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -540,6 +540,7 @@
     private Layout mLayout;
     private boolean mLocaleChanged = false;
 
+    @ViewDebug.ExportedProperty(category = "text")
     private int mGravity = Gravity.TOP | Gravity.START;
     private boolean mHorizontallyScrolling;
 
diff --git a/core/java/android/widget/YearPickerView.java b/core/java/android/widget/YearPickerView.java
index 7182414..89e59f9 100644
--- a/core/java/android/widget/YearPickerView.java
+++ b/core/java/android/widget/YearPickerView.java
@@ -178,24 +178,29 @@
 
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
-            if (convertView == null) {
-                convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
+            final TextView v;
+            final boolean hasNewView = convertView == null;
+            if (hasNewView) {
+                v = (TextView) mInflater.inflate(ITEM_LAYOUT, parent, false);
+            } else {
+                v = (TextView) convertView;
             }
 
             final int year = getYearForPosition(position);
             final boolean activated = mActivatedYear == year;
 
-            final int textAppearanceResId;
-            if (activated && ITEM_TEXT_ACTIVATED_APPEARANCE != 0) {
-                textAppearanceResId = ITEM_TEXT_ACTIVATED_APPEARANCE;
-            } else {
-                textAppearanceResId = ITEM_TEXT_APPEARANCE;
+            if (hasNewView || v.isActivated() != activated) {
+                final int textAppearanceResId;
+                if (activated && ITEM_TEXT_ACTIVATED_APPEARANCE != 0) {
+                    textAppearanceResId = ITEM_TEXT_ACTIVATED_APPEARANCE;
+                } else {
+                    textAppearanceResId = ITEM_TEXT_APPEARANCE;
+                }
+                v.setTextAppearance(textAppearanceResId);
+                v.setActivated(activated);
             }
 
-            final TextView v = (TextView) convertView;
-            v.setText("" + year);
-            v.setTextAppearance(v.getContext(), textAppearanceResId);
-            v.setActivated(activated);
+            v.setText(Integer.toString(year));
             return v;
         }
 
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 9dabb4e..b8110e3 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -170,9 +170,8 @@
     }
 
     private static boolean shouldCenterSingleButton(Context context) {
-        TypedValue outValue = new TypedValue();
-        context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogCenterButtons,
-                outValue, true);
+        final TypedValue outValue = new TypedValue();
+        context.getTheme().resolveAttribute(R.attr.alertDialogCenterButtons, outValue, true);
         return outValue.data != 0;
     }
 
@@ -182,27 +181,25 @@
         mWindow = window;
         mHandler = new ButtonHandler(di);
 
-        TypedArray a = context.obtainStyledAttributes(null,
-                com.android.internal.R.styleable.AlertDialog,
-                com.android.internal.R.attr.alertDialogStyle, 0);
+        final TypedArray a = context.obtainStyledAttributes(null,
+                R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
 
-        mAlertDialogLayout = a.getResourceId(com.android.internal.R.styleable.AlertDialog_layout,
-                com.android.internal.R.layout.alert_dialog);
+        mAlertDialogLayout = a.getResourceId(
+                R.styleable.AlertDialog_layout, R.layout.alert_dialog);
         mButtonPanelSideLayout = a.getResourceId(
-                com.android.internal.R.styleable.AlertDialog_buttonPanelSideLayout, 0);
-
+                R.styleable.AlertDialog_buttonPanelSideLayout, 0);
         mListLayout = a.getResourceId(
-                com.android.internal.R.styleable.AlertDialog_listLayout,
-                com.android.internal.R.layout.select_dialog);
+                R.styleable.AlertDialog_listLayout, R.layout.select_dialog);
+
         mMultiChoiceItemLayout = a.getResourceId(
-                com.android.internal.R.styleable.AlertDialog_multiChoiceItemLayout,
-                com.android.internal.R.layout.select_dialog_multichoice);
+                R.styleable.AlertDialog_multiChoiceItemLayout,
+                R.layout.select_dialog_multichoice);
         mSingleChoiceItemLayout = a.getResourceId(
-                com.android.internal.R.styleable.AlertDialog_singleChoiceItemLayout,
-                com.android.internal.R.layout.select_dialog_singlechoice);
+                R.styleable.AlertDialog_singleChoiceItemLayout,
+                R.layout.select_dialog_singlechoice);
         mListItemLayout = a.getResourceId(
-                com.android.internal.R.styleable.AlertDialog_listItemLayout,
-                com.android.internal.R.layout.select_dialog_item);
+                R.styleable.AlertDialog_listItemLayout,
+                R.layout.select_dialog_item);
 
         a.recycle();
     }
@@ -1067,9 +1064,9 @@
         }
 
         private void createListView(final AlertController dialog) {
-            final RecycleListView listView = (RecycleListView)
-                    mInflater.inflate(dialog.mListLayout, null);
-            ListAdapter adapter;
+            final RecycleListView listView =
+                    (RecycleListView) mInflater.inflate(dialog.mListLayout, null);
+            final ListAdapter adapter;
 
             if (mIsMultiChoice) {
                 if (mCursor == null) {
@@ -1115,14 +1112,20 @@
                     };
                 }
             } else {
-                int layout = mIsSingleChoice
-                        ? dialog.mSingleChoiceItemLayout : dialog.mListItemLayout;
-                if (mCursor == null) {
-                    adapter = (mAdapter != null) ? mAdapter
-                            : new CheckedItemAdapter(mContext, layout, R.id.text1, mItems);
+                final int layout;
+                if (mIsSingleChoice) {
+                    layout = dialog.mSingleChoiceItemLayout;
                 } else {
-                    adapter = new SimpleCursorAdapter(mContext, layout,
-                            mCursor, new String[]{mLabelColumn}, new int[]{R.id.text1});
+                    layout = dialog.mListItemLayout;
+                }
+
+                if (mCursor != null) {
+                    adapter = new SimpleCursorAdapter(mContext, layout, mCursor,
+                            new String[] { mLabelColumn }, new int[] { R.id.text1 });
+                } else if (mAdapter != null) {
+                    adapter = mAdapter;
+                } else {
+                    adapter = new CheckedItemAdapter(mContext, layout, R.id.text1, mItems);
                 }
             }
 
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index e32a3a2..22d35f2 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -45,8 +45,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashSet;
-import static android.system.OsConstants.*;
+import static android.system.OsConstants.SEEK_CUR;
 
 /**
  * Backup transport for stashing stuff into a known location on disk, and
@@ -284,8 +283,10 @@
     private int tearDownFullBackup() {
         if (mSocket != null) {
             try {
-                mFullBackupOutputStream.flush();
-                mFullBackupOutputStream.close();
+                if (mFullBackupOutputStream != null) {
+                    mFullBackupOutputStream.flush();
+                    mFullBackupOutputStream.close();
+                }
                 mSocketInputStream = null;
                 mFullTargetPackage = null;
                 mSocket.close();
@@ -296,6 +297,7 @@
                 return TRANSPORT_ERROR;
             } finally {
                 mSocket = null;
+                mFullBackupOutputStream = null;
             }
         }
         return TRANSPORT_OK;
@@ -311,6 +313,18 @@
     }
 
     @Override
+    public int checkFullBackupSize(long size) {
+        // Decline zero-size "backups"
+        final int result = (size > 0) ? TRANSPORT_OK : TRANSPORT_PACKAGE_REJECTED;
+        if (result != TRANSPORT_OK) {
+            if (DEBUG) {
+                Log.v(TAG, "Declining backup of size " + size);
+            }
+        }
+        return result;
+    }
+
+    @Override
     public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) {
         if (mSocket != null) {
             Log.e(TAG, "Attempt to initiate full backup while one is in progress");
@@ -333,22 +347,14 @@
         }
 
         mFullTargetPackage = targetPackage.packageName;
-        FileOutputStream tarstream;
-        try {
-            File tarball = tarballFile(mFullTargetPackage);
-            tarstream = new FileOutputStream(tarball);
-        } catch (FileNotFoundException e) {
-            return TRANSPORT_ERROR;
-        }
-        mFullBackupOutputStream = new BufferedOutputStream(tarstream);
         mFullBackupBuffer = new byte[4096];
 
         return TRANSPORT_OK;
     }
 
     @Override
-    public int sendBackupData(int numBytes) {
-        if (mFullBackupBuffer == null) {
+    public int sendBackupData(final int numBytes) {
+        if (mSocket == null) {
             Log.w(TAG, "Attempted sendBackupData before performFullBackup");
             return TRANSPORT_ERROR;
         }
@@ -356,16 +362,29 @@
         if (numBytes > mFullBackupBuffer.length) {
             mFullBackupBuffer = new byte[numBytes];
         }
-        while (numBytes > 0) {
+
+        if (mFullBackupOutputStream == null) {
+            FileOutputStream tarstream;
             try {
-            int nRead = mSocketInputStream.read(mFullBackupBuffer, 0, numBytes);
+                File tarball = tarballFile(mFullTargetPackage);
+                tarstream = new FileOutputStream(tarball);
+            } catch (FileNotFoundException e) {
+                return TRANSPORT_ERROR;
+            }
+            mFullBackupOutputStream = new BufferedOutputStream(tarstream);
+        }
+
+        int bytesLeft = numBytes;
+        while (bytesLeft > 0) {
+            try {
+            int nRead = mSocketInputStream.read(mFullBackupBuffer, 0, bytesLeft);
             if (nRead < 0) {
                 // Something went wrong if we expect data but saw EOD
                 Log.w(TAG, "Unexpected EOD; failing backup");
                 return TRANSPORT_ERROR;
             }
             mFullBackupOutputStream.write(mFullBackupBuffer, 0, nRead);
-            numBytes -= nRead;
+            bytesLeft -= nRead;
             } catch (IOException e) {
                 Log.e(TAG, "Error handling backup data for " + mFullTargetPackage);
                 return TRANSPORT_ERROR;
diff --git a/core/java/com/android/internal/widget/DialogViewAnimator.java b/core/java/com/android/internal/widget/DialogViewAnimator.java
new file mode 100644
index 0000000..bdfc1af
--- /dev/null
+++ b/core/java/com/android/internal/widget/DialogViewAnimator.java
@@ -0,0 +1,141 @@
+/*
+ * 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 com.android.internal.widget;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ViewAnimator;
+
+import java.util.ArrayList;
+
+/**
+ * ViewAnimator with a more reasonable handling of MATCH_PARENT.
+ */
+public class DialogViewAnimator extends ViewAnimator {
+    private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
+
+    public DialogViewAnimator(Context context) {
+        super(context);
+    }
+
+    public DialogViewAnimator(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final boolean measureMatchParentChildren =
+                MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
+                        MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
+
+        int maxHeight = 0;
+        int maxWidth = 0;
+        int childState = 0;
+
+        // First measure all children and record maximum dimensions where the
+        // spec isn't MATCH_PARENT.
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (getMeasureAllChildren() || child.getVisibility() != GONE) {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                final boolean matchWidth = lp.width == LayoutParams.MATCH_PARENT;
+                final boolean matchHeight = lp.height == LayoutParams.MATCH_PARENT;
+                if (measureMatchParentChildren && (matchWidth || matchHeight)) {
+                    mMatchParentChildren.add(child);
+                }
+
+                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+
+                // Measured dimensions only count against the maximum
+                // dimensions if they're not MATCH_PARENT.
+                int state = 0;
+
+                if (measureMatchParentChildren && !matchWidth) {
+                    maxWidth = Math.max(maxWidth, child.getMeasuredWidth()
+                            + lp.leftMargin + lp.rightMargin);
+                    state |= child.getMeasuredWidthAndState() & MEASURED_STATE_MASK;
+                }
+
+                if (measureMatchParentChildren && !matchHeight) {
+                    maxHeight = Math.max(maxHeight, child.getMeasuredHeight()
+                            + lp.topMargin + lp.bottomMargin);
+                    state |= (child.getMeasuredHeightAndState() >> MEASURED_HEIGHT_STATE_SHIFT)
+                            & (MEASURED_STATE_MASK >> MEASURED_HEIGHT_STATE_SHIFT);
+                }
+
+                childState = combineMeasuredStates(childState, state);
+            }
+        }
+
+        // Account for padding too.
+        maxWidth += getPaddingLeft() + getPaddingRight();
+        maxHeight += getPaddingTop() + getPaddingBottom();
+
+        // Check against our minimum height and width.
+        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
+        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
+
+        // Check against our foreground's minimum height and width.
+        final Drawable drawable = getForeground();
+        if (drawable != null) {
+            maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
+            maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
+        }
+
+        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+                resolveSizeAndState(maxHeight, heightMeasureSpec,
+                        childState << MEASURED_HEIGHT_STATE_SHIFT));
+
+        // Measure remaining MATCH_PARENT children again using real dimensions.
+        final int matchCount = mMatchParentChildren.size();
+        for (int i = 0; i < matchCount; i++) {
+            final View child = mMatchParentChildren.get(i);
+            final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+
+            final int childWidthMeasureSpec;
+            if (lp.width == LayoutParams.MATCH_PARENT) {
+                childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                        getMeasuredWidth() - getPaddingLeft() - getPaddingRight()
+                                - lp.leftMargin - lp.rightMargin,
+                        MeasureSpec.EXACTLY);
+            } else {
+                childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
+                        getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin,
+                        lp.width);
+            }
+
+            final int childHeightMeasureSpec;
+            if (lp.height == LayoutParams.MATCH_PARENT) {
+                childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                        getMeasuredHeight() - getPaddingTop() - getPaddingBottom()
+                                - lp.topMargin - lp.bottomMargin,
+                        MeasureSpec.EXACTLY);
+            } else {
+                childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
+                        getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin,
+                        lp.height);
+            }
+
+            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+        }
+
+        mMatchParentChildren.clear();
+    }
+}
diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java
index 8d66191..5c08daf 100644
--- a/core/java/com/android/internal/widget/ViewPager.java
+++ b/core/java/com/android/internal/widget/ViewPager.java
@@ -889,7 +889,7 @@
         }
     }
 
-    void populate() {
+    public void populate() {
         populate(mCurItem);
     }
 
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 4c4a39d..d4069a1 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -261,7 +261,7 @@
     SkBitmap* outputBitmap = NULL;
     unsigned int existingBufferSize = 0;
     if (javaBitmap != NULL) {
-        outputBitmap = GraphicsJNI::getSkBitmap(env, javaBitmap);
+        outputBitmap = GraphicsJNI::getSkBitmapDeprecated(env, javaBitmap);
         if (outputBitmap->isImmutable()) {
             ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
             javaBitmap = NULL;
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 3525d07..aeea808 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -217,7 +217,7 @@
 
     if (tileBitmap != NULL) {
         // Re-use bitmap.
-        bitmap = GraphicsJNI::getSkBitmap(env, tileBitmap);
+        bitmap = GraphicsJNI::getSkBitmapDeprecated(env, tileBitmap);
     }
     if (bitmap == NULL) {
         bitmap = new SkBitmap;
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 0747969..f0bd5dd 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -338,7 +338,7 @@
     return static_cast<SkColorType>(gConfig2ColorType[legacyConfig]);
 }
 
-SkBitmap* GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap) {
+SkBitmap* GraphicsJNI::getSkBitmapDeprecated(JNIEnv* env, jobject bitmap) {
     SkASSERT(env);
     SkASSERT(bitmap);
     SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
@@ -348,6 +348,21 @@
     return b;
 }
 
+void GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap, SkBitmap* outBitmap) {
+    SkPixelRef* pixelRef = getSkPixelRef(env, bitmap);
+    // TODO: pixelRef->rowBytes() is only valid if the pixels are locked
+    // (which is currently always true on android), switch this to querying
+    // from the wrapper once that exists instead
+    outBitmap->setInfo(pixelRef->info(), pixelRef->rowBytes());
+    outBitmap->setPixelRef(pixelRef);
+}
+
+SkPixelRef* GraphicsJNI::getSkPixelRef(JNIEnv* env, jobject bitmap) {
+    jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_skBitmapPtr);
+    SkBitmap* b = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    return b->pixelRef();
+}
+
 SkColorType GraphicsJNI::getNativeBitmapColorType(JNIEnv* env, jobject jconfig) {
     SkASSERT(env);
     if (NULL == jconfig) {
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 422d3f1..49def13 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -48,7 +48,9 @@
     static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf);
 
     static SkCanvas* getNativeCanvas(JNIEnv*, jobject canvas);
-    static SkBitmap* getSkBitmap(JNIEnv*, jobject bitmap);
+    static SkBitmap* getSkBitmapDeprecated(JNIEnv*, jobject bitmap);
+    static void getSkBitmap(JNIEnv*, jobject bitmap, SkBitmap* outBitmap);
+    static SkPixelRef* getSkPixelRef(JNIEnv*, jobject bitmap);
     static SkRegion* getNativeRegion(JNIEnv*, jobject region);
 
     // Given the 'native' long held by the Rasterizer.java object, return a
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index fc98cf9..876bea4 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -243,19 +243,21 @@
 }
 
 static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong pagePtr,
-        jlong bitmapPtr, jint destLeft, jint destTop, jint destRight, jint destBottom,
+        jobject jbitmap, jint destLeft, jint destTop, jint destRight, jint destBottom,
         jlong matrixPtr, jint renderMode) {
 
     FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
-    SkBitmap* skBitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
     SkMatrix* skMatrix = reinterpret_cast<SkMatrix*>(matrixPtr);
 
-    skBitmap->lockPixels();
+    SkBitmap skBitmap;
+    GraphicsJNI::getSkBitmap(env, jbitmap, &skBitmap);
 
-    const int stride = skBitmap->width() * 4;
+    SkAutoLockPixels alp(skBitmap);
 
-    FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap->width(), skBitmap->height(),
-            FPDFBitmap_BGRA, skBitmap->getPixels(), stride);
+    const int stride = skBitmap.width() * 4;
+
+    FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap.width(), skBitmap.height(),
+            FPDFBitmap_BGRA, skBitmap.getPixels(), stride);
 
     if (!bitmap) {
         ALOGE("Erorr creating bitmap");
@@ -278,8 +280,7 @@
     renderPageBitmap(bitmap, page, destLeft, destTop, destRight,
             destBottom, skMatrix, renderFlags);
 
-    skBitmap->notifyPixelsChanged();
-    skBitmap->unlockPixels();
+    skBitmap.notifyPixelsChanged();
 }
 
 static JNINativeMethod gPdfRenderer_Methods[] = {
@@ -287,7 +288,7 @@
     {"nativeClose", "(J)V", (void*) nativeClose},
     {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
     {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
-    {"nativeRenderPage", "(JJJIIIIJI)V", (void*) nativeRenderPage},
+    {"nativeRenderPage", "(JJLandroid/graphics/Bitmap;IIIIJI)V", (void*) nativeRenderPage},
     {"nativeOpenPageAndGetSize", "(JILandroid/graphics/Point;)J", (void*) nativeOpenPageAndGetSize},
     {"nativeClosePage", "(J)V", (void*) nativeClosePage}
 };
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 5c2d0d0..bce2b33 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -618,23 +618,25 @@
 static jint util_getInternalFormat(JNIEnv *env, jclass clazz,
         jobject jbitmap)
 {
-    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
-    return getInternalFormat(nativeBitmap->colorType());
+    SkBitmap nativeBitmap;
+    GraphicsJNI::getSkBitmap(env, jbitmap, &nativeBitmap);
+    return getInternalFormat(nativeBitmap.colorType());
 }
 
 static jint util_getType(JNIEnv *env, jclass clazz,
         jobject jbitmap)
 {
-    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
-    return getType(nativeBitmap->colorType());
+    SkBitmap nativeBitmap;
+    GraphicsJNI::getSkBitmap(env, jbitmap, &nativeBitmap);
+    return getType(nativeBitmap.colorType());
 }
 
 static jint util_texImage2D(JNIEnv *env, jclass clazz,
         jint target, jint level, jint internalformat,
         jobject jbitmap, jint type, jint border)
 {
-    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
-    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     SkColorType colorType = bitmap.colorType();
     if (internalformat < 0) {
         internalformat = getInternalFormat(colorType);
@@ -680,8 +682,8 @@
         jint target, jint level, jint xoffset, jint yoffset,
         jobject jbitmap, jint format, jint type)
 {
-    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
-    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     SkColorType colorType = bitmap.colorType();
     if (format < 0) {
         format = getInternalFormat(colorType);
diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp
index f6d9a1a..d04adbf 100644
--- a/core/jni/android_view_PointerIcon.cpp
+++ b/core/jni/android_view_PointerIcon.cpp
@@ -80,10 +80,7 @@
 
     jobject bitmapObj = env->GetObjectField(loadedPointerIconObj, gPointerIconClassInfo.mBitmap);
     if (bitmapObj) {
-        SkBitmap* bitmap = GraphicsJNI::getSkBitmap(env, bitmapObj);
-        if (bitmap) {
-            outPointerIcon->bitmap = *bitmap; // use a shared pixel ref
-        }
+        GraphicsJNI::getSkBitmap(env, bitmapObj, &(outPointerIcon->bitmap));
         env->DeleteLocalRef(bitmapObj);
     }
 
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 7080e2a..baeb7dd 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -277,8 +277,9 @@
     EGLConfig  cnf = getConfig(_env, config);
     jint* base = 0;
 
-    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(_env, native_pixmap);
-    SkPixelRef* ref = nativeBitmap ? nativeBitmap->pixelRef() : 0;
+    SkBitmap nativeBitmap;
+    GraphicsJNI::getSkBitmap(_env, native_pixmap, &nativeBitmap);
+    SkPixelRef* ref = nativeBitmap.pixelRef();
     if (ref == NULL) {
         jniThrowException(_env, "java/lang/IllegalArgumentException", "Bitmap has no PixelRef");
         return;
@@ -289,10 +290,10 @@
 
     egl_native_pixmap_t pixmap;
     pixmap.version = sizeof(pixmap);
-    pixmap.width  = nativeBitmap->width();
-    pixmap.height = nativeBitmap->height();
-    pixmap.stride = nativeBitmap->rowBytes() / nativeBitmap->bytesPerPixel();
-    pixmap.format = convertPixelFormat(nativeBitmap->colorType());
+    pixmap.width  = nativeBitmap.width();
+    pixmap.height = nativeBitmap.height();
+    pixmap.stride = nativeBitmap.rowBytes() / nativeBitmap.bytesPerPixel();
+    pixmap.format = convertPixelFormat(nativeBitmap.colorType());
     pixmap.data   = (uint8_t*)ref->pixels();
 
     base = beginNativeAttribList(_env, attrib_list);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7c5d194..4a1be2d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -87,6 +87,7 @@
     <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" />
@@ -2374,6 +2375,12 @@
     <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:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+                android:protectionLevel="signature" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/res/res/anim/date_picker_fade_in_material.xml b/core/res/res/anim/date_picker_fade_in_material.xml
new file mode 100644
index 0000000..12e7ce3
--- /dev/null
+++ b/core/res/res/anim/date_picker_fade_in_material.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+       android:interpolator="@interpolator/accelerate_quad"
+       android:fromAlpha="0.0"
+       android:toAlpha="1.0"
+       android:duration="250"  />
diff --git a/core/res/res/anim/date_picker_fade_out_material.xml b/core/res/res/anim/date_picker_fade_out_material.xml
new file mode 100644
index 0000000..4084605
--- /dev/null
+++ b/core/res/res/anim/date_picker_fade_out_material.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+       android:interpolator="@interpolator/decelerate_quad"
+       android:fromAlpha="1.0"
+       android:toAlpha="0.0"
+       android:duration="250" />
diff --git a/core/res/res/layout/date_picker_material.xml b/core/res/res/layout/date_picker_material.xml
index a1c97ff..763f2a4 100644
--- a/core/res/res/layout/date_picker_material.xml
+++ b/core/res/res/layout/date_picker_material.xml
@@ -16,8 +16,8 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
               android:orientation="vertical">
 
     <include
diff --git a/core/res/res/layout/date_picker_view_animator_material.xml b/core/res/res/layout/date_picker_view_animator_material.xml
index 620ddfa..e863b28 100644
--- a/core/res/res/layout/date_picker_view_animator_material.xml
+++ b/core/res/res/layout/date_picker_view_animator_material.xml
@@ -15,23 +15,23 @@
      limitations under the License.
 -->
 
-<ViewAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.DialogViewAnimator xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/animator"
     android:layout_width="match_parent"
-    android:layout_height="0dp"
-    android:layout_weight="1"
-    android:gravity="center">
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:inAnimation="@anim/date_picker_fade_in_material"
+    android:outAnimation="@anim/date_picker_fade_out_material"
+    android:measureAllChildren="true">
 
     <android.widget.DayPickerView
         android:id="@+id/date_picker_day_picker"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:inAnimation="@anim/fade_in"
-        android:outAnimation="@anim/fade_out" />
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
 
     <android.widget.YearPickerView
         android:id="@+id/date_picker_year_picker"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
 
-</ViewAnimator>
+</com.android.internal.widget.DialogViewAnimator>
diff --git a/core/res/res/layout/select_dialog_multichoice_material.xml b/core/res/res/layout/select_dialog_multichoice_material.xml
index 9cfbbb3..e21df73 100644
--- a/core/res/res/layout/select_dialog_multichoice_material.xml
+++ b/core/res/res/layout/select_dialog_multichoice_material.xml
@@ -16,15 +16,15 @@
 -->
 
 <CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@android:id/text1"
+    android:id="@id/text1"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeightSmall"
-    android:textAppearance="?android:attr/textAppearanceMedium"
-    android:textColor="?android:attr/textColorAlertDialogListItem"
+    android:minHeight="?attr/listPreferredItemHeightSmall"
+    android:textAppearance="?attr/textAppearanceMedium"
+    android:textColor="?attr/textColorAlertDialogListItem"
     android:gravity="center_vertical"
-    android:paddingStart="?attr/dialogPreferredPadding"
+    android:paddingStart="@dimen/select_dialog_padding_start_material"
     android:paddingEnd="?attr/dialogPreferredPadding"
-    android:checkMark="?android:attr/listChoiceIndicatorMultiple"
+    android:checkMark="?attr/listChoiceIndicatorMultiple"
     android:checkMarkGravity="start"
     android:ellipsize="marquee" />
diff --git a/core/res/res/layout/select_dialog_singlechoice_material.xml b/core/res/res/layout/select_dialog_singlechoice_material.xml
index 4f8672f..3828317 100644
--- a/core/res/res/layout/select_dialog_singlechoice_material.xml
+++ b/core/res/res/layout/select_dialog_singlechoice_material.xml
@@ -16,15 +16,15 @@
 -->
 
 <CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@android:id/text1"
+    android:id="@id/text1"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeightSmall"
-    android:textAppearance="?android:attr/textAppearanceMedium"
-    android:textColor="?android:attr/textColorAlertDialogListItem"
+    android:minHeight="?attr/listPreferredItemHeightSmall"
+    android:textAppearance="?attr/textAppearanceMedium"
+    android:textColor="?attr/textColorAlertDialogListItem"
     android:gravity="center_vertical"
-    android:paddingStart="?attr/dialogPreferredPadding"
+    android:paddingStart="@dimen/select_dialog_padding_start_material"
     android:paddingEnd="?attr/dialogPreferredPadding"
-    android:checkMark="?android:attr/listChoiceIndicatorSingle"
+    android:checkMark="?attr/listChoiceIndicatorSingle"
     android:checkMarkGravity="start"
     android:ellipsize="marquee" />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index cbd74cd..0f50502 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -6042,6 +6042,7 @@
             <!-- child animations should be played sequentially, in the same order as the xml. -->
             <enum name="sequentially" value="1" />
         </attr>
+        <attr name="durationScaleHint" />
     </declare-styleable>
 
     <!-- ========================== -->
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 6fd39f6..937e92ad 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -112,6 +112,9 @@
     <dimen name="dialog_padding_material">24dp</dimen>
     <dimen name="dialog_padding_top_material">18dp</dimen>
 
+    <!-- Dialog padding minus control padding, used to fix alignment. -->
+    <dimen name="select_dialog_padding_start_material">20dp</dimen>
+
     <!-- Padding above and below selection dialog lists. -->
     <dimen name="dialog_list_padding_vertical_material">8dp</dimen>
 
diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd
index bbbda67..a4fc2d2 100644
--- a/docs/html/training/articles/keystore.jd
+++ b/docs/html/training/articles/keystore.jd
@@ -26,11 +26,10 @@
   </div>
 </div>
 
-<p>The Android Keystore system lets you store private keys
-  in a container to make it more difficult to extract from the
-  device. Once keys are in the keystore, they can be used for
-  cryptographic operations with the private key material remaining
-  non-exportable.</p>
+<p>The Android Keystore system lets you store cryptographic keys in a container
+  to make it more difficult to extract from the device. Once keys are in the
+  keystore, they can be used for cryptographic operations with the key material
+  remaining non-exportable.</p>
 
 <p>The Keystore system is used by the {@link
   android.security.KeyChain} API as well as the Android
@@ -59,7 +58,8 @@
 
 <p>
 To use this feature, you use the standard {@link java.security.KeyStore}
-and {@link java.security.KeyPairGenerator} classes along with the
+and {@link java.security.KeyPairGenerator} or
+{@link javax.crypto.KeyGenerator} classes along with the
 {@code AndroidKeyStore} provider introduced in Android 4.3 (API level 18).</p>
 
 <p>{@code AndroidKeyStore} is registered as a {@link
@@ -67,7 +67,9 @@
   java.security.KeyStore#getInstance(String) KeyStore.getInstance(type)}
   method and as a provider for use with the {@link
   java.security.KeyPairGenerator#getInstance(String, String)
-  KeyPairGenerator.getInstance(algorithm, provider)} method.</p>
+  KeyPairGenerator.getInstance(algorithm, provider)} and {@link
+  javax.crypto.KeyGenerator#getInstance(String, String)
+  KeyGenerator.getInstance(algorithm, provider)} methods.</p>
 
 <h3 id="GeneratingANewPrivateKey">Generating a New Private Key</h3>
 
@@ -81,6 +83,11 @@
 
 {@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java generate}
 
+<h3 id="GeneratingANewSecretKey">Generating a New Secret Key</h3>
+
+<p>To generate the key, use a {@link javax.crypto.KeyGenerator} with
+  {@link android.security.KeyGeneratorSpec}.
+
 <h3 id="WorkingWithKeyStoreEntries">Working with Keystore Entries</h3>
 
 <p>Using the {@code AndroidKeyStore} provider takes place through
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 05a81de..8468d9e 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -297,7 +297,7 @@
             }
 
             final Drawable d = layer.mDrawable;
-            if (d.canApplyTheme()) {
+            if (d != null && d.canApplyTheme()) {
                 d.applyTheme(t);
 
                 // Update cached mask of child changing configurations.
@@ -881,7 +881,10 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.draw(canvas);
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null) {
+                dr.draw(canvas);
+            }
         }
     }
 
@@ -946,13 +949,15 @@
      */
     @Override
     public void getOutline(@NonNull Outline outline) {
-        final LayerState state = mLayerState;
-        final ChildDrawable[] children = state.mChildren;
-        final int N = state.mNum;
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            children[i].mDrawable.getOutline(outline);
-            if (!outline.isEmpty()) {
-                return;
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null) {
+                dr.getOutline(outline);
+                if (!outline.isEmpty()) {
+                    return;
+                }
             }
         }
     }
@@ -962,7 +967,10 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.setHotspot(x, y);
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null) {
+                dr.setHotspot(x, y);
+            }
         }
     }
 
@@ -971,7 +979,10 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.setHotspotBounds(left, top, right, bottom);
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null) {
+                dr.setHotspotBounds(left, top, right, bottom);
+            }
         }
 
         if (mHotspotBounds == null) {
@@ -996,7 +1007,10 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.setVisible(visible, restart);
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null) {
+                dr.setVisible(visible, restart);
+            }
         }
 
         return changed;
@@ -1007,17 +1021,18 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.setDither(dither);
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null) {
+                dr.setDither(dither);
+            }
         }
     }
 
     @Override
     public boolean getDither() {
-        final ChildDrawable[] array = mLayerState.mChildren;
-        if (mLayerState.mNum > 0) {
-            // All layers should have the same dither set on them - just return
-            // the first one
-            return array[0].mDrawable.getDither();
+        final Drawable dr = getFirstNonNullDrawable();
+        if (dr != null) {
+            return dr.getDither();
         } else {
             return super.getDither();
         }
@@ -1028,17 +1043,18 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.setAlpha(alpha);
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null) {
+                dr.setAlpha(alpha);
+            }
         }
     }
 
     @Override
     public int getAlpha() {
-        final ChildDrawable[] array = mLayerState.mChildren;
-        if (mLayerState.mNum > 0) {
-            // All layers should have the same alpha set on them - just return
-            // the first one
-            return array[0].mDrawable.getAlpha();
+        final Drawable dr = getFirstNonNullDrawable();
+        if (dr != null) {
+            return dr.getAlpha();
         } else {
             return super.getAlpha();
         }
@@ -1049,7 +1065,10 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.setColorFilter(colorFilter);
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null) {
+                dr.setColorFilter(colorFilter);
+            }
         }
     }
 
@@ -1058,7 +1077,10 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.setTintList(tint);
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null) {
+                dr.setTintList(tint);
+            }
         }
     }
 
@@ -1067,10 +1089,25 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.setTintMode(tintMode);
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null) {
+                dr.setTintMode(tintMode);
+            }
         }
     }
 
+    private Drawable getFirstNonNullDrawable() {
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i = 0; i < N; i++) {
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null) {
+                return dr;
+            }
+        }
+        return null;
+    }
+
     /**
      * Sets the opacity of this drawable directly, instead of collecting the
      * states from the layers
@@ -1101,7 +1138,10 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.setAutoMirrored(mirrored);
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null) {
+                dr.setAutoMirrored(mirrored);
+            }
         }
     }
 
@@ -1122,9 +1162,9 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            final ChildDrawable r = array[i];
-            if (r.mDrawable.isStateful() && r.mDrawable.setState(state)) {
-                refreshChildPadding(i, r);
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null && dr.isStateful() && dr.setState(state)) {
+                refreshChildPadding(i, array[i]);
                 changed = true;
             }
         }
@@ -1143,9 +1183,9 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            final ChildDrawable r = array[i];
-            if (r.mDrawable.setLevel(level)) {
-                refreshChildPadding(i, r);
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null && dr.setLevel(level)) {
+                refreshChildPadding(i, array[i]);
                 changed = true;
             }
         }
@@ -1176,6 +1216,10 @@
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
             final Drawable d = r.mDrawable;
+            if (d == null) {
+                continue;
+            }
+
             final Rect container = mTmpContainer;
             container.set(d.getBounds());
 
@@ -1257,6 +1301,10 @@
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
+            if (r.mDrawable == null) {
+                continue;
+            }
+
             final int minWidth = r.mWidth < 0 ? r.mDrawable.getIntrinsicWidth() : r.mWidth;
             final int w = minWidth + r.mInsetL + r.mInsetR + padL + padR;
             if (w > width) {
@@ -1283,6 +1331,10 @@
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
+            if (r.mDrawable == null) {
+                continue;
+            }
+
             final int minHeight = r.mHeight < 0 ? r.mDrawable.getIntrinsicHeight() : r.mHeight;
             final int h = minHeight + r.mInsetT + r.mInsetB + padT + padB;
             if (h > height) {
@@ -1304,15 +1356,17 @@
      * @return true if the child's padding has changed
      */
     private boolean refreshChildPadding(int i, ChildDrawable r) {
-        final Rect rect = mTmpRect;
-        r.mDrawable.getPadding(rect);
-        if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i] ||
-                rect.right != mPaddingR[i] || rect.bottom != mPaddingB[i]) {
-            mPaddingL[i] = rect.left;
-            mPaddingT[i] = rect.top;
-            mPaddingR[i] = rect.right;
-            mPaddingB[i] = rect.bottom;
-            return true;
+        if (r.mDrawable != null) {
+            final Rect rect = mTmpRect;
+            r.mDrawable.getPadding(rect);
+            if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i] ||
+                    rect.right != mPaddingR[i] || rect.bottom != mPaddingB[i]) {
+                mPaddingL[i] = rect.left;
+                mPaddingT[i] = rect.top;
+                mPaddingR[i] = rect.right;
+                mPaddingB[i] = rect.bottom;
+                return true;
+            }
         }
         return false;
     }
@@ -1348,7 +1402,10 @@
             final ChildDrawable[] array = mLayerState.mChildren;
             final int N = mLayerState.mNum;
             for (int i = 0; i < N; i++) {
-                array[i].mDrawable.mutate();
+                final Drawable dr = array[i].mDrawable;
+                if (dr != null) {
+                    dr.mutate();
+                }
             }
             mMutated = true;
         }
@@ -1360,10 +1417,14 @@
      */
     public void clearMutated() {
         super.clearMutated();
+
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.clearMutated();
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null) {
+                dr.clearMutated();
+            }
         }
         mMutated = false;
     }
@@ -1371,11 +1432,16 @@
     @Override
     public boolean onLayoutDirectionChange(int layoutDirection) {
         boolean changed = false;
+
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            changed |= array[i].mDrawable.setLayoutDirection(layoutDirection);
+            final Drawable dr = array[i].mDrawable;
+            if (dr != null) {
+                changed |= dr.setLayoutDirection(layoutDirection);
+            }
         }
+
         updateLayerBounds(getBounds());
         return changed;
     }
@@ -1396,15 +1462,24 @@
         }
 
         ChildDrawable(ChildDrawable orig, LayerDrawable owner, Resources res) {
-            if (res != null) {
-                mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
+            final Drawable dr = orig.mDrawable;
+            final Drawable clone;
+            if (dr != null) {
+                final ConstantState cs = dr.getConstantState();
+                if (res != null) {
+                    clone = cs.newDrawable(res);
+                } else {
+                    clone = cs.newDrawable();
+                }
+                clone.setCallback(owner);
+                clone.setLayoutDirection(dr.getLayoutDirection());
+                clone.setBounds(dr.getBounds());
+                clone.setLevel(dr.getLevel());
             } else {
-                mDrawable = orig.mDrawable.getConstantState().newDrawable();
+                clone = null;
             }
-            mDrawable.setCallback(owner);
-            mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
-            mDrawable.setBounds(orig.mDrawable.getBounds());
-            mDrawable.setLevel(orig.mDrawable.getLevel());
+
+            mDrawable = clone;
             mThemeAttrs = orig.mThemeAttrs;
             mInsetL = orig.mInsetL;
             mInsetT = orig.mInsetT;
@@ -1417,6 +1492,11 @@
             mGravity = orig.mGravity;
             mId = orig.mId;
         }
+
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null
+                    || (mDrawable != null && mDrawable.canApplyTheme());
+        }
     }
 
     static class LayerState extends ConstantState {
@@ -1476,7 +1556,7 @@
             final int N = mNum;
             for (int i = 0; i < N; i++) {
                 final ChildDrawable layer = array[i];
-                if (layer.mThemeAttrs != null || layer.mDrawable.canApplyTheme()) {
+                if (layer.canApplyTheme()) {
                     return true;
                 }
             }
@@ -1507,9 +1587,29 @@
 
             final ChildDrawable[] array = mChildren;
             final int N = mNum;
-            int op = N > 0 ? array[0].mDrawable.getOpacity() : PixelFormat.TRANSPARENT;
-            for (int i = 1; i < N; i++) {
-                op = Drawable.resolveOpacity(op, array[i].mDrawable.getOpacity());
+
+            // Seek to the first non-null drawable.
+            int firstIndex = -1;
+            for (int i = 0; i < N; i++) {
+                if (array[i].mDrawable != null) {
+                    firstIndex = i;
+                    break;
+                }
+            }
+
+            int op;
+            if (firstIndex >= 0) {
+                op = array[firstIndex].mDrawable.getOpacity();
+            } else {
+                op = PixelFormat.TRANSPARENT;
+            }
+
+            // Merge all remaining non-null drawables.
+            for (int i = firstIndex + 1; i < N; i++) {
+                final Drawable dr = array[i].mDrawable;
+                if (dr != null) {
+                    op = Drawable.resolveOpacity(op, dr.getOpacity());
+                }
             }
 
             mOpacity = op;
@@ -1526,7 +1626,8 @@
             final int N = mNum;
             boolean isStateful = false;
             for (int i = 0; i < N; i++) {
-                if (array[i].mDrawable.isStateful()) {
+                final Drawable dr = array[i].mDrawable;
+                if (dr != null && dr.isStateful()) {
                     isStateful = true;
                     break;
                 }
@@ -1541,7 +1642,8 @@
             final ChildDrawable[] array = mChildren;
             final int N = mNum;
             for (int i = 0; i < N; i++) {
-                if (array[i].mDrawable.getConstantState() == null) {
+                final Drawable dr = array[i].mDrawable;
+                if (dr != null && dr.getConstantState() == null) {
                     return false;
                 }
             }
@@ -1561,9 +1663,12 @@
             final int N = mNum;
             int pixelCount = 0;
             for (int i = 0; i < N; i++) {
-                final ConstantState state = array[i].mDrawable.getConstantState();
-                if (state != null) {
-                    pixelCount += state.addAtlasableBitmaps(atlasList);
+                final Drawable dr = array[i].mDrawable;
+                if (dr != null) {
+                    final ConstantState state = dr.getConstantState();
+                    if (state != null) {
+                        pixelCount += state.addAtlasableBitmaps(atlasList);
+                    }
                 }
             }
             return pixelCount;
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index b32dcc6..feb8052 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -380,7 +380,7 @@
 
             final long transformPtr = (transform != null) ? transform.native_instance : 0;
 
-            nativeRenderPage(mNativeDocument, mNativePage, destination.getSkBitmap(), contentLeft,
+            nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft,
                     contentTop, contentRight, contentBottom, transformPtr, renderMode);
         }
 
@@ -425,7 +425,7 @@
     private static native void nativeClose(long documentPtr);
     private static native int nativeGetPageCount(long documentPtr);
     private static native boolean nativeScaleForPrinting(long documentPtr);
-    private static native void nativeRenderPage(long documentPtr, long pagePtr, long destPtr,
+    private static native void nativeRenderPage(long documentPtr, long pagePtr, Bitmap dest,
             int destLeft, int destTop, int destRight, int destBottom, long matrixPtr, int renderMode);
     private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex,
             Point outSize);
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index c5b6a68..b9317741 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -19,6 +19,8 @@
 import com.android.org.conscrypt.OpenSSLEngine;
 import com.android.org.conscrypt.OpenSSLKeyHolder;
 
+import libcore.util.EmptyArray;
+
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
@@ -46,6 +48,7 @@
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
@@ -112,13 +115,6 @@
             if (keymasterAlgorithm == -1) {
                 throw new UnrecoverableKeyException("Key algorithm unknown");
             }
-            @KeyStoreKeyConstraints.AlgorithmEnum int keyAlgorithm;
-            try {
-                keyAlgorithm = KeyStoreKeyConstraints.Algorithm.fromKeymaster(keymasterAlgorithm);
-            } catch (IllegalArgumentException e) {
-                throw (UnrecoverableKeyException)
-                        new UnrecoverableKeyException("Unsupported key algorithm").initCause(e);
-            }
 
             int keymasterDigest =
                     keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_DIGEST, -1);
@@ -126,20 +122,11 @@
                 keymasterDigest =
                         keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_DIGEST, -1);
             }
-            @KeyStoreKeyConstraints.DigestEnum Integer digest = null;
-            if (keymasterDigest != -1) {
-                try {
-                    digest = KeyStoreKeyConstraints.Digest.fromKeymaster(keymasterDigest);
-                } catch (IllegalArgumentException e) {
-                    throw (UnrecoverableKeyException)
-                            new UnrecoverableKeyException("Unsupported digest").initCause(e);
-                }
-            }
 
             String keyAlgorithmString;
             try {
-                keyAlgorithmString = KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(
-                    keyAlgorithm, digest);
+                keyAlgorithmString = KeymasterUtils.getJcaSecretKeyAlgorithm(
+                        keymasterAlgorithm, keymasterDigest);
             } catch (IllegalArgumentException e) {
                 throw (UnrecoverableKeyException)
                         new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
@@ -456,90 +443,92 @@
         }
 
         String keyAlgorithmString = key.getAlgorithm();
-        @KeyStoreKeyConstraints.AlgorithmEnum int keyAlgorithm;
-        @KeyStoreKeyConstraints.DigestEnum Integer digest;
+        int keymasterAlgorithm;
+        int keymasterDigest;
         try {
-            keyAlgorithm =
-                    KeyStoreKeyConstraints.Algorithm.fromJCASecretKeyAlgorithm(keyAlgorithmString);
-            digest = KeyStoreKeyConstraints.Digest.fromJCASecretKeyAlgorithm(keyAlgorithmString);
+            keymasterAlgorithm = KeymasterUtils.getKeymasterAlgorithmFromJcaSecretKeyAlgorithm(
+                    keyAlgorithmString);
+            keymasterDigest =
+                    KeymasterUtils.getKeymasterDigestfromJcaSecretKeyAlgorithm(keyAlgorithmString);
         } catch (IllegalArgumentException e) {
             throw new KeyStoreException("Unsupported secret key algorithm: " + keyAlgorithmString);
         }
 
         KeymasterArguments args = new KeymasterArguments();
-        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM,
-                KeyStoreKeyConstraints.Algorithm.toKeymaster(keyAlgorithm));
+        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm);
 
-        @KeyStoreKeyConstraints.DigestEnum int digests;
+        int[] keymasterDigests;
         if (params.isDigestsSpecified()) {
             // Digest(s) specified in parameters
-            if (digest != null) {
+            keymasterDigests =
+                    KeymasterUtils.getKeymasterDigestsFromJcaDigestAlgorithms(params.getDigests());
+            if (keymasterDigest != -1) {
                 // Digest also specified in the JCA key algorithm name.
-                if ((params.getDigests() & digest) != digest) {
+                if (!com.android.internal.util.ArrayUtils.contains(
+                        keymasterDigests, keymasterDigest)) {
                     throw new KeyStoreException("Key digest mismatch"
                             + ". Key: " + keyAlgorithmString
-                            + ", parameter spec: "
-                            + KeyStoreKeyConstraints.Digest.allToString(params.getDigests()));
+                            + ", parameter spec: " + Arrays.asList(params.getDigests()));
                 }
             }
-            digests = params.getDigests();
         } else {
             // No digest specified in parameters
-            if (digest != null) {
+            if (keymasterDigest != -1) {
                 // Digest specified in the JCA key algorithm name.
-                digests = digest;
+                keymasterDigests = new int[] {keymasterDigest};
             } else {
-                digests = 0;
+                keymasterDigests = EmptyArray.INT;
             }
         }
-        for (int keymasterDigest : KeyStoreKeyConstraints.Digest.allToKeymaster(digests)) {
-            args.addInt(KeymasterDefs.KM_TAG_DIGEST, keymasterDigest);
-        }
-        if (digests != 0) {
+        args.addInts(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
+        if (keymasterDigests.length > 0) {
             // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
             // This code will blow up if mode than one digest is specified.
-            Integer digestOutputSizeBytes =
-                    KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest);
-            if (digestOutputSizeBytes != null) {
+            int digestOutputSizeBytes =
+                    KeymasterUtils.getDigestOutputSizeBytes(keymasterDigests[0]);
+            if (digestOutputSizeBytes != -1) {
                 // TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
                 args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
             }
         }
-        if (keyAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
-            if (digests == 0) {
+        if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
+            if (keymasterDigests.length == 0) {
                 throw new KeyStoreException("At least one digest algorithm must be specified"
                         + " for key algorithm " + keyAlgorithmString);
             }
         }
 
-        @KeyStoreKeyConstraints.PurposeEnum int purposes = params.getPurposes();
-        @KeyStoreKeyConstraints.BlockModeEnum int blockModes = params.getBlockModes();
-        if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
+        @KeyStoreKeyProperties.PurposeEnum int purposes = params.getPurposes();
+        int[] keymasterBlockModes = KeymasterUtils.getKeymasterBlockModesFromJcaBlockModes(
+                params.getBlockModes());
+        if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
                 && (params.isRandomizedEncryptionRequired())) {
-            @KeyStoreKeyConstraints.BlockModeEnum int incompatibleBlockModes =
-                    blockModes & ~KeyStoreKeyConstraints.BlockMode.IND_CPA_COMPATIBLE_MODES;
-            if (incompatibleBlockModes != 0) {
-                throw new KeyStoreException("Randomized encryption (IND-CPA) required but may be"
-                        + " violated by block mode(s): "
-                        + KeyStoreKeyConstraints.BlockMode.allToString(incompatibleBlockModes)
-                        + ". See KeyStoreParameter documentation.");
+            for (int keymasterBlockMode : keymasterBlockModes) {
+                if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible(keymasterBlockMode)) {
+                    throw new KeyStoreException(
+                            "Randomized encryption (IND-CPA) required but may be violated by block"
+                            + " mode: "
+                            + KeymasterUtils.getJcaBlockModeFromKeymasterBlockMode(
+                                    keymasterBlockMode)
+                            + ". See KeyStoreParameter documentation.");
+                }
             }
         }
-        for (int keymasterPurpose : KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) {
+        for (int keymasterPurpose : KeyStoreKeyProperties.Purpose.allToKeymaster(purposes)) {
             args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose);
         }
-        for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(blockModes)) {
-            args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockMode);
-        }
-        for (int keymasterPadding :
-            KeyStoreKeyConstraints.Padding.allToKeymaster(params.getPaddings())) {
-            args.addInt(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
-        }
+        args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
+        int[] keymasterPaddings = ArrayUtils.concat(
+                KeymasterUtils.getKeymasterPaddingsFromJcaEncryptionPaddings(
+                        params.getEncryptionPaddings()),
+                KeymasterUtils.getKeymasterPaddingsFromJcaSignaturePaddings(
+                        params.getSignaturePaddings()));
+        args.addInts(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
         if (params.getUserAuthenticators() == 0) {
             args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
         } else {
             args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
-                    KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
+                    KeyStoreKeyProperties.UserAuthenticator.allToKeymaster(
                             params.getUserAuthenticators()));
         }
         if (params.isInvalidatedOnNewFingerprintEnrolled()) {
@@ -563,7 +552,7 @@
         // TODO: Remove this once keymaster does not require us to specify the size of imported key.
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keyMaterial.length * 8);
 
-        if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
+        if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
                 && (!params.isRandomizedEncryptionRequired())) {
             // Permit caller-provided IV when encrypting with this key
             args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
diff --git a/keystore/java/android/security/ArrayUtils.java b/keystore/java/android/security/ArrayUtils.java
new file mode 100644
index 0000000..2047d3f
--- /dev/null
+++ b/keystore/java/android/security/ArrayUtils.java
@@ -0,0 +1,62 @@
+package android.security;
+
+import libcore.util.EmptyArray;
+
+/**
+ * @hide
+ */
+abstract class ArrayUtils {
+    private ArrayUtils() {}
+
+    public static String[] nullToEmpty(String[] array) {
+        return (array != null) ? array : EmptyArray.STRING;
+    }
+
+    public static String[] cloneIfNotEmpty(String[] array) {
+        return ((array != null) && (array.length > 0)) ? array.clone() : array;
+    }
+
+    public static byte[] concat(byte[] arr1, byte[] arr2) {
+        return concat(arr1, 0, (arr1 != null) ? arr1.length : 0,
+                arr2, 0, (arr2 != null) ? arr2.length : 0);
+    }
+
+    public static byte[] concat(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2,
+            int len2) {
+        if (len1 == 0) {
+            return subarray(arr2, offset2, len2);
+        } else if (len2 == 0) {
+            return subarray(arr1, offset1, len1);
+        } else {
+            byte[] result = new byte[len1 + len2];
+            System.arraycopy(arr1, offset1, result, 0, len1);
+            System.arraycopy(arr2, offset2, result, len1, len2);
+            return result;
+        }
+    }
+
+    public static byte[] subarray(byte[] arr, int offset, int len) {
+        if (len == 0) {
+            return EmptyArray.BYTE;
+        }
+        if ((offset == 0) && (len == arr.length)) {
+            return arr;
+        }
+        byte[] result = new byte[len];
+        System.arraycopy(arr, offset, result, 0, len);
+        return result;
+    }
+
+    public static int[] concat(int[] arr1, int[] arr2) {
+        if ((arr1 == null) || (arr1.length == 0)) {
+            return arr2;
+        } else if ((arr2 == null) || (arr2.length == 0)) {
+            return arr1;
+        } else {
+            int[] result = new int[arr1.length + arr2.length];
+            System.arraycopy(arr1, 0, result, 0, arr1.length);
+            System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
+            return result;
+        }
+    }
+}
diff --git a/keystore/java/android/security/CryptoOperationException.java b/keystore/java/android/security/CryptoOperationException.java
index 00c142f..1c9d005 100644
--- a/keystore/java/android/security/CryptoOperationException.java
+++ b/keystore/java/android/security/CryptoOperationException.java
@@ -25,8 +25,6 @@
  * permitted to throw a checked exception during operation. Because crypto operations can fail
  * for a variety of reasons after initialization, this base class provides type-safety for unchecked
  * exceptions that may be thrown in those cases.
- *
- * @hide
  */
 public class CryptoOperationException extends RuntimeException {
 
diff --git a/keystore/java/android/security/EcIesParameterSpec.java b/keystore/java/android/security/EcIesParameterSpec.java
index 0f19812..3826679 100644
--- a/keystore/java/android/security/EcIesParameterSpec.java
+++ b/keystore/java/android/security/EcIesParameterSpec.java
@@ -46,8 +46,6 @@
  * MAC algorithm specified by {@link #getDemMacAlgorithm()} (e.g., {@code HmacSHA1} for standard
  * DEM1).</li>
  * </ul>
- *
- * @hide
  */
 public class EcIesParameterSpec implements AlgorithmParameterSpec {
 
@@ -124,6 +122,8 @@
 
     /**
      * Returns KEM EC curve name (e.g., {@code secp256r1}) or {@code null} if not specified.
+     *
+     * @hide
      */
     public String getKemCurveName() {
         return mKemCurveName;
@@ -200,6 +200,8 @@
          * Sets KEM EC curve name. For example, {@code P-256} or {@code secp256r1}.
          *
          * <p>NOTE: Only curves with cofactor of {@code 1} are supported.
+         *
+         * @hide
          */
         public Builder setKemCurveName(String name) {
             mKemCurveName = name;
diff --git a/keystore/java/android/security/KeyExpiredException.java b/keystore/java/android/security/KeyExpiredException.java
index 35a5acc..a02dc33 100644
--- a/keystore/java/android/security/KeyExpiredException.java
+++ b/keystore/java/android/security/KeyExpiredException.java
@@ -19,8 +19,6 @@
 /**
  * Indicates that a cryptographic operation failed because the employed key's validity end date
  * is in the past.
- *
- * @hide
  */
 public class KeyExpiredException extends CryptoOperationException {
 
diff --git a/keystore/java/android/security/KeyGeneratorSpec.java b/keystore/java/android/security/KeyGeneratorSpec.java
index 4eedb24..7ecc47e 100644
--- a/keystore/java/android/security/KeyGeneratorSpec.java
+++ b/keystore/java/android/security/KeyGeneratorSpec.java
@@ -37,23 +37,21 @@
  * <p>After generation, the {@code keyStoreAlias} is used with the
  * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)}
  * interface to retrieve the {@link SecretKey}.
- *
- * @hide
  */
 public class KeyGeneratorSpec implements AlgorithmParameterSpec {
 
     private final Context mContext;
     private final String mKeystoreAlias;
     private final int mFlags;
-    private final Integer mKeySize;
+    private final int mKeySize;
     private final Date mKeyValidityStart;
     private final Date mKeyValidityForOriginationEnd;
     private final Date mKeyValidityForConsumptionEnd;
-    private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
-    private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
-    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+    private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+    private final String[] mEncryptionPaddings;
+    private final String[] mBlockModes;
     private final boolean mRandomizedEncryptionRequired;
-    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
     private final int mUserAuthenticationValidityDurationSeconds;
     private final boolean mInvalidatedOnNewFingerprintEnrolled;
 
@@ -61,15 +59,15 @@
             Context context,
             String keyStoreAlias,
             int flags,
-            Integer keySize,
+            int keySize,
             Date keyValidityStart,
             Date keyValidityForOriginationEnd,
             Date keyValidityForConsumptionEnd,
-            @KeyStoreKeyConstraints.PurposeEnum int purposes,
-            @KeyStoreKeyConstraints.PaddingEnum int paddings,
-            @KeyStoreKeyConstraints.BlockModeEnum int blockModes,
+            @KeyStoreKeyProperties.PurposeEnum int purposes,
+            String[] encryptionPaddings,
+            String[] blockModes,
             boolean randomizedEncryptionRequired,
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
+            @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
             int userAuthenticationValidityDurationSeconds,
             boolean invalidatedOnNewFingerprintEnrolled) {
         if (context == null) {
@@ -90,8 +88,9 @@
         mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
         mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
         mPurposes = purposes;
-        mPaddings = paddings;
-        mBlockModes = blockModes;
+        mEncryptionPaddings =
+                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
+        mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
         mRandomizedEncryptionRequired = randomizedEncryptionRequired;
         mUserAuthenticators = userAuthenticators;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
@@ -121,9 +120,9 @@
     }
 
     /**
-     * Gets the requested key size or {@code null} if the default size should be used.
+     * Returns the requested key size or {@code -1} if default size should be used.
      */
-    public Integer getKeySize() {
+    public int getKeySize() {
         return mKeySize;
     }
 
@@ -157,22 +156,22 @@
     /**
      * Gets the set of purposes for which the key can be used.
      */
-    public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
+    public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
         return mPurposes;
     }
 
     /**
-     * Gets the set of padding schemes to which the key is restricted.
+     * Gets the set of padding schemes with which the key can be used when encrypting/decrypting.
      */
-    public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
-        return mPaddings;
+    public String[] getEncryptionPaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
     }
 
     /**
-     * Gets the set of block modes to which the key is restricted.
+     * Gets the set of block modes with which the key can be used.
      */
-    public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
-        return mBlockModes;
+    public String[] getBlockModes() {
+        return ArrayUtils.cloneIfNotEmpty(mBlockModes);
     }
 
     /**
@@ -194,7 +193,7 @@
      *
      * @return user authenticators or {@code 0} if the key can be used without user authentication.
      */
-    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
+    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
         return mUserAuthenticators;
     }
 
@@ -215,8 +214,6 @@
      * authenticators protecting access to this key.
      *
      * @see #getUserAuthenticators()
-     *
-     * @hide
      */
     public boolean isInvalidatedOnNewFingerprintEnrolled() {
         return mInvalidatedOnNewFingerprintEnrolled;
@@ -233,15 +230,15 @@
         private final Context mContext;
         private String mKeystoreAlias;
         private int mFlags;
-        private Integer mKeySize;
+        private int mKeySize = -1;
         private Date mKeyValidityStart;
         private Date mKeyValidityForOriginationEnd;
         private Date mKeyValidityForConsumptionEnd;
-        private @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
-        private @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
-        private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+        private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+        private String[] mEncryptionPaddings;
+        private String[] mBlockModes;
         private boolean mRandomizedEncryptionRequired = true;
-        private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+        private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
         private int mUserAuthenticationValidityDurationSeconds = -1;
         private boolean mInvalidatedOnNewFingerprintEnrolled;
 
@@ -349,34 +346,35 @@
         }
 
         /**
-         * Restricts the key to being used only for the provided set of purposes.
+         * Sets the set of purposes for which the key can be used.
          *
-         * <p>This restriction must be specified. There is no default.
+         * <p>This must be specified for all keys. There is no default.
          */
-        public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
+        public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
             mPurposes = purposes;
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided padding schemes. Attempts to use
-         * the key with any other padding will be rejected.
+         * Sets the set of padding schemes with which the key can be used when
+         * encrypting/decrypting. Attempts to use the key with any other padding scheme will be
+         * rejected.
          *
-         * <p>This restriction must be specified for keys which are used for encryption/decryption.
+         * <p>This must be specified for keys which are used for encryption/decryption.
          */
-        public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) {
-            mPaddings = paddings;
+        public Builder setEncryptionPaddings(String... paddings) {
+            mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided block modes. Attempts to use the
-         * key with any other block modes will be rejected.
+         * Sets the set of block modes with which the key can be used when encrypting/decrypting.
+         * Attempts to use the key with any other block modes will be rejected.
          *
-         * <p>This restriction must be specified for keys which are used for encryption/decryption.
+         * <p>This must be specified for encryption/decryption keys.
          */
-        public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) {
-            mBlockModes = blockModes;
+        public Builder setBlockModes(String... blockModes) {
+            mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
             return this;
         }
 
@@ -429,7 +427,7 @@
          * @see #setUserAuthenticationValidityDurationSeconds(int)
          */
         public Builder setUserAuthenticators(
-                @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
+                @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
             mUserAuthenticators = userAuthenticators;
             return this;
         }
@@ -458,8 +456,6 @@
          * <p>By default, enrolling a new fingerprint does not invalidate the key.
          *
          * @see #setUserAuthenticators(Set)
-         *
-         * @hide
          */
         public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
             mInvalidatedOnNewFingerprintEnrolled = invalidated;
@@ -480,7 +476,7 @@
                     mKeyValidityForOriginationEnd,
                     mKeyValidityForConsumptionEnd,
                     mPurposes,
-                    mPaddings,
+                    mEncryptionPaddings,
                     mBlockModes,
                     mRandomizedEncryptionRequired,
                     mUserAuthenticators,
diff --git a/keystore/java/android/security/KeyNotYetValidException.java b/keystore/java/android/security/KeyNotYetValidException.java
index f1c2cac..964cd7e 100644
--- a/keystore/java/android/security/KeyNotYetValidException.java
+++ b/keystore/java/android/security/KeyNotYetValidException.java
@@ -19,8 +19,6 @@
 /**
  * Indicates that a cryptographic operation failed because the employed key's validity start date
  * is in the future.
- *
- * @hide
  */
 public class KeyNotYetValidException extends CryptoOperationException {
 
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index 4ca220d..e297d26 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -78,17 +78,19 @@
 
     private final Date mKeyValidityForConsumptionEnd;
 
-    private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
+    private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
 
-    private final @KeyStoreKeyConstraints.DigestEnum int mDigests;
+    private final String[] mDigests;
 
-    private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
+    private final String[] mEncryptionPaddings;
 
-    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+    private final String[] mSignaturePaddings;
+
+    private final String[] mBlockModes;
 
     private final boolean mRandomizedEncryptionRequired;
 
-    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
 
     private final int mUserAuthenticationValidityDurationSeconds;
 
@@ -132,12 +134,13 @@
             Date keyValidityStart,
             Date keyValidityForOriginationEnd,
             Date keyValidityForConsumptionEnd,
-            @KeyStoreKeyConstraints.PurposeEnum int purposes,
-            @KeyStoreKeyConstraints.DigestEnum int digests,
-            @KeyStoreKeyConstraints.PaddingEnum int paddings,
-            @KeyStoreKeyConstraints.BlockModeEnum int blockModes,
+            @KeyStoreKeyProperties.PurposeEnum int purposes,
+            String[] digests,
+            String[] encryptionPaddings,
+            String[] signaturePaddings,
+            String[] blockModes,
             boolean randomizedEncryptionRequired,
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
+            @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
             int userAuthenticationValidityDurationSeconds,
             boolean invalidatedOnNewFingerprintEnrolled) {
         if (context == null) {
@@ -174,9 +177,11 @@
         mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
         mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
         mPurposes = purposes;
-        mDigests = digests;
-        mPaddings = paddings;
-        mBlockModes = blockModes;
+        mDigests = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(digests));
+        mEncryptionPaddings =
+                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
+        mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
+        mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
         mRandomizedEncryptionRequired = randomizedEncryptionRequired;
         mUserAuthenticators = userAuthenticators;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
@@ -204,14 +209,16 @@
                 startDate,
                 endDate,
                 endDate,
-                0,
-                0,
-                0,
-                0,
-                true,
-                0,
-                -1,
-                false);
+                0, // purposes
+                null, // digests
+                null, // encryption paddings
+                null, // signature paddings
+                null, // block modes
+                false, // randomized encryption required
+                0, // user authenticators
+                -1, // user authentication validity duration (seconds)
+                false // invalidate on new fingerprint enrolled
+                );
     }
 
     /**
@@ -304,8 +311,6 @@
      * Gets the time instant before which the key pair is not yet valid.
      *
      * @return instant or {@code null} if not restricted.
-     *
-     * @hide
      */
     public Date getKeyValidityStart() {
         return mKeyValidityStart;
@@ -316,8 +321,6 @@
      * verification.
      *
      * @return instant or {@code null} if not restricted.
-     *
-     * @hide
      */
     public Date getKeyValidityForConsumptionEnd() {
         return mKeyValidityForConsumptionEnd;
@@ -327,8 +330,6 @@
      * Gets the time instant after which the key pair is no longer valid for encryption and signing.
      *
      * @return instant or {@code null} if not restricted.
-     *
-     * @hide
      */
     public Date getKeyValidityForOriginationEnd() {
         return mKeyValidityForOriginationEnd;
@@ -336,38 +337,37 @@
 
     /**
      * Gets the set of purposes for which the key can be used.
-     *
-     * @hide
      */
-    public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
+    public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
         return mPurposes;
     }
 
     /**
-     * Gets the set of digests to which the key is restricted.
-     *
-     * @hide
+     * Gets the set of digest algorithms with which the key can be used.
      */
-    public @KeyStoreKeyConstraints.DigestEnum int getDigests() {
-        return mDigests;
+    public String[] getDigests() {
+        return ArrayUtils.cloneIfNotEmpty(mDigests);
     }
 
     /**
-     * Gets the set of padding schemes to which the key is restricted.
-     *
-     * @hide
+     * Gets the set of padding schemes with which the key can be used when encrypting/decrypting.
      */
-    public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
-        return mPaddings;
+    public String[] getEncryptionPaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
     }
 
     /**
-     * Gets the set of block modes to which the key is restricted.
-     *
-     * @hide
+     * Gets the set of padding schemes with which the key can be used when signing/verifying.
      */
-    public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
-        return mBlockModes;
+    public String[] getSignaturePaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
+    }
+
+    /**
+     * Gets the set of block modes with which the key can be used.
+     */
+    public String[] getBlockModes() {
+        return ArrayUtils.cloneIfNotEmpty(mBlockModes);
     }
 
     /**
@@ -378,8 +378,6 @@
      * weaknesses due to which ciphertext may leak information about plaintext.  For example, if a
      * given plaintext always produces the same ciphertext, an attacker may see the repeated
      * ciphertexts and be able to deduce something about the plaintext.
-     *
-     * @hide
      */
     public boolean isRandomizedEncryptionRequired() {
         return mRandomizedEncryptionRequired;
@@ -393,10 +391,8 @@
      * restricted.
      *
      * @return user authenticators or {@code 0} if the key can be used without user authentication.
-     *
-     * @hide
      */
-    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
+    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
         return mUserAuthenticators;
     }
 
@@ -409,8 +405,6 @@
      *
      * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
      *         is required for every use of the key.
-     *
-     * @hide
      */
     public int getUserAuthenticationValidityDurationSeconds() {
         return mUserAuthenticationValidityDurationSeconds;
@@ -422,8 +416,6 @@
      * authenticators protecting access to this key.
      *
      * @see #getUserAuthenticators()
-     *
-     * @hide
      */
     public boolean isInvalidatedOnNewFingerprintEnrolled() {
         return mInvalidatedOnNewFingerprintEnrolled;
@@ -477,17 +469,19 @@
 
         private Date mKeyValidityForConsumptionEnd;
 
-        private @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
+        private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
 
-        private @KeyStoreKeyConstraints.DigestEnum int mDigests;
+        private String[] mDigests;
 
-        private @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
+        private String[] mEncryptionPaddings;
 
-        private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+        private String[] mSignaturePaddings;
+
+        private String[] mBlockModes;
 
         private boolean mRandomizedEncryptionRequired = true;
 
-        private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+        private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
 
         private int mUserAuthenticationValidityDurationSeconds = -1;
 
@@ -624,8 +618,6 @@
          * <p>By default, the key is valid at any instant.
          *
          * @see #setKeyValidityEnd(Date)
-         *
-         * @hide
          */
         public Builder setKeyValidityStart(Date startDate) {
             mKeyValidityStart = startDate;
@@ -640,8 +632,6 @@
          * @see #setKeyValidityStart(Date)
          * @see #setKeyValidityForConsumptionEnd(Date)
          * @see #setKeyValidityForOriginationEnd(Date)
-         *
-         * @hide
          */
         public Builder setKeyValidityEnd(Date endDate) {
             setKeyValidityForOriginationEnd(endDate);
@@ -655,8 +645,6 @@
          * <p>By default, the key is valid at any instant.
          *
          * @see #setKeyValidityForConsumptionEnd(Date)
-         *
-         * @hide
          */
         public Builder setKeyValidityForOriginationEnd(Date endDate) {
             mKeyValidityForOriginationEnd = endDate;
@@ -670,8 +658,6 @@
          * <p>By default, the key is valid at any instant.
          *
          * @see #setKeyValidityForOriginationEnd(Date)
-         *
-         * @hide
          */
         public Builder setKeyValidityForConsumptionEnd(Date endDate) {
             mKeyValidityForConsumptionEnd = endDate;
@@ -679,53 +665,58 @@
         }
 
         /**
-         * Restricts the key to being used only for the provided set of purposes.
+         * Sets the set of purposes for which the key can be used.
          *
-         * <p>This restriction must be specified. There is no default.
-         *
-         * @hide
+         * <p>This must be specified for all keys. There is no default.
          */
-        public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
+        public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
             mPurposes = purposes;
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided digests. Attempts to use the key
-         * with any other digests be rejected.
+         * Sets the set of digests with which the key can be used when signing/verifying. Attempts
+         * to use the key with any other digest will be rejected.
          *
-         * <p>This restriction must be specified for keys which are used for signing/verification.
-         *
-         * @hide
+         * <p>This must be specified for keys which are used for signing/verification.
          */
-        public Builder setDigests(@KeyStoreKeyConstraints.DigestEnum int digests) {
-            mDigests = digests;
+        public Builder setDigests(String... digests) {
+            mDigests = ArrayUtils.cloneIfNotEmpty(digests);
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided padding schemes. Attempts to use
-         * the key with any other padding will be rejected.
+         * Sets the set of padding schemes with which the key can be used when
+         * encrypting/decrypting. Attempts to use the key with any other padding scheme will be
+         * rejected.
          *
-         * <p>This restriction must be specified for keys which are used for encryption/decryption.
-         *
-         * @hide
+         * <p>This must be specified for keys which are used for encryption/decryption.
          */
-        public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) {
-            mPaddings = paddings;
+        public Builder setEncryptionPaddings(String... paddings) {
+            mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided block mode when encrypting or
-         * decrypting. Attempts to use the key with any other block modes will be rejected.
+         * Sets the set of padding schemes with which the key can be used when
+         * signing/verifying. Attempts to use the key with any other padding scheme will be
+         * rejected.
          *
-         * <p>This restriction must be specified for keys which are used for encryption/decryption.
-         *
-         * @hide
+         * <p>This must be specified for RSA keys which are used for signing/verification.
          */
-        public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) {
-            mBlockModes = blockModes;
+        public Builder setSignaturePaddings(String... paddings) {
+            mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
+            return this;
+        }
+
+        /**
+         * Sets the set of block modes with which the key can be used when encrypting/decrypting.
+         * Attempts to use the key with any other block modes will be rejected.
+         *
+         * <p>This must be specified for encryption/decryption keys.
+         */
+        public Builder setBlockModes(String... blockModes) {
+            mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
             return this;
         }
 
@@ -748,8 +739,6 @@
          * <li>If you are using RSA encryption without padding, consider switching to padding
          * schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
          * </ul>
-         *
-         * @hide
          */
         public Builder setRandomizedEncryptionRequired(boolean required) {
             mRandomizedEncryptionRequired = required;
@@ -769,11 +758,9 @@
          *        without user authentication.
          *
          * @see #setUserAuthenticationValidityDurationSeconds(int)
-         *
-         * @hide
          */
         public Builder setUserAuthenticators(
-                @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
+                @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
             mUserAuthenticators = userAuthenticators;
             return this;
         }
@@ -791,8 +778,6 @@
          *        every use of the key.
          *
          * @see #setUserAuthenticators(int)
-         *
-         * @hide
          */
         public Builder setUserAuthenticationValidityDurationSeconds(int seconds) {
             mUserAuthenticationValidityDurationSeconds = seconds;
@@ -807,8 +792,6 @@
          * <p>By default, enrolling a new fingerprint does not invalidate the key.
          *
          * @see #setUserAuthenticators(Set)
-         *
-         * @hide
          */
         public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
             mInvalidatedOnNewFingerprintEnrolled = invalidated;
@@ -837,7 +820,8 @@
                     mKeyValidityForConsumptionEnd,
                     mPurposes,
                     mDigests,
-                    mPaddings,
+                    mEncryptionPaddings,
+                    mSignaturePaddings,
                     mBlockModes,
                     mRandomizedEncryptionRequired,
                     mUserAuthenticators,
diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java
index 487eac0..7bc6378 100644
--- a/keystore/java/android/security/KeyStoreCipherSpi.java
+++ b/keystore/java/android/security/KeyStoreCipherSpi.java
@@ -48,68 +48,67 @@
 public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCryptoOperation {
 
     public abstract static class AES extends KeyStoreCipherSpi {
-        protected AES(@KeyStoreKeyConstraints.BlockModeEnum int blockMode,
-                @KeyStoreKeyConstraints.PaddingEnum int padding, boolean ivUsed) {
-            super(KeyStoreKeyConstraints.Algorithm.AES,
-                    blockMode,
-                    padding,
+        protected AES(int keymasterBlockMode, int keymasterPadding, boolean ivUsed) {
+            super(KeymasterDefs.KM_ALGORITHM_AES,
+                    keymasterBlockMode,
+                    keymasterPadding,
                     16,
                     ivUsed);
         }
 
         public abstract static class ECB extends AES {
-            protected ECB(@KeyStoreKeyConstraints.PaddingEnum int padding) {
-                super(KeyStoreKeyConstraints.BlockMode.ECB, padding, false);
+            protected ECB(int keymasterPadding) {
+                super(KeymasterDefs.KM_MODE_ECB, keymasterPadding, false);
             }
 
             public static class NoPadding extends ECB {
                 public NoPadding() {
-                    super(KeyStoreKeyConstraints.Padding.NONE);
+                    super(KeymasterDefs.KM_PAD_NONE);
                 }
             }
 
             public static class PKCS7Padding extends ECB {
                 public PKCS7Padding() {
-                    super(KeyStoreKeyConstraints.Padding.PKCS7);
+                    super(KeymasterDefs.KM_PAD_PKCS7);
                 }
             }
         }
 
         public abstract static class CBC extends AES {
-            protected CBC(@KeyStoreKeyConstraints.BlockModeEnum int padding) {
-                super(KeyStoreKeyConstraints.BlockMode.CBC, padding, true);
+            protected CBC(int keymasterPadding) {
+                super(KeymasterDefs.KM_MODE_CBC, keymasterPadding, true);
             }
 
             public static class NoPadding extends CBC {
                 public NoPadding() {
-                    super(KeyStoreKeyConstraints.Padding.NONE);
+                    super(KeymasterDefs.KM_PAD_NONE);
                 }
             }
 
             public static class PKCS7Padding extends CBC {
                 public PKCS7Padding() {
-                    super(KeyStoreKeyConstraints.Padding.PKCS7);
+                    super(KeymasterDefs.KM_PAD_PKCS7);
                 }
             }
         }
 
         public abstract static class CTR extends AES {
-            protected CTR(@KeyStoreKeyConstraints.BlockModeEnum int padding) {
-                super(KeyStoreKeyConstraints.BlockMode.CTR, padding, true);
+            protected CTR(int keymasterPadding) {
+                super(KeymasterDefs.KM_MODE_CTR, keymasterPadding, true);
             }
 
             public static class NoPadding extends CTR {
                 public NoPadding() {
-                    super(KeyStoreKeyConstraints.Padding.NONE);
+                    super(KeymasterDefs.KM_PAD_NONE);
                 }
             }
         }
     }
 
     private final KeyStore mKeyStore;
-    private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
-    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockMode;
-    private final @KeyStoreKeyConstraints.PaddingEnum int mPadding;
+    private final int mKeymasterAlgorithm;
+    private final int mKeymasterBlockMode;
+    private final int mKeymasterPadding;
     private final int mBlockSizeBytes;
 
     /** Whether this transformation requires an IV. */
@@ -138,15 +137,15 @@
     private KeyStoreCryptoOperationChunkedStreamer mMainDataStreamer;
 
     protected KeyStoreCipherSpi(
-            @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
-            @KeyStoreKeyConstraints.BlockModeEnum int blockMode,
-            @KeyStoreKeyConstraints.PaddingEnum int padding,
+            int keymasterAlgorithm,
+            int keymasterBlockMode,
+            int keymasterPadding,
             int blockSizeBytes,
             boolean ivUsed) {
         mKeyStore = KeyStore.getInstance();
-        mAlgorithm = algorithm;
-        mBlockMode = blockMode;
-        mPadding = padding;
+        mKeymasterAlgorithm = keymasterAlgorithm;
+        mKeymasterBlockMode = keymasterBlockMode;
+        mKeymasterPadding = keymasterPadding;
         mBlockSizeBytes = blockSizeBytes;
         mIvRequired = ivUsed;
     }
@@ -236,9 +235,9 @@
         }
 
         KeymasterArguments keymasterInputArgs = new KeymasterArguments();
-        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mAlgorithm);
-        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, mBlockMode);
-        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_PADDING, mPadding);
+        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
+        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode);
+        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
         addAlgorithmSpecificParametersToBegin(keymasterInputArgs);
 
         KeymasterArguments keymasterOutputArgs = new KeymasterArguments();
diff --git a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
index 1f8b7e4..aafd2fa 100644
--- a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
@@ -19,6 +19,8 @@
 import android.os.IBinder;
 import android.security.keymaster.OperationResult;
 
+import libcore.util.EmptyArray;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
@@ -95,7 +97,7 @@
                 // Too much input for one chunk -- extract one max-sized chunk and feed it into the
                 // update operation.
                 inputBytesInChunk = mMaxChunkSize - mBufferedLength;
-                chunk = concat(mBuffered, mBufferedOffset, mBufferedLength,
+                chunk = ArrayUtils.concat(mBuffered, mBufferedOffset, mBufferedLength,
                         input, inputOffset, inputBytesInChunk);
             } else {
                 // All of available input fits into one chunk.
@@ -108,7 +110,7 @@
                 } else {
                     // Need to combine buffered data with input data into one array.
                     inputBytesInChunk = inputLength;
-                    chunk = concat(mBuffered, mBufferedOffset, mBufferedLength,
+                    chunk = ArrayUtils.concat(mBuffered, mBufferedOffset, mBufferedLength,
                             input, inputOffset, inputBytesInChunk);
                 }
             }
@@ -197,7 +199,7 @@
 
         // Flush all buffered input and provided input into keystore/keymaster.
         byte[] output = update(input, inputOffset, inputLength);
-        output = concat(output, flush());
+        output = ArrayUtils.concat(output, flush());
 
         OperationResult opResult = mKeyStoreStream.finish();
         if (opResult == null) {
@@ -206,7 +208,7 @@
             throw KeyStore.getKeyStoreException(opResult.resultCode);
         }
 
-        return concat(output, opResult.output);
+        return ArrayUtils.concat(output, opResult.output);
     }
 
     /**
@@ -215,11 +217,11 @@
      */
     public byte[] flush() throws KeyStoreException {
         if (mBufferedLength <= 0) {
-            return EMPTY_BYTE_ARRAY;
+            return EmptyArray.BYTE;
         }
 
-        byte[] chunk = subarray(mBuffered, mBufferedOffset, mBufferedLength);
-        mBuffered = EMPTY_BYTE_ARRAY;
+        byte[] chunk = ArrayUtils.subarray(mBuffered, mBufferedOffset, mBufferedLength);
+        mBuffered = EmptyArray.BYTE;
         mBufferedLength = 0;
         mBufferedOffset = 0;
 
@@ -238,46 +240,7 @@
                     + " . Provided: " + chunk.length + ", consumed: " + opResult.inputConsumed);
         }
 
-        return (opResult.output != null) ? opResult.output : EMPTY_BYTE_ARRAY;
-    }
-
-    private static byte[] concat(byte[] arr1, byte[] arr2) {
-        if ((arr1 == null) || (arr1.length == 0)) {
-            return arr2;
-        } else if ((arr2 == null) || (arr2.length == 0)) {
-            return arr1;
-        } else {
-            byte[] result = new byte[arr1.length + arr2.length];
-            System.arraycopy(arr1, 0, result, 0, arr1.length);
-            System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
-            return result;
-        }
-    }
-
-    private static byte[] concat(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2,
-            int len2) {
-        if (len1 == 0) {
-            return subarray(arr2, offset2, len2);
-        } else if (len2 == 0) {
-            return subarray(arr1, offset1, len1);
-        } else {
-            byte[] result = new byte[len1 + len2];
-            System.arraycopy(arr1, offset1, result, 0, len1);
-            System.arraycopy(arr2, offset2, result, len1, len2);
-            return result;
-        }
-    }
-
-    private static byte[] subarray(byte[] arr, int offset, int len) {
-        if (len == 0) {
-            return EMPTY_BYTE_ARRAY;
-        }
-        if ((offset == 0) && (len == arr.length)) {
-            return arr;
-        }
-        byte[] result = new byte[len];
-        System.arraycopy(arr, offset, result, 0, len);
-        return result;
+        return (opResult.output != null) ? opResult.output : EmptyArray.BYTE;
     }
 
     /**
diff --git a/keystore/java/android/security/KeyStoreHmacSpi.java b/keystore/java/android/security/KeyStoreHmacSpi.java
index f69e7d1..a19bbda 100644
--- a/keystore/java/android/security/KeyStoreHmacSpi.java
+++ b/keystore/java/android/security/KeyStoreHmacSpi.java
@@ -37,36 +37,36 @@
 
     public static class HmacSHA1 extends KeyStoreHmacSpi {
         public HmacSHA1() {
-            super(KeyStoreKeyConstraints.Digest.SHA1);
+            super(KeymasterDefs.KM_DIGEST_SHA1);
         }
     }
 
     public static class HmacSHA224 extends KeyStoreHmacSpi {
         public HmacSHA224() {
-            super(KeyStoreKeyConstraints.Digest.SHA224);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_224);
         }
     }
 
     public static class HmacSHA256 extends KeyStoreHmacSpi {
         public HmacSHA256() {
-            super(KeyStoreKeyConstraints.Digest.SHA256);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_256);
         }
     }
 
     public static class HmacSHA384 extends KeyStoreHmacSpi {
         public HmacSHA384() {
-            super(KeyStoreKeyConstraints.Digest.SHA384);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_384);
         }
     }
 
     public static class HmacSHA512 extends KeyStoreHmacSpi {
         public HmacSHA512() {
-            super(KeyStoreKeyConstraints.Digest.SHA512);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_512);
         }
     }
 
     private final KeyStore mKeyStore = KeyStore.getInstance();
-    private final @KeyStoreKeyConstraints.DigestEnum int mDigest;
+    private final int mKeymasterDigest;
     private final int mMacSizeBytes;
 
     private String mKeyAliasInKeyStore;
@@ -76,9 +76,9 @@
     private IBinder mOperationToken;
     private Long mOperationHandle;
 
-    protected KeyStoreHmacSpi(@KeyStoreKeyConstraints.DigestEnum int digest) {
-        mDigest = digest;
-        mMacSizeBytes = KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest);
+    protected KeyStoreHmacSpi(int keymasterDigest) {
+        mKeymasterDigest = keymasterDigest;
+        mMacSizeBytes = KeymasterUtils.getDigestOutputSizeBytes(keymasterDigest);
     }
 
     @Override
@@ -129,8 +129,8 @@
         }
 
         KeymasterArguments keymasterArgs = new KeymasterArguments();
-        keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeyStoreKeyConstraints.Algorithm.HMAC);
-        keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, mDigest);
+        keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_HMAC);
+        keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
 
         OperationResult opResult = mKeyStore.begin(mKeyAliasInKeyStore,
                 KeymasterDefs.KM_PURPOSE_SIGN,
diff --git a/keystore/java/android/security/KeyStoreKeyCharacteristics.java b/keystore/java/android/security/KeyStoreKeyCharacteristics.java
deleted file mode 100644
index 1f5d400..0000000
--- a/keystore/java/android/security/KeyStoreKeyCharacteristics.java
+++ /dev/null
@@ -1,63 +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.security;
-
-import android.annotation.IntDef;
-import android.security.keymaster.KeymasterDefs;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Characteristics of {@code AndroidKeyStore} keys.
- *
- * @hide
- */
-public abstract class KeyStoreKeyCharacteristics {
-    private KeyStoreKeyCharacteristics() {}
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({Origin.GENERATED, Origin.IMPORTED})
-    public @interface OriginEnum {}
-
-    /**
-     * Origin of the key.
-     */
-    public static abstract class Origin {
-        private Origin() {}
-
-        /** Key was generated inside AndroidKeyStore. */
-        public static final int GENERATED = 1 << 0;
-
-        /** Key was imported into AndroidKeyStore. */
-        public static final int IMPORTED = 1 << 1;
-
-        /**
-         * @hide
-         */
-        public static @OriginEnum int fromKeymaster(int origin) {
-            switch (origin) {
-                case KeymasterDefs.KM_ORIGIN_HARDWARE:
-                    return GENERATED;
-                case KeymasterDefs.KM_ORIGIN_IMPORTED:
-                    return IMPORTED;
-                default:
-                    throw new IllegalArgumentException("Unknown origin: " + origin);
-            }
-        }
-    }
-}
diff --git a/keystore/java/android/security/KeyStoreKeyConstraints.java b/keystore/java/android/security/KeyStoreKeyConstraints.java
deleted file mode 100644
index 98ac3e7..0000000
--- a/keystore/java/android/security/KeyStoreKeyConstraints.java
+++ /dev/null
@@ -1,946 +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.security;
-
-import android.annotation.IntDef;
-import android.security.keymaster.KeymasterDefs;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Collection;
-import java.util.Locale;
-
-/**
- * Constraints for {@code AndroidKeyStore} keys.
- *
- * @hide
- */
-public abstract class KeyStoreKeyConstraints {
-    private KeyStoreKeyConstraints() {}
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true,
-            value = {Purpose.ENCRYPT, Purpose.DECRYPT, Purpose.SIGN, Purpose.VERIFY})
-    public @interface PurposeEnum {}
-
-    /**
-     * Purpose of key.
-     */
-    public static abstract class Purpose {
-        private Purpose() {}
-
-        /**
-         * Purpose: encryption.
-         */
-        public static final int ENCRYPT = 1 << 0;
-
-        /**
-         * Purpose: decryption.
-         */
-        public static final int DECRYPT = 1 << 1;
-
-        /**
-         * Purpose: signing.
-         */
-        public static final int SIGN = 1 << 2;
-
-        /**
-         * Purpose: signature verification.
-         */
-        public static final int VERIFY = 1 << 3;
-
-        /**
-         * @hide
-         */
-        public static int toKeymaster(@PurposeEnum int purpose) {
-            switch (purpose) {
-                case ENCRYPT:
-                    return KeymasterDefs.KM_PURPOSE_ENCRYPT;
-                case DECRYPT:
-                    return KeymasterDefs.KM_PURPOSE_DECRYPT;
-                case SIGN:
-                    return KeymasterDefs.KM_PURPOSE_SIGN;
-                case VERIFY:
-                    return KeymasterDefs.KM_PURPOSE_VERIFY;
-                default:
-                    throw new IllegalArgumentException("Unknown purpose: " + purpose);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @PurposeEnum int fromKeymaster(int purpose) {
-            switch (purpose) {
-                case KeymasterDefs.KM_PURPOSE_ENCRYPT:
-                    return ENCRYPT;
-                case KeymasterDefs.KM_PURPOSE_DECRYPT:
-                    return DECRYPT;
-                case KeymasterDefs.KM_PURPOSE_SIGN:
-                    return SIGN;
-                case KeymasterDefs.KM_PURPOSE_VERIFY:
-                    return VERIFY;
-                default:
-                    throw new IllegalArgumentException("Unknown purpose: " + purpose);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static int[] allToKeymaster(@PurposeEnum int purposes) {
-            int[] result = getSetFlags(purposes);
-            for (int i = 0; i < result.length; i++) {
-                result[i] = toKeymaster(result[i]);
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static @PurposeEnum int allFromKeymaster(Collection<Integer> purposes) {
-            @PurposeEnum int result = 0;
-            for (int keymasterPurpose : purposes) {
-                result |= fromKeymaster(keymasterPurpose);
-            }
-            return result;
-        }
-    }
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({Algorithm.AES, Algorithm.HMAC, Algorithm.RSA, Algorithm.EC})
-    public @interface AlgorithmEnum {}
-
-    /**
-     * Key algorithm.
-     */
-    public static abstract class Algorithm {
-        private Algorithm() {}
-
-        /**
-         * Key algorithm: AES.
-         */
-        public static final int AES = 1 << 0;
-
-        /**
-         * Key algorithm: HMAC.
-         */
-        public static final int HMAC = 1 << 1;
-
-        /**
-         * Key algorithm: RSA.
-         */
-        public static final int RSA = 1 << 2;
-
-        /**
-         * Key algorithm: EC.
-         */
-        public static final int EC = 1 << 3;
-
-        /**
-         * @hide
-         */
-        public static int toKeymaster(@AlgorithmEnum int algorithm) {
-            switch (algorithm) {
-                case AES:
-                    return KeymasterDefs.KM_ALGORITHM_AES;
-                case HMAC:
-                    return KeymasterDefs.KM_ALGORITHM_HMAC;
-                case RSA:
-                    return KeymasterDefs.KM_ALGORITHM_RSA;
-                case EC:
-                    return KeymasterDefs.KM_ALGORITHM_EC;
-                default:
-                    throw new IllegalArgumentException("Unknown algorithm: " + algorithm);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @AlgorithmEnum int fromKeymaster(int algorithm) {
-            switch (algorithm) {
-                case KeymasterDefs.KM_ALGORITHM_AES:
-                    return AES;
-                case KeymasterDefs.KM_ALGORITHM_HMAC:
-                    return HMAC;
-                case KeymasterDefs.KM_ALGORITHM_RSA:
-                    return RSA;
-                case KeymasterDefs.KM_ALGORITHM_EC:
-                    return EC;
-                default:
-                    throw new IllegalArgumentException("Unknown algorithm: " + algorithm);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static String toString(@AlgorithmEnum int algorithm) {
-            switch (algorithm) {
-                case AES:
-                    return "AES";
-                case HMAC:
-                    return "HMAC";
-                case RSA:
-                    return "RSA";
-                case EC:
-                    return "EC";
-                default:
-                    throw new IllegalArgumentException("Unknown algorithm: " + algorithm);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @AlgorithmEnum int fromJCASecretKeyAlgorithm(String algorithm) {
-            if (algorithm == null) {
-                throw new NullPointerException("algorithm == null");
-            } else  if ("AES".equalsIgnoreCase(algorithm)) {
-                return AES;
-            } else if (algorithm.toLowerCase(Locale.US).startsWith("hmac")) {
-                return HMAC;
-            } else {
-                throw new IllegalArgumentException(
-                        "Unsupported secret key algorithm: " + algorithm);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static String toJCASecretKeyAlgorithm(@AlgorithmEnum int algorithm,
-                @DigestEnum Integer digest) {
-            switch (algorithm) {
-                case AES:
-                    return "AES";
-                case HMAC:
-                    if (digest == null) {
-                        throw new IllegalArgumentException("HMAC digest not specified");
-                    }
-                    switch (digest) {
-                        case Digest.MD5:
-                            return "HmacMD5";
-                        case Digest.SHA1:
-                            return "HmacSHA1";
-                        case Digest.SHA224:
-                            return "HmacSHA224";
-                        case Digest.SHA256:
-                            return "HmacSHA256";
-                        case Digest.SHA384:
-                            return "HmacSHA384";
-                        case Digest.SHA512:
-                            return "HmacSHA512";
-                        default:
-                            throw new IllegalArgumentException(
-                                    "Unsupported HMAC digest: " + digest);
-                    }
-                default:
-                    throw new IllegalArgumentException("Unsupported key algorithm: " + algorithm);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static String toJCAKeyPairAlgorithm(@AlgorithmEnum int algorithm) {
-            switch (algorithm) {
-                case RSA:
-                    return "RSA";
-                case EC:
-                    return "EC";
-                default:
-                    throw new IllegalArgumentException("Unsupported key alorithm: " + algorithm);
-            }
-        }
-    }
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true,
-            value = {
-                Padding.NONE,
-                Padding.PKCS7,
-                Padding.RSA_PKCS1_ENCRYPTION,
-                Padding.RSA_PKCS1_SIGNATURE,
-                Padding.RSA_OAEP,
-                Padding.RSA_PSS,
-                })
-    public @interface PaddingEnum {}
-
-    /**
-     * Padding for signing and encryption.
-     */
-    public static abstract class Padding {
-        private Padding() {}
-
-        /**
-         * No padding.
-         */
-        public static final int NONE = 1 << 0;
-
-        /**
-         * PKCS#7 padding.
-         */
-        public static final int PKCS7 = 1 << 1;
-
-        /**
-         * RSA PKCS#1 v1.5 padding for encryption/decryption.
-         */
-        public static final int RSA_PKCS1_ENCRYPTION = 1 << 2;
-
-        /**
-         * RSA PKCS#1 v1.5 padding for signatures.
-         */
-        public static final int RSA_PKCS1_SIGNATURE = 1 << 3;
-
-        /**
-         * RSA Optimal Asymmetric Encryption Padding (OAEP).
-         */
-        public static final int RSA_OAEP = 1 << 4;
-
-        /**
-         * RSA PKCS#1 v2.1 Probabilistic Signature Scheme (PSS) padding.
-         */
-        public static final int RSA_PSS = 1 << 5;
-
-        /**
-         * @hide
-         */
-        public static int toKeymaster(int padding) {
-            switch (padding) {
-                case NONE:
-                    return KeymasterDefs.KM_PAD_NONE;
-                case PKCS7:
-                    return KeymasterDefs.KM_PAD_PKCS7;
-                case RSA_PKCS1_ENCRYPTION:
-                    return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
-                case RSA_PKCS1_SIGNATURE:
-                    return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN;
-                case RSA_OAEP:
-                    return KeymasterDefs.KM_PAD_RSA_OAEP;
-                case RSA_PSS:
-                    return KeymasterDefs.KM_PAD_RSA_PSS;
-                default:
-                    throw new IllegalArgumentException("Unknown padding: " + padding);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @PaddingEnum int fromKeymaster(int padding) {
-            switch (padding) {
-                case KeymasterDefs.KM_PAD_NONE:
-                    return NONE;
-                case KeymasterDefs.KM_PAD_PKCS7:
-                    return PKCS7;
-                case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
-                    return RSA_PKCS1_ENCRYPTION;
-                case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN:
-                    return RSA_PKCS1_SIGNATURE;
-                case KeymasterDefs.KM_PAD_RSA_OAEP:
-                    return RSA_OAEP;
-                case KeymasterDefs.KM_PAD_RSA_PSS:
-                    return RSA_PSS;
-                default:
-                    throw new IllegalArgumentException("Unknown padding: " + padding);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static String toString(@PaddingEnum int padding) {
-            switch (padding) {
-                case NONE:
-                    return "NONE";
-                case PKCS7:
-                    return "PKCS#7";
-                case RSA_PKCS1_ENCRYPTION:
-                    return "RSA PKCS#1 (encryption)";
-                case RSA_PKCS1_SIGNATURE:
-                    return "RSA PKCS#1 (signature)";
-                case RSA_OAEP:
-                    return "RSA OAEP";
-                case RSA_PSS:
-                    return "RSA PSS";
-                default:
-                    throw new IllegalArgumentException("Unknown padding: " + padding);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @PaddingEnum int fromJCACipherPadding(String padding) {
-            String paddingLower = padding.toLowerCase(Locale.US);
-            if ("nopadding".equals(paddingLower)) {
-                return NONE;
-            } else if ("pkcs7padding".equals(paddingLower)) {
-                return PKCS7;
-            } else if ("pkcs1padding".equals(paddingLower)) {
-                return RSA_PKCS1_ENCRYPTION;
-            } else if (("oaeppadding".equals(paddingLower))
-                    || ((paddingLower.startsWith("oaepwith"))
-                            && (paddingLower.endsWith("padding")))) {
-                return RSA_OAEP;
-            } else {
-                throw new IllegalArgumentException("Unknown padding: " + padding);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static int[] allToKeymaster(@PaddingEnum int paddings) {
-            int[] result = getSetFlags(paddings);
-            for (int i = 0; i < result.length; i++) {
-                result[i] = toKeymaster(result[i]);
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static @PaddingEnum int allFromKeymaster(Collection<Integer> paddings) {
-            @PaddingEnum int result = 0;
-            for (int keymasterPadding : paddings) {
-                result |= fromKeymaster(keymasterPadding);
-            }
-            return result;
-        }
-    }
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true,
-            value = {
-                Digest.NONE,
-                Digest.MD5,
-                Digest.SHA1,
-                Digest.SHA224,
-                Digest.SHA256,
-                Digest.SHA384,
-                Digest.SHA512,
-                })
-    public @interface DigestEnum {}
-
-    /**
-     * Digests that can be used with a key when signing or generating Message Authentication
-     * Codes (MACs).
-     */
-    public static abstract class Digest {
-        private Digest() {}
-
-        /**
-         * No digest: sign/authenticate the raw message.
-         */
-        public static final int NONE = 1 << 0;
-
-        /**
-         * MD5 digest.
-         */
-        public static final int MD5 = 1 << 1;
-
-        /**
-         * SHA-1 digest.
-         */
-        public static final int SHA1 = 1 << 2;
-
-        /**
-         * SHA-2 224 (aka SHA-224) digest.
-         */
-        public static final int SHA224 = 1 << 3;
-
-        /**
-         * SHA-2 256 (aka SHA-256) digest.
-         */
-        public static final int SHA256 = 1 << 4;
-
-        /**
-         * SHA-2 384 (aka SHA-384) digest.
-         */
-        public static final int SHA384 = 1 << 5;
-
-        /**
-         * SHA-2 512 (aka SHA-512) digest.
-         */
-        public static final int SHA512 = 1 << 6;
-
-        /**
-         * @hide
-         */
-        public static String toString(@DigestEnum int digest) {
-            switch (digest) {
-                case NONE:
-                    return "NONE";
-                case MD5:
-                    return "MD5";
-                case SHA1:
-                    return "SHA-1";
-                case SHA224:
-                    return "SHA-224";
-                case SHA256:
-                    return "SHA-256";
-                case SHA384:
-                    return "SHA-384";
-                case SHA512:
-                    return "SHA-512";
-                default:
-                    throw new IllegalArgumentException("Unknown digest: " + digest);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static String allToString(@DigestEnum int digests) {
-            StringBuilder result = new StringBuilder("[");
-            boolean firstValue = true;
-            for (@DigestEnum int digest : getSetFlags(digests)) {
-                if (firstValue) {
-                    firstValue = false;
-                } else {
-                    result.append(", ");
-                }
-                result.append(toString(digest));
-            }
-            result.append(']');
-            return result.toString();
-        }
-
-        /**
-         * @hide
-         */
-        public static int toKeymaster(@DigestEnum int digest) {
-            switch (digest) {
-                case NONE:
-                    return KeymasterDefs.KM_DIGEST_NONE;
-                case MD5:
-                    return KeymasterDefs.KM_DIGEST_MD5;
-                case SHA1:
-                    return KeymasterDefs.KM_DIGEST_SHA1;
-                case SHA224:
-                    return KeymasterDefs.KM_DIGEST_SHA_2_224;
-                case SHA256:
-                    return KeymasterDefs.KM_DIGEST_SHA_2_256;
-                case SHA384:
-                    return KeymasterDefs.KM_DIGEST_SHA_2_384;
-                case SHA512:
-                    return KeymasterDefs.KM_DIGEST_SHA_2_512;
-                default:
-                    throw new IllegalArgumentException("Unknown digest: " + digest);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @DigestEnum int fromKeymaster(int digest) {
-            switch (digest) {
-                case KeymasterDefs.KM_DIGEST_NONE:
-                    return NONE;
-                case KeymasterDefs.KM_DIGEST_MD5:
-                    return MD5;
-                case KeymasterDefs.KM_DIGEST_SHA1:
-                    return SHA1;
-                case KeymasterDefs.KM_DIGEST_SHA_2_224:
-                    return SHA224;
-                case KeymasterDefs.KM_DIGEST_SHA_2_256:
-                    return SHA256;
-                case KeymasterDefs.KM_DIGEST_SHA_2_384:
-                    return SHA384;
-                case KeymasterDefs.KM_DIGEST_SHA_2_512:
-                    return SHA512;
-                default:
-                    throw new IllegalArgumentException("Unknown digest: " + digest);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static int[] allToKeymaster(@DigestEnum int digests) {
-            int[] result = getSetFlags(digests);
-            for (int i = 0; i < result.length; i++) {
-                result[i] = toKeymaster(result[i]);
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static @DigestEnum int allFromKeymaster(Collection<Integer> digests) {
-            @DigestEnum int result = 0;
-            for (int keymasterDigest : digests) {
-                result |= fromKeymaster(keymasterDigest);
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static @DigestEnum Integer fromJCASecretKeyAlgorithm(String algorithm) {
-            String algorithmLower = algorithm.toLowerCase(Locale.US);
-            if (algorithmLower.startsWith("hmac")) {
-                String digestLower = algorithmLower.substring("hmac".length());
-                if ("md5".equals(digestLower)) {
-                    return MD5;
-                } else if ("sha1".equals(digestLower)) {
-                    return SHA1;
-                } else if ("sha224".equals(digestLower)) {
-                    return SHA224;
-                } else if ("sha256".equals(digestLower)) {
-                    return SHA256;
-                } else if ("sha384".equals(digestLower)) {
-                    return SHA384;
-                } else if ("sha512".equals(digestLower)) {
-                    return SHA512;
-                } else {
-                    throw new IllegalArgumentException("Unsupported digest: " + digestLower);
-                }
-            } else {
-                return null;
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static String toJCASignatureAlgorithmDigest(@DigestEnum int digest) {
-            switch (digest) {
-                case NONE:
-                    return "NONE";
-                case MD5:
-                    return "MD5";
-                case SHA1:
-                    return "SHA1";
-                case SHA224:
-                    return "SHA224";
-                case SHA256:
-                    return "SHA256";
-                case SHA384:
-                    return "SHA384";
-                case SHA512:
-                    return "SHA512";
-                default:
-                    throw new IllegalArgumentException("Unknown digest: " + digest);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static Integer getOutputSizeBytes(@DigestEnum int digest) {
-            switch (digest) {
-                case NONE:
-                    return null;
-                case MD5:
-                    return 128 / 8;
-                case SHA1:
-                    return 160 / 8;
-                case SHA224:
-                    return 224 / 8;
-                case SHA256:
-                    return 256 / 8;
-                case SHA384:
-                    return 384 / 8;
-                case SHA512:
-                    return 512 / 8;
-                default:
-                    throw new IllegalArgumentException("Unknown digest: " + digest);
-            }
-        }
-    }
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true,
-            value = {BlockMode.ECB, BlockMode.CBC, BlockMode.CTR, BlockMode.GCM})
-    public @interface BlockModeEnum {}
-
-    /**
-     * Block modes that can be used when encrypting/decrypting using a key.
-     */
-    public static abstract class BlockMode {
-        private BlockMode() {}
-
-        /** Electronic Codebook (ECB) block mode. */
-        public static final int ECB = 1 << 0;
-
-        /** Cipher Block Chaining (CBC) block mode. */
-        public static final int CBC = 1 << 1;
-
-        /** Counter (CTR) block mode. */
-        public static final int CTR = 1 << 2;
-
-        /** Galois/Counter Mode (GCM) block mode. */
-        public static final int GCM = 1 << 3;
-
-        /**
-         * Set of block modes compatible with IND-CPA if used correctly.
-         *
-         * @hide
-         */
-        public static final @BlockModeEnum int IND_CPA_COMPATIBLE_MODES =
-                CBC | CTR | GCM;
-
-        /**
-         * @hide
-         */
-        public static int toKeymaster(@BlockModeEnum int mode) {
-            switch (mode) {
-                case ECB:
-                    return KeymasterDefs.KM_MODE_ECB;
-                case CBC:
-                    return KeymasterDefs.KM_MODE_CBC;
-                case CTR:
-                    return KeymasterDefs.KM_MODE_CTR;
-                case GCM:
-                    return KeymasterDefs.KM_MODE_GCM;
-                default:
-                    throw new IllegalArgumentException("Unknown block mode: " + mode);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @BlockModeEnum int fromKeymaster(int mode) {
-            switch (mode) {
-                case KeymasterDefs.KM_MODE_ECB:
-                    return ECB;
-                case KeymasterDefs.KM_MODE_CBC:
-                    return CBC;
-                case KeymasterDefs.KM_MODE_CTR:
-                    return CTR;
-                case KeymasterDefs.KM_MODE_GCM:
-                    return GCM;
-                default:
-                    throw new IllegalArgumentException("Unknown block mode: " + mode);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static int[] allToKeymaster(@BlockModeEnum int modes) {
-            int[] result = getSetFlags(modes);
-            for (int i = 0; i < result.length; i++) {
-                result[i] = toKeymaster(result[i]);
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static @BlockModeEnum int allFromKeymaster(Collection<Integer> modes) {
-            @BlockModeEnum int result = 0;
-            for (int keymasterMode : modes) {
-                result |= fromKeymaster(keymasterMode);
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static String toString(@BlockModeEnum int mode) {
-            switch (mode) {
-                case ECB:
-                    return "ECB";
-                case CBC:
-                    return "CBC";
-                case CTR:
-                    return "CTR";
-                case GCM:
-                    return "GCM";
-                default:
-                    throw new IllegalArgumentException("Unknown block mode: " + mode);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static String allToString(@BlockModeEnum int modes) {
-            StringBuilder result = new StringBuilder("[");
-            boolean firstValue = true;
-            for (@BlockModeEnum int mode : getSetFlags(modes)) {
-                if (firstValue) {
-                    firstValue = false;
-                } else {
-                    result.append(", ");
-                }
-                result.append(toString(mode));
-            }
-            result.append(']');
-            return result.toString();
-        }
-
-        /**
-         * @hide
-         */
-        public static @BlockModeEnum int fromJCAMode(String mode) {
-            String modeLower = mode.toLowerCase(Locale.US);
-            if ("ecb".equals(modeLower)) {
-                return ECB;
-            } else if ("cbc".equals(modeLower)) {
-                return CBC;
-            } else if ("ctr".equals(modeLower)) {
-                return CTR;
-            } else if ("gcm".equals(modeLower)) {
-                return GCM;
-            } else {
-                throw new IllegalArgumentException("Unknown block mode: " + mode);
-            }
-        }
-    }
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true,
-            value = {UserAuthenticator.LOCK_SCREEN})
-    public @interface UserAuthenticatorEnum {}
-
-    /**
-     * User authenticators which can be used to restrict/protect access to keys.
-     */
-    public static abstract class UserAuthenticator {
-        private UserAuthenticator() {}
-
-        /** Lock screen. */
-        public static final int LOCK_SCREEN = 1 << 0;
-
-        /** Fingerprint reader/sensor. */
-        public static final int FINGERPRINT_READER = 1 << 1;
-
-        /**
-         * @hide
-         */
-        public static int toKeymaster(@UserAuthenticatorEnum int userAuthenticator) {
-            switch (userAuthenticator) {
-                case LOCK_SCREEN:
-                    return KeymasterDefs.HW_AUTH_PASSWORD;
-                case FINGERPRINT_READER:
-                    return KeymasterDefs.HW_AUTH_FINGERPRINT;
-                default:
-                    throw new IllegalArgumentException(
-                            "Unknown user authenticator: " + userAuthenticator);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @UserAuthenticatorEnum int fromKeymaster(int userAuthenticator) {
-            switch (userAuthenticator) {
-                case KeymasterDefs.HW_AUTH_PASSWORD:
-                    return LOCK_SCREEN;
-                case FINGERPRINT_READER:
-                    return FINGERPRINT_READER;
-                default:
-                    throw new IllegalArgumentException(
-                            "Unknown user authenticator: " + userAuthenticator);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static int allToKeymaster(@UserAuthenticatorEnum int userAuthenticators) {
-            int result = 0;
-            int userAuthenticator = 1;
-            while (userAuthenticators != 0) {
-                if ((userAuthenticators & 1) != 0) {
-                    result |= toKeymaster(userAuthenticator);
-                }
-                userAuthenticators >>>= 1;
-                userAuthenticator <<= 1;
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static @UserAuthenticatorEnum int allFromKeymaster(int userAuthenticators) {
-            @UserAuthenticatorEnum int result = 0;
-            int userAuthenticator = 1;
-            while (userAuthenticators != 0) {
-                if ((userAuthenticators & 1) != 0) {
-                    result |= fromKeymaster(userAuthenticator);
-                }
-                userAuthenticators >>>= 1;
-                userAuthenticator <<= 1;
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static String toString(@UserAuthenticatorEnum int userAuthenticator) {
-            switch (userAuthenticator) {
-                case LOCK_SCREEN:
-                    return "LOCK_SCREEN";
-                case FINGERPRINT_READER:
-                    return "FINGERPRINT_READER";
-                default:
-                    throw new IllegalArgumentException(
-                            "Unknown user authenticator: " + userAuthenticator);
-            }
-        }
-    }
-
-    private static final int[] EMPTY_INT_ARRAY = new int[0];
-
-    private static int[] getSetFlags(int flags) {
-        if (flags == 0) {
-            return EMPTY_INT_ARRAY;
-        }
-        int result[] = new int[getSetBitCount(flags)];
-        int resultOffset = 0;
-        int flag = 1;
-        while (flags != 0) {
-            if ((flags & 1) != 0) {
-                result[resultOffset] = flag;
-                resultOffset++;
-            }
-            flags >>>= 1;
-            flag <<= 1;
-        }
-        return result;
-    }
-
-    private static int getSetBitCount(int value) {
-        if (value == 0) {
-            return 0;
-        }
-        int result = 0;
-        while (value != 0) {
-            if ((value & 1) != 0) {
-                result++;
-            }
-            value >>>= 1;
-        }
-        return result;
-    }
-}
diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
index b39d16d..72c485a 100644
--- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
@@ -37,68 +37,68 @@
 
     public static class AES extends KeyStoreKeyGeneratorSpi {
         public AES() {
-            super(KeyStoreKeyConstraints.Algorithm.AES, 128);
+            super(KeymasterDefs.KM_ALGORITHM_AES, 128);
         }
     }
 
     protected static abstract class HmacBase extends KeyStoreKeyGeneratorSpi {
-        protected HmacBase(@KeyStoreKeyConstraints.DigestEnum int digest) {
-            super(KeyStoreKeyConstraints.Algorithm.HMAC,
-                    digest,
-                    KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest) * 8);
+        protected HmacBase(int keymasterDigest) {
+            super(KeymasterDefs.KM_ALGORITHM_HMAC,
+                    keymasterDigest,
+                    KeymasterUtils.getDigestOutputSizeBytes(keymasterDigest) * 8);
         }
     }
 
     public static class HmacSHA1 extends HmacBase {
         public HmacSHA1() {
-            super(KeyStoreKeyConstraints.Digest.SHA1);
+            super(KeymasterDefs.KM_DIGEST_SHA1);
         }
     }
 
     public static class HmacSHA224 extends HmacBase {
         public HmacSHA224() {
-            super(KeyStoreKeyConstraints.Digest.SHA224);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_224);
         }
     }
 
     public static class HmacSHA256 extends HmacBase {
         public HmacSHA256() {
-            super(KeyStoreKeyConstraints.Digest.SHA256);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_256);
         }
     }
 
     public static class HmacSHA384 extends HmacBase {
         public HmacSHA384() {
-            super(KeyStoreKeyConstraints.Digest.SHA384);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_384);
         }
     }
 
     public static class HmacSHA512 extends HmacBase {
         public HmacSHA512() {
-            super(KeyStoreKeyConstraints.Digest.SHA512);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_512);
         }
     }
 
     private final KeyStore mKeyStore = KeyStore.getInstance();
-    private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
-    private final @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
+    private final int mKeymasterAlgorithm;
+    private final int mKeymasterDigest;
     private final int mDefaultKeySizeBits;
 
     private KeyGeneratorSpec mSpec;
     private SecureRandom mRng;
 
     protected KeyStoreKeyGeneratorSpi(
-            @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
+            int keymasterAlgorithm,
             int defaultKeySizeBits) {
-        this(algorithm, null, defaultKeySizeBits);
+        this(keymasterAlgorithm, -1, defaultKeySizeBits);
     }
 
     protected KeyStoreKeyGeneratorSpi(
-            @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
-            @KeyStoreKeyConstraints.DigestEnum Integer digest,
+            int keymasterAlgorithm,
+            int keymasterDigest,
             int defaultKeySizeBits) {
-        mAlgorithm = algorithm;
-        mDigest = digest;
+        mKeymasterAlgorithm = keymasterAlgorithm;
+        mKeymasterDigest = keymasterDigest;
         mDefaultKeySizeBits = defaultKeySizeBits;
     }
 
@@ -117,58 +117,55 @@
         }
 
         KeymasterArguments args = new KeymasterArguments();
-        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM,
-                KeyStoreKeyConstraints.Algorithm.toKeymaster(mAlgorithm));
-        if (mDigest != null) {
-            args.addInt(KeymasterDefs.KM_TAG_DIGEST,
-                    KeyStoreKeyConstraints.Digest.toKeymaster(mDigest));
-            Integer digestOutputSizeBytes =
-                    KeyStoreKeyConstraints.Digest.getOutputSizeBytes(mDigest);
-            if (digestOutputSizeBytes != null) {
+        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
+        if (mKeymasterDigest != -1) {
+            args.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
+            int digestOutputSizeBytes =
+                    KeymasterUtils.getDigestOutputSizeBytes(mKeymasterDigest);
+            if (digestOutputSizeBytes != -1) {
                 // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
                 // TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
                 args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
             }
         }
-        if (mAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
-            if (mDigest == null) {
-                throw new IllegalStateException("Digest algorithm must be specified for key"
-                        + " algorithm " + KeyStoreKeyConstraints.Algorithm.toString(mAlgorithm));
+        if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
+            if (mKeymasterDigest == -1) {
+                throw new IllegalStateException("Digest algorithm must be specified for HMAC key");
             }
         }
-        int keySizeBits = (spec.getKeySize() != null) ? spec.getKeySize() : mDefaultKeySizeBits;
+        int keySizeBits = (spec.getKeySize() != -1) ? spec.getKeySize() : mDefaultKeySizeBits;
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keySizeBits);
-        @KeyStoreKeyConstraints.PurposeEnum int purposes = spec.getPurposes();
-        @KeyStoreKeyConstraints.BlockModeEnum int blockModes = spec.getBlockModes();
-        if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
+        @KeyStoreKeyProperties.PurposeEnum int purposes = spec.getPurposes();
+        int[] keymasterBlockModes = KeymasterUtils.getKeymasterBlockModesFromJcaBlockModes(
+                spec.getBlockModes());
+        if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
                 && (spec.isRandomizedEncryptionRequired())) {
-            @KeyStoreKeyConstraints.BlockModeEnum int incompatibleBlockModes =
-                    blockModes & ~KeyStoreKeyConstraints.BlockMode.IND_CPA_COMPATIBLE_MODES;
-            if (incompatibleBlockModes != 0) {
-                throw new IllegalStateException(
-                        "Randomized encryption (IND-CPA) required but may be violated by block"
-                        + " mode(s): "
-                        + KeyStoreKeyConstraints.BlockMode.allToString(incompatibleBlockModes)
-                        + ". See KeyGeneratorSpec documentation.");
+            for (int keymasterBlockMode : keymasterBlockModes) {
+                if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible(keymasterBlockMode)) {
+                    throw new IllegalStateException(
+                            "Randomized encryption (IND-CPA) required but may be violated by block"
+                            + " mode: "
+                            + KeymasterUtils.getJcaBlockModeFromKeymasterBlockMode(
+                                    keymasterBlockMode)
+                            + ". See KeyGeneratorSpec documentation.");
+                }
             }
         }
 
         for (int keymasterPurpose :
-            KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) {
+            KeyStoreKeyProperties.Purpose.allToKeymaster(purposes)) {
             args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose);
         }
-        for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(blockModes)) {
-            args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockMode);
-        }
-        for (int keymasterPadding :
-            KeyStoreKeyConstraints.Padding.allToKeymaster(spec.getPaddings())) {
-            args.addInt(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
-        }
+        args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
+        args.addInts(
+                KeymasterDefs.KM_TAG_PADDING,
+                KeymasterUtils.getKeymasterPaddingsFromJcaEncryptionPaddings(
+                        spec.getEncryptionPaddings()));
         if (spec.getUserAuthenticators() == 0) {
             args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
         } else {
             args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
-                    KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
+                    KeyStoreKeyProperties.UserAuthenticator.allToKeymaster(
                             spec.getUserAuthenticators()));
         }
         if (spec.isInvalidatedOnNewFingerprintEnrolled()) {
@@ -189,7 +186,7 @@
                 (spec.getKeyValidityForConsumptionEnd() != null)
                 ? spec.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE));
 
-        if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
+        if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
                 && (!spec.isRandomizedEncryptionRequired())) {
             // Permit caller-provided IV when encrypting with this key
             args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
@@ -210,7 +207,7 @@
             throw KeyStore.getCryptoOperationException(errorCode);
         }
         String keyAlgorithmJCA =
-                KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(mAlgorithm, mDigest);
+                KeymasterUtils.getJcaSecretKeyAlgorithm(mKeymasterAlgorithm, mKeymasterDigest);
         return new KeyStoreSecretKey(keyAliasInKeystore, keyAlgorithmJCA);
     }
 
diff --git a/keystore/java/android/security/KeyStoreKeyProperties.java b/keystore/java/android/security/KeyStoreKeyProperties.java
new file mode 100644
index 0000000..b1f330f
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreKeyProperties.java
@@ -0,0 +1,281 @@
+/*
+ * 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;
+
+import android.annotation.IntDef;
+import android.security.keymaster.KeymasterDefs;
+
+import libcore.util.EmptyArray;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+
+/**
+ * Properties of {@code AndroidKeyStore} keys.
+ */
+public abstract class KeyStoreKeyProperties {
+    private KeyStoreKeyProperties() {}
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true,
+            value = {Purpose.ENCRYPT, Purpose.DECRYPT, Purpose.SIGN, Purpose.VERIFY})
+    public @interface PurposeEnum {}
+
+    /**
+     * Purpose of key.
+     */
+    public static abstract class Purpose {
+        private Purpose() {}
+
+        /**
+         * Purpose: encryption.
+         */
+        public static final int ENCRYPT = 1 << 0;
+
+        /**
+         * Purpose: decryption.
+         */
+        public static final int DECRYPT = 1 << 1;
+
+        /**
+         * Purpose: signing.
+         */
+        public static final int SIGN = 1 << 2;
+
+        /**
+         * Purpose: signature verification.
+         */
+        public static final int VERIFY = 1 << 3;
+
+        /**
+         * @hide
+         */
+        public static int toKeymaster(@PurposeEnum int purpose) {
+            switch (purpose) {
+                case ENCRYPT:
+                    return KeymasterDefs.KM_PURPOSE_ENCRYPT;
+                case DECRYPT:
+                    return KeymasterDefs.KM_PURPOSE_DECRYPT;
+                case SIGN:
+                    return KeymasterDefs.KM_PURPOSE_SIGN;
+                case VERIFY:
+                    return KeymasterDefs.KM_PURPOSE_VERIFY;
+                default:
+                    throw new IllegalArgumentException("Unknown purpose: " + purpose);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public static @PurposeEnum int fromKeymaster(int purpose) {
+            switch (purpose) {
+                case KeymasterDefs.KM_PURPOSE_ENCRYPT:
+                    return ENCRYPT;
+                case KeymasterDefs.KM_PURPOSE_DECRYPT:
+                    return DECRYPT;
+                case KeymasterDefs.KM_PURPOSE_SIGN:
+                    return SIGN;
+                case KeymasterDefs.KM_PURPOSE_VERIFY:
+                    return VERIFY;
+                default:
+                    throw new IllegalArgumentException("Unknown purpose: " + purpose);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public static int[] allToKeymaster(@PurposeEnum int purposes) {
+            int[] result = getSetFlags(purposes);
+            for (int i = 0; i < result.length; i++) {
+                result[i] = toKeymaster(result[i]);
+            }
+            return result;
+        }
+
+        /**
+         * @hide
+         */
+        public static @PurposeEnum int allFromKeymaster(Collection<Integer> purposes) {
+            @PurposeEnum int result = 0;
+            for (int keymasterPurpose : purposes) {
+                result |= fromKeymaster(keymasterPurpose);
+            }
+            return result;
+        }
+    }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true,
+            value = {UserAuthenticator.LOCK_SCREEN, UserAuthenticator.FINGERPRINT_READER})
+    public @interface UserAuthenticatorEnum {}
+
+    /**
+     * User authenticators which can be used to restrict/protect access to keys.
+     */
+    public static abstract class UserAuthenticator {
+        private UserAuthenticator() {}
+
+        /** Lock screen. */
+        public static final int LOCK_SCREEN = 1 << 0;
+
+        /** Fingerprint reader/sensor. */
+        public static final int FINGERPRINT_READER = 1 << 1;
+
+        /**
+         * @hide
+         */
+        public static int toKeymaster(@UserAuthenticatorEnum int userAuthenticator) {
+            switch (userAuthenticator) {
+                case LOCK_SCREEN:
+                    return KeymasterDefs.HW_AUTH_PASSWORD;
+                case FINGERPRINT_READER:
+                    return KeymasterDefs.HW_AUTH_FINGERPRINT;
+                default:
+                    throw new IllegalArgumentException(
+                            "Unknown user authenticator: " + userAuthenticator);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public static @UserAuthenticatorEnum int fromKeymaster(int userAuthenticator) {
+            switch (userAuthenticator) {
+                case KeymasterDefs.HW_AUTH_PASSWORD:
+                    return LOCK_SCREEN;
+                case KeymasterDefs.HW_AUTH_FINGERPRINT:
+                    return FINGERPRINT_READER;
+                default:
+                    throw new IllegalArgumentException(
+                            "Unknown user authenticator: " + userAuthenticator);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public static int allToKeymaster(@UserAuthenticatorEnum int userAuthenticators) {
+            int result = 0;
+            int userAuthenticator = 1;
+            while (userAuthenticators != 0) {
+                if ((userAuthenticators & 1) != 0) {
+                    result |= toKeymaster(userAuthenticator);
+                }
+                userAuthenticators >>>= 1;
+                userAuthenticator <<= 1;
+            }
+            return result;
+        }
+
+        /**
+         * @hide
+         */
+        public static @UserAuthenticatorEnum int allFromKeymaster(int userAuthenticators) {
+            @UserAuthenticatorEnum int result = 0;
+            int userAuthenticator = 1;
+            while (userAuthenticators != 0) {
+                if ((userAuthenticators & 1) != 0) {
+                    result |= fromKeymaster(userAuthenticator);
+                }
+                userAuthenticators >>>= 1;
+                userAuthenticator <<= 1;
+            }
+            return result;
+        }
+
+        /**
+         * @hide
+         */
+        public static String toString(@UserAuthenticatorEnum int userAuthenticator) {
+            switch (userAuthenticator) {
+                case LOCK_SCREEN:
+                    return "LOCK_SCREEN";
+                case FINGERPRINT_READER:
+                    return "FINGERPRINT_READER";
+                default:
+                    throw new IllegalArgumentException(
+                            "Unknown user authenticator: " + userAuthenticator);
+            }
+        }
+    }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({Origin.GENERATED, Origin.IMPORTED})
+    public @interface OriginEnum {}
+
+    /**
+     * Origin of the key.
+     */
+    public static abstract class Origin {
+        private Origin() {}
+
+        /** Key was generated inside AndroidKeyStore. */
+        public static final int GENERATED = 1 << 0;
+
+        /** Key was imported into AndroidKeyStore. */
+        public static final int IMPORTED = 1 << 1;
+
+        /**
+         * @hide
+         */
+        public static @OriginEnum int fromKeymaster(int origin) {
+            switch (origin) {
+                case KeymasterDefs.KM_ORIGIN_HARDWARE:
+                    return GENERATED;
+                case KeymasterDefs.KM_ORIGIN_IMPORTED:
+                    return IMPORTED;
+                default:
+                    throw new IllegalArgumentException("Unknown origin: " + origin);
+            }
+        }
+    }
+
+    private static int[] getSetFlags(int flags) {
+        if (flags == 0) {
+            return EmptyArray.INT;
+        }
+        int result[] = new int[getSetBitCount(flags)];
+        int resultOffset = 0;
+        int flag = 1;
+        while (flags != 0) {
+            if ((flags & 1) != 0) {
+                result[resultOffset] = flag;
+                resultOffset++;
+            }
+            flags >>>= 1;
+            flag <<= 1;
+        }
+        return result;
+    }
+
+    private static int getSetBitCount(int value) {
+        if (value == 0) {
+            return 0;
+        }
+        int result = 0;
+        while (value != 0) {
+            if ((value & 1) != 0) {
+                result++;
+            }
+            value >>>= 1;
+        }
+        return result;
+    }
+}
diff --git a/keystore/java/android/security/KeyStoreKeySpec.java b/keystore/java/android/security/KeyStoreKeySpec.java
index 65bb236..a89e4dd 100644
--- a/keystore/java/android/security/KeyStoreKeySpec.java
+++ b/keystore/java/android/security/KeyStoreKeySpec.java
@@ -22,24 +22,22 @@
 /**
  * Information about a key from the <a href="{@docRoot}training/articles/keystore.html">Android
  * KeyStore</a>.
- *
- * @hide
  */
 public class KeyStoreKeySpec implements KeySpec {
     private final String mKeystoreAlias;
     private final int mKeySize;
     private final boolean mTeeBacked;
-    private final @KeyStoreKeyCharacteristics.OriginEnum int mOrigin;
+    private final @KeyStoreKeyProperties.OriginEnum int mOrigin;
     private final Date mKeyValidityStart;
     private final Date mKeyValidityForOriginationEnd;
     private final Date mKeyValidityForConsumptionEnd;
-    private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
-    private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
-    private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
-    private final @KeyStoreKeyConstraints.DigestEnum int mDigests;
-    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
-    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
-    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mTeeEnforcedUserAuthenticators;
+    private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+    private final String[] mEncryptionPaddings;
+    private final String[] mSignaturePaddings;
+    private final String[] mDigests;
+    private final String[] mBlockModes;
+    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
+    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mTeeEnforcedUserAuthenticators;
     private final int mUserAuthenticationValidityDurationSeconds;
     private final boolean mInvalidatedOnNewFingerprintEnrolled;
 
@@ -48,18 +46,18 @@
      */
     KeyStoreKeySpec(String keystoreKeyAlias,
             boolean teeBacked,
-            @KeyStoreKeyCharacteristics.OriginEnum int origin,
+            @KeyStoreKeyProperties.OriginEnum int origin,
             int keySize,
             Date keyValidityStart,
             Date keyValidityForOriginationEnd,
             Date keyValidityForConsumptionEnd,
-            @KeyStoreKeyConstraints.PurposeEnum int purposes,
-            @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
-            @KeyStoreKeyConstraints.PaddingEnum int paddings,
-            @KeyStoreKeyConstraints.DigestEnum int digests,
-            @KeyStoreKeyConstraints.BlockModeEnum int blockModes,
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum int teeEnforcedUserAuthenticators,
+            @KeyStoreKeyProperties.PurposeEnum int purposes,
+            String[] encryptionPaddings,
+            String[] signaturePaddings,
+            String[] digests,
+            String[] blockModes,
+            @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
+            @KeyStoreKeyProperties.UserAuthenticatorEnum int teeEnforcedUserAuthenticators,
             int userAuthenticationValidityDurationSeconds,
             boolean invalidatedOnNewFingerprintEnrolled) {
         mKeystoreAlias = keystoreKeyAlias;
@@ -70,10 +68,12 @@
         mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
         mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
         mPurposes = purposes;
-        mAlgorithm = algorithm;
-        mPaddings = paddings;
-        mDigests = digests;
-        mBlockModes = blockModes;
+        mEncryptionPaddings =
+                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
+        mSignaturePaddings =
+                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
+        mDigests = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(digests));
+        mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
         mUserAuthenticators = userAuthenticators;
         mTeeEnforcedUserAuthenticators = teeEnforcedUserAuthenticators;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
@@ -98,7 +98,7 @@
     /**
      * Gets the origin of the key.
      */
-    public @KeyStoreKeyCharacteristics.OriginEnum int getOrigin() {
+    public @KeyStoreKeyProperties.OriginEnum int getOrigin() {
         return mOrigin;
     }
 
@@ -139,36 +139,36 @@
     /**
      * Gets the set of purposes for which the key can be used.
      */
-    public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
+    public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
         return mPurposes;
     }
 
     /**
-     * Gets the algorithm of the key.
-     */
-    public @KeyStoreKeyConstraints.AlgorithmEnum int getAlgorithm() {
-        return mAlgorithm;
-    }
-
-    /**
      * Gets the set of block modes with which the key can be used.
      */
-    public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
-        return mBlockModes;
+    public String[] getBlockModes() {
+        return ArrayUtils.cloneIfNotEmpty(mBlockModes);
     }
 
     /**
-     * Gets the set of padding modes with which the key can be used.
+     * Gets the set of padding modes with which the key can be used when encrypting/decrypting.
      */
-    public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
-        return mPaddings;
+    public String[] getEncryptionPaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
+    }
+
+    /**
+     * Gets the set of padding modes with which the key can be used when signing/verifying.
+     */
+    public String[] getSignaturePaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
     }
 
     /**
      * Gets the set of digest algorithms with which the key can be used.
      */
-    public @KeyStoreKeyConstraints.DigestEnum int getDigests() {
-        return mDigests;
+    public String[] getDigests() {
+        return ArrayUtils.cloneIfNotEmpty(mDigests);
     }
 
     /**
@@ -177,7 +177,7 @@
      *
      * @return user authenticators or {@code 0} if the key can be used without user authentication.
      */
-    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
+    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
         return mUserAuthenticators;
     }
 
@@ -186,7 +186,7 @@
      * key. This is a subset of the user authentications returned by
      * {@link #getUserAuthenticators()}.
      */
-    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getTeeEnforcedUserAuthenticators() {
+    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getTeeEnforcedUserAuthenticators() {
         return mTeeEnforcedUserAuthenticators;
     }
 
diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
index 751eef5..c24b74f 100644
--- a/keystore/java/android/security/KeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -43,12 +43,13 @@
     private final Date mKeyValidityStart;
     private final Date mKeyValidityForOriginationEnd;
     private final Date mKeyValidityForConsumptionEnd;
-    private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
-    private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
-    private final @KeyStoreKeyConstraints.DigestEnum Integer mDigests;
-    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+    private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+    private final String[] mEncryptionPaddings;
+    private final String[] mSignaturePaddings;
+    private final String[] mDigests;
+    private final String[] mBlockModes;
     private final boolean mRandomizedEncryptionRequired;
-    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
     private final int mUserAuthenticationValidityDurationSeconds;
     private final boolean mInvalidatedOnNewFingerprintEnrolled;
 
@@ -56,12 +57,13 @@
             Date keyValidityStart,
             Date keyValidityForOriginationEnd,
             Date keyValidityForConsumptionEnd,
-            @KeyStoreKeyConstraints.PurposeEnum int purposes,
-            @KeyStoreKeyConstraints.PaddingEnum int paddings,
-            @KeyStoreKeyConstraints.DigestEnum Integer digests,
-            @KeyStoreKeyConstraints.BlockModeEnum int blockModes,
+            @KeyStoreKeyProperties.PurposeEnum int purposes,
+            String[] encryptionPaddings,
+            String[] signaturePaddings,
+            String[] digests,
+            String[] blockModes,
             boolean randomizedEncryptionRequired,
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
+            @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
             int userAuthenticationValidityDurationSeconds,
             boolean invalidatedOnNewFingerprintEnrolled) {
         if ((userAuthenticationValidityDurationSeconds < 0)
@@ -75,9 +77,12 @@
         mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
         mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
         mPurposes = purposes;
-        mPaddings = paddings;
-        mDigests = digests;
-        mBlockModes = blockModes;
+        mEncryptionPaddings =
+                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
+        mSignaturePaddings =
+                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
+        mDigests = ArrayUtils.cloneIfNotEmpty(digests);
+        mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
         mRandomizedEncryptionRequired = randomizedEncryptionRequired;
         mUserAuthenticators = userAuthenticators;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
@@ -103,7 +108,6 @@
      * Gets the time instant before which the key is not yet valid.
      *
      * @return instant or {@code null} if not restricted.
-     * @hide
      */
     public Date getKeyValidityStart() {
         return mKeyValidityStart;
@@ -113,8 +117,6 @@
      * Gets the time instant after which the key is no long valid for decryption and verification.
      *
      * @return instant or {@code null} if not restricted.
-     *
-     * @hide
      */
     public Date getKeyValidityForConsumptionEnd() {
         return mKeyValidityForConsumptionEnd;
@@ -124,8 +126,6 @@
      * Gets the time instant after which the key is no long valid for encryption and signing.
      *
      * @return instant or {@code null} if not restricted.
-     *
-     * @hide
      */
     public Date getKeyValidityForOriginationEnd() {
         return mKeyValidityForOriginationEnd;
@@ -133,56 +133,55 @@
 
     /**
      * Gets the set of purposes for which the key can be used.
-     *
-     * @hide
      */
-    public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
+    public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
         return mPurposes;
     }
 
     /**
-     * Gets the set of padding schemes to which the key is restricted.
-     *
-     * @hide
+     * Gets the set of padding schemes with which the key can be used when encrypting/decrypting.
      */
-    public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
-        return mPaddings;
+    public String[] getEncryptionPaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
     }
 
     /**
-     * Gets the set of digests to which the key is restricted.
+     * Gets the set of padding schemes with which the key can be used when signing or verifying
+     * signatures.
+     */
+    public String[] getSignaturePaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
+    }
+
+    /**
+     * Gets the set of digest algorithms with which the key can be used.
      *
-     * @throws IllegalStateException if this restriction has not been specified.
+     * @throws IllegalStateException if this set has not been specified.
      *
      * @see #isDigestsSpecified()
-     *
-     * @hide
      */
-    public @KeyStoreKeyConstraints.DigestEnum int getDigests() {
+    public String[] getDigests() {
         if (mDigests == null) {
             throw new IllegalStateException("Digests not specified");
         }
-        return mDigests;
+        return ArrayUtils.cloneIfNotEmpty(mDigests);
     }
 
     /**
-     * Returns {@code true} if digest restrictions have been specified.
+     * Returns {@code true} if the set of digest algorithms with which the key can be used has been
+     * specified.
      *
      * @see #getDigests()
-     *
-     * @hide
      */
     public boolean isDigestsSpecified() {
         return mDigests != null;
     }
 
     /**
-     * Gets the set of block modes to which the key is restricted.
-     *
-     * @hide
+     * Gets the set of block modes with which the key can be used.
      */
-    public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
-        return mBlockModes;
+    public String[] getBlockModes() {
+        return ArrayUtils.cloneIfNotEmpty(mBlockModes);
     }
 
     /**
@@ -193,8 +192,6 @@
      * weaknesses due to which ciphertext may leak information about plaintext. For example, if a
      * given plaintext always produces the same ciphertext, an attacker may see the repeated
      * ciphertexts and be able to deduce something about the plaintext.
-     *
-     * @hide
      */
     public boolean isRandomizedEncryptionRequired() {
         return mRandomizedEncryptionRequired;
@@ -205,10 +202,8 @@
      * used iff the user has authenticated to at least one of these user authenticators.
      *
      * @return user authenticators or {@code 0} if the key can be used without user authentication.
-     *
-     * @hide
      */
-    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
+    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
         return mUserAuthenticators;
     }
 
@@ -218,8 +213,6 @@
      *
      * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
      *         is required for every use of the key.
-     *
-     * @hide
      */
     public int getUserAuthenticationValidityDurationSeconds() {
         return mUserAuthenticationValidityDurationSeconds;
@@ -231,8 +224,6 @@
      * authenticators protecting access to this key.
      *
      * @see #getUserAuthenticators()
-     *
-     * @hide
      */
     public boolean isInvalidatedOnNewFingerprintEnrolled() {
         return mInvalidatedOnNewFingerprintEnrolled;
@@ -260,12 +251,13 @@
         private Date mKeyValidityStart;
         private Date mKeyValidityForOriginationEnd;
         private Date mKeyValidityForConsumptionEnd;
-        private @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
-        private @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
-        private @KeyStoreKeyConstraints.DigestEnum Integer mDigests;
-        private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+        private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+        private String[] mEncryptionPaddings;
+        private String[] mSignaturePaddings;
+        private String[] mDigests;
+        private String[] mBlockModes;
         private boolean mRandomizedEncryptionRequired = true;
-        private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+        private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
         private int mUserAuthenticationValidityDurationSeconds = -1;
         private boolean mInvalidatedOnNewFingerprintEnrolled;
 
@@ -304,8 +296,6 @@
          * <p>By default, the key is valid at any instant.
          *
          * @see #setKeyValidityEnd(Date)
-         *
-         * @hide
          */
         public Builder setKeyValidityStart(Date startDate) {
             mKeyValidityStart = startDate;
@@ -320,8 +310,6 @@
          * @see #setKeyValidityStart(Date)
          * @see #setKeyValidityForConsumptionEnd(Date)
          * @see #setKeyValidityForOriginationEnd(Date)
-         *
-         * @hide
          */
         public Builder setKeyValidityEnd(Date endDate) {
             setKeyValidityForOriginationEnd(endDate);
@@ -335,8 +323,6 @@
          * <p>By default, the key is valid at any instant.
          *
          * @see #setKeyValidityForConsumptionEnd(Date)
-         *
-         * @hide
          */
         public Builder setKeyValidityForOriginationEnd(Date endDate) {
             mKeyValidityForOriginationEnd = endDate;
@@ -350,8 +336,6 @@
          * <p>By default, the key is valid at any instant.
          *
          * @see #setKeyValidityForOriginationEnd(Date)
-         *
-         * @hide
          */
         public Builder setKeyValidityForConsumptionEnd(Date endDate) {
             mKeyValidityForConsumptionEnd = endDate;
@@ -359,55 +343,60 @@
         }
 
         /**
-         * Restricts the key to being used only for the provided set of purposes.
+         * Sets the set of purposes for which the key can be used.
          *
-         * <p>This restriction must be specified. There is no default.
-         *
-         * @hide
+         * <p>This must be specified for all keys. There is no default.
          */
-        public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
+        public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
             mPurposes = purposes;
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided padding schemes. Attempts to use
-         * the key with any other padding will be rejected.
+         * Sets the set of padding schemes with which the key can be used when
+         * encrypting/decrypting. Attempts to use the key with any other padding scheme will be
+         * rejected.
          *
-         * <p>This restriction must be specified for keys which are used for encryption/decryption.
-         *
-         * @hide
+         * <p>This must be specified for keys which are used for encryption/decryption.
          */
-        public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) {
-            mPaddings = paddings;
+        public Builder setEncryptionPaddings(String... paddings) {
+            mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided digests when generating signatures
-         * or HMACs. Attempts to use the key with any other digest will be rejected.
+         * Sets the set of padding schemes with which the key can be used when
+         * signing/verifying. Attempts to use the key with any other padding scheme will be
+         * rejected.
          *
-         * <p>For HMAC keys, the default is to restrict to the digest specified in
-         * {@link Key#getAlgorithm()}. For asymmetric signing keys this constraint must be specified
-         * because there is no default.
-         *
-         * @hide
+         * <p>This must be specified for RSA keys which are used for signing/verification.
          */
-        public Builder setDigests(@KeyStoreKeyConstraints.DigestEnum int digests) {
-            mDigests = digests;
+        public Builder setSignaturePaddings(String... paddings) {
+            mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
+            return this;
+        }
+
+
+        /**
+         * Sets the set of digests with which the key can be used when signing/verifying or
+         * generating MACs. Attempts to use the key with any other digest will be rejected.
+         *
+         * <p>For HMAC keys, the default is the digest specified in {@link Key#getAlgorithm()}. For
+         * asymmetric signing keys this constraint must be specified.
+         */
+        public Builder setDigests(String... digests) {
+            mDigests = ArrayUtils.cloneIfNotEmpty(digests);
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided block modes. Attempts to use the
-         * key with any other block modes will be rejected.
+         * Sets the set of block modes with which the key can be used when encrypting/decrypting.
+         * Attempts to use the key with any other block modes will be rejected.
          *
-         * <p>This restriction must be specified for symmetric encryption/decryption keys.
-         *
-         * @hide
+         * <p>This must be specified for encryption/decryption keys.
          */
-        public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) {
-            mBlockModes = blockModes;
+        public Builder setBlockModes(String... blockModes) {
+            mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
             return this;
         }
 
@@ -444,8 +433,6 @@
          * <li>If you are using RSA encryption without padding, consider switching to padding
          * schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
          * </ul>
-         *
-         * @hide
          */
         public Builder setRandomizedEncryptionRequired(boolean required) {
             mRandomizedEncryptionRequired = required;
@@ -462,11 +449,9 @@
          *        without user authentication.
          *
          * @see #setUserAuthenticationValidityDurationSeconds(int)
-         *
-         * @hide
          */
         public Builder setUserAuthenticators(
-                @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
+                @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
             mUserAuthenticators = userAuthenticators;
             return this;
         }
@@ -481,8 +466,6 @@
          *        every use of the key.
          *
          * @see #setUserAuthenticators(int)
-         *
-         * @hide
          */
         public Builder setUserAuthenticationValidityDurationSeconds(int seconds) {
             mUserAuthenticationValidityDurationSeconds = seconds;
@@ -497,8 +480,6 @@
          * <p>By default, enrolling a new fingerprint does not invalidate the key.
          *
          * @see #setUserAuthenticators(Set)
-         *
-         * @hide
          */
         public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
             mInvalidatedOnNewFingerprintEnrolled = invalidated;
@@ -517,7 +498,8 @@
                     mKeyValidityForOriginationEnd,
                     mKeyValidityForConsumptionEnd,
                     mPurposes,
-                    mPaddings,
+                    mEncryptionPaddings,
+                    mSignaturePaddings,
                     mDigests,
                     mBlockModes,
                     mRandomizedEncryptionRequired,
diff --git a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
index a5e87d1..4be0638 100644
--- a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
@@ -19,10 +19,14 @@
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterDefs;
 
+import libcore.util.EmptyArray;
+
 import java.security.InvalidKeyException;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.KeySpec;
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.List;
 
 import javax.crypto.SecretKey;
 import javax.crypto.SecretKeyFactorySpi;
@@ -71,84 +75,90 @@
         }
 
         boolean teeBacked;
-        @KeyStoreKeyCharacteristics.OriginEnum int origin;
+        @KeyStoreKeyProperties.OriginEnum int origin;
         int keySize;
-        @KeyStoreKeyConstraints.PurposeEnum int purposes;
-        @KeyStoreKeyConstraints.AlgorithmEnum int algorithm;
-        @KeyStoreKeyConstraints.PaddingEnum int paddings;
-        @KeyStoreKeyConstraints.DigestEnum int digests;
-        @KeyStoreKeyConstraints.BlockModeEnum int blockModes;
-        @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators;
-        @KeyStoreKeyConstraints.UserAuthenticatorEnum int teeEnforcedUserAuthenticators;
+        @KeyStoreKeyProperties.PurposeEnum int purposes;
+        String[] encryptionPaddings;
+        String[] digests;
+        String[] blockModes;
+        @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators;
+        @KeyStoreKeyProperties.UserAuthenticatorEnum int teeEnforcedUserAuthenticators;
         try {
             if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
                 teeBacked = true;
-                origin = KeyStoreKeyCharacteristics.Origin.fromKeymaster(
+                origin = KeyStoreKeyProperties.Origin.fromKeymaster(
                         keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
             } else if (keyCharacteristics.swEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
                 teeBacked = false;
-                origin = KeyStoreKeyCharacteristics.Origin.fromKeymaster(
+                origin = KeyStoreKeyProperties.Origin.fromKeymaster(
                         keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
             } else {
                 throw new InvalidKeySpecException("Key origin not available");
             }
-            Integer keySizeInteger =
-                    KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_KEY_SIZE);
+            Integer keySizeInteger = keyCharacteristics.getInteger(KeymasterDefs.KM_TAG_KEY_SIZE);
             if (keySizeInteger == null) {
                 throw new InvalidKeySpecException("Key size not available");
             }
             keySize = keySizeInteger;
-            purposes = KeyStoreKeyConstraints.Purpose.allFromKeymaster(
-                    KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_PURPOSE));
-            Integer alg = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_ALGORITHM);
-            if (alg == null) {
-                throw new InvalidKeySpecException("Key algorithm not available");
-            }
-            algorithm = KeyStoreKeyConstraints.Algorithm.fromKeymaster(alg);
-            paddings = KeyStoreKeyConstraints.Padding.allFromKeymaster(
-                    KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_PADDING));
-            digests = KeyStoreKeyConstraints.Digest.allFromKeymaster(
-                    KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_DIGEST));
-            blockModes = KeyStoreKeyConstraints.BlockMode.allFromKeymaster(
-                    KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_BLOCK_MODE));
+            purposes = KeyStoreKeyProperties.Purpose.allFromKeymaster(
+                    keyCharacteristics.getInts(KeymasterDefs.KM_TAG_PURPOSE));
 
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum
+            List<String> encryptionPaddingsList = new ArrayList<String>();
+            for (int keymasterPadding : keyCharacteristics.getInts(KeymasterDefs.KM_TAG_PADDING)) {
+                String jcaPadding;
+                try {
+                    jcaPadding = KeymasterUtils.getJcaEncryptionPaddingFromKeymasterPadding(
+                            keymasterPadding);
+                } catch (IllegalArgumentException e) {
+                    throw new InvalidKeySpecException(
+                            "Unsupported encryption padding: " + keymasterPadding);
+                }
+                encryptionPaddingsList.add(jcaPadding);
+            }
+            encryptionPaddings =
+                    encryptionPaddingsList.toArray(new String[encryptionPaddingsList.size()]);
+
+            digests = KeymasterUtils.getJcaDigestAlgorithmsFromKeymasterDigests(
+                    keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST));
+            blockModes = KeymasterUtils.getJcaBlockModesFromKeymasterBlockModes(
+                    keyCharacteristics.getInts(KeymasterDefs.KM_TAG_BLOCK_MODE));
+
+            @KeyStoreKeyProperties.UserAuthenticatorEnum
             int swEnforcedKeymasterUserAuthenticators =
                     keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum
+            @KeyStoreKeyProperties.UserAuthenticatorEnum
             int hwEnforcedKeymasterUserAuthenticators =
                     keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum
+            @KeyStoreKeyProperties.UserAuthenticatorEnum
             int keymasterUserAuthenticators =
                     swEnforcedKeymasterUserAuthenticators | hwEnforcedKeymasterUserAuthenticators;
-            userAuthenticators = KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(
+            userAuthenticators = KeyStoreKeyProperties.UserAuthenticator.allFromKeymaster(
                     keymasterUserAuthenticators);
             teeEnforcedUserAuthenticators =
-                    KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(
+                    KeyStoreKeyProperties.UserAuthenticator.allFromKeymaster(
                             hwEnforcedKeymasterUserAuthenticators);
         } catch (IllegalArgumentException e) {
             throw new InvalidKeySpecException("Unsupported key characteristic", e);
         }
 
-        Date keyValidityStart =
-                KeymasterUtils.getDate(keyCharacteristics, KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
+        Date keyValidityStart = keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
         if ((keyValidityStart != null) && (keyValidityStart.getTime() <= 0)) {
             keyValidityStart = null;
         }
-        Date keyValidityForOriginationEnd = KeymasterUtils.getDate(keyCharacteristics,
-                KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
+        Date keyValidityForOriginationEnd =
+                keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
         if ((keyValidityForOriginationEnd != null)
                 && (keyValidityForOriginationEnd.getTime() == Long.MAX_VALUE)) {
             keyValidityForOriginationEnd = null;
         }
-        Date keyValidityForConsumptionEnd = KeymasterUtils.getDate(keyCharacteristics,
-                KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
+        Date keyValidityForConsumptionEnd =
+                keyCharacteristics.getDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
         if ((keyValidityForConsumptionEnd != null)
                 && (keyValidityForConsumptionEnd.getTime() == Long.MAX_VALUE)) {
             keyValidityForConsumptionEnd = null;
         }
-        Integer userAuthenticationValidityDurationSeconds =
-                KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_AUTH_TIMEOUT);
+        int userAuthenticationValidityDurationSeconds =
+                keyCharacteristics.getInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, -1);
 
         // TODO: Populate the value below from key characteristics once Keymaster is ready.
         boolean invalidatedOnNewFingerprintEnrolled = false;
@@ -161,14 +171,13 @@
                 keyValidityForOriginationEnd,
                 keyValidityForConsumptionEnd,
                 purposes,
-                algorithm,
-                paddings,
+                encryptionPaddings,
+                EmptyArray.STRING, // no signature paddings -- this is symmetric crypto
                 digests,
                 blockModes,
                 userAuthenticators,
                 teeEnforcedUserAuthenticators,
-                ((userAuthenticationValidityDurationSeconds != null)
-                        ? userAuthenticationValidityDurationSeconds : -1),
+                userAuthenticationValidityDurationSeconds,
                 invalidatedOnNewFingerprintEnrolled);
     }
 
diff --git a/keystore/java/android/security/KeymasterUtils.java b/keystore/java/android/security/KeymasterUtils.java
index 3143d4d..67f75c2 100644
--- a/keystore/java/android/security/KeymasterUtils.java
+++ b/keystore/java/android/security/KeymasterUtils.java
@@ -16,48 +16,327 @@
 
 package android.security;
 
-import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterDefs;
 
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
+import libcore.util.EmptyArray;
+
+import java.util.Collection;
+import java.util.Locale;
 
 /**
  * @hide
  */
 public abstract class KeymasterUtils {
+
     private KeymasterUtils() {}
 
-    public static Integer getInt(KeyCharacteristics keyCharacteristics, int tag) {
-        if (keyCharacteristics.hwEnforced.containsTag(tag)) {
-            return keyCharacteristics.hwEnforced.getInt(tag, -1);
-        } else if (keyCharacteristics.swEnforced.containsTag(tag)) {
-            return keyCharacteristics.swEnforced.getInt(tag, -1);
+    public static int getKeymasterAlgorithmFromJcaSecretKeyAlgorithm(String jcaKeyAlgorithm) {
+        if ("AES".equalsIgnoreCase(jcaKeyAlgorithm)) {
+            return KeymasterDefs.KM_ALGORITHM_AES;
+        } else if (jcaKeyAlgorithm.toUpperCase(Locale.US).startsWith("HMAC")) {
+            return KeymasterDefs.KM_ALGORITHM_HMAC;
         } else {
-            return null;
+            throw new IllegalArgumentException(
+                    "Unsupported secret key algorithm: " + jcaKeyAlgorithm);
         }
     }
 
-    public static List<Integer> getInts(KeyCharacteristics keyCharacteristics, int tag) {
-        List<Integer> result = new ArrayList<Integer>();
-        result.addAll(keyCharacteristics.hwEnforced.getInts(tag));
-        result.addAll(keyCharacteristics.swEnforced.getInts(tag));
-        return result;
+    public static String getJcaSecretKeyAlgorithm(int keymasterAlgorithm, int keymasterDigest) {
+        switch (keymasterAlgorithm) {
+            case KeymasterDefs.KM_ALGORITHM_AES:
+                if (keymasterDigest != -1) {
+                    throw new IllegalArgumentException(
+                            "Digest not supported for AES key: " + keymasterDigest);
+                }
+                return "AES";
+            case KeymasterDefs.KM_ALGORITHM_HMAC:
+                switch (keymasterDigest) {
+                    case KeymasterDefs.KM_DIGEST_SHA1:
+                        return "HmacSHA1";
+                    case KeymasterDefs.KM_DIGEST_SHA_2_224:
+                        return "HmacSHA224";
+                    case KeymasterDefs.KM_DIGEST_SHA_2_256:
+                        return "HmacSHA256";
+                    case KeymasterDefs.KM_DIGEST_SHA_2_384:
+                        return "HmacSHA384";
+                    case KeymasterDefs.KM_DIGEST_SHA_2_512:
+                        return "HmacSHA512";
+                    default:
+                        throw new IllegalArgumentException(
+                                "Unsupported HMAC digest: " + keymasterDigest);
+                }
+            default:
+                throw new IllegalArgumentException("Unsupported algorithm: " + keymasterAlgorithm);
+        }
     }
 
-    public static Date getDate(KeyCharacteristics keyCharacteristics, int tag) {
-        Date result = keyCharacteristics.hwEnforced.getDate(tag, null);
-        if (result == null) {
-            result = keyCharacteristics.swEnforced.getDate(tag, null);
+    public static String getJcaKeyPairAlgorithmFromKeymasterAlgorithm(int keymasterAlgorithm) {
+        switch (keymasterAlgorithm) {
+            case KeymasterDefs.KM_ALGORITHM_RSA:
+                return "RSA";
+            case KeymasterDefs.KM_ALGORITHM_EC:
+                return "EC";
+            default:
+                throw new IllegalArgumentException("Unsupported algorithm: " + keymasterAlgorithm);
+        }
+    }
+
+    public static int getKeymasterDigestfromJcaSecretKeyAlgorithm(String jcaKeyAlgorithm) {
+        String algorithmUpper = jcaKeyAlgorithm.toUpperCase(Locale.US);
+        if (algorithmUpper.startsWith("HMAC")) {
+            String digestUpper = algorithmUpper.substring("HMAC".length());
+            switch (digestUpper) {
+                case "MD5":
+                    return KeymasterDefs.KM_DIGEST_MD5;
+                case "SHA1":
+                    return KeymasterDefs.KM_DIGEST_SHA1;
+                case "SHA224":
+                    return KeymasterDefs.KM_DIGEST_SHA_2_224;
+                case "SHA256":
+                    return KeymasterDefs.KM_DIGEST_SHA_2_256;
+                case "SHA384":
+                    return KeymasterDefs.KM_DIGEST_SHA_2_384;
+                case "SHA512":
+                    return KeymasterDefs.KM_DIGEST_SHA_2_512;
+                default:
+                    throw new IllegalArgumentException("Unsupported HMAC digest: " + digestUpper);
+            }
+        } else {
+            return -1;
+        }
+    }
+
+    public static int getKeymasterDigestFromJcaDigestAlgorithm(String jcaDigestAlgorithm) {
+        if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-1")) {
+            return KeymasterDefs.KM_DIGEST_SHA1;
+        } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-224")) {
+            return KeymasterDefs.KM_DIGEST_SHA_2_224;
+        } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-256")) {
+            return KeymasterDefs.KM_DIGEST_SHA_2_256;
+        } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-384")) {
+            return KeymasterDefs.KM_DIGEST_SHA_2_384;
+        } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-512")) {
+            return KeymasterDefs.KM_DIGEST_SHA_2_512;
+        } else if (jcaDigestAlgorithm.equalsIgnoreCase("NONE")) {
+            return KeymasterDefs.KM_DIGEST_NONE;
+        } else if (jcaDigestAlgorithm.equalsIgnoreCase("MD5")) {
+            return KeymasterDefs.KM_DIGEST_MD5;
+        } else {
+            throw new IllegalArgumentException(
+                    "Unsupported digest algorithm: " + jcaDigestAlgorithm);
+        }
+    }
+
+    public static String getJcaDigestAlgorithmFromKeymasterDigest(int keymasterDigest) {
+        switch (keymasterDigest) {
+            case KeymasterDefs.KM_DIGEST_NONE:
+                return "NONE";
+            case KeymasterDefs.KM_DIGEST_MD5:
+                return "MD5";
+            case KeymasterDefs.KM_DIGEST_SHA1:
+                return "SHA-1";
+            case KeymasterDefs.KM_DIGEST_SHA_2_224:
+                return "SHA-224";
+            case KeymasterDefs.KM_DIGEST_SHA_2_256:
+                return "SHA-256";
+            case KeymasterDefs.KM_DIGEST_SHA_2_384:
+                return "SHA-384";
+            case KeymasterDefs.KM_DIGEST_SHA_2_512:
+                return "SHA-512";
+            default:
+                throw new IllegalArgumentException(
+                        "Unsupported digest algorithm: " + keymasterDigest);
+        }
+    }
+
+    public static String[] getJcaDigestAlgorithmsFromKeymasterDigests(
+            Collection<Integer> keymasterDigests) {
+        if (keymasterDigests.isEmpty()) {
+            return EmptyArray.STRING;
+        }
+        String[] result = new String[keymasterDigests.size()];
+        int offset = 0;
+        for (int keymasterDigest : keymasterDigests) {
+            result[offset] = getJcaDigestAlgorithmFromKeymasterDigest(keymasterDigest);
+            offset++;
         }
         return result;
     }
 
-    public static boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) {
-        if (keyCharacteristics.hwEnforced.containsTag(tag)) {
-            return keyCharacteristics.hwEnforced.getBoolean(tag, false);
-        } else {
-            return keyCharacteristics.swEnforced.getBoolean(tag, false);
+    public static int[] getKeymasterDigestsFromJcaDigestAlgorithms(String[] jcaDigestAlgorithms) {
+        if ((jcaDigestAlgorithms == null) || (jcaDigestAlgorithms.length == 0)) {
+            return EmptyArray.INT;
         }
+        int[] result = new int[jcaDigestAlgorithms.length];
+        int offset = 0;
+        for (String jcaDigestAlgorithm : jcaDigestAlgorithms) {
+            result[offset] = getKeymasterDigestFromJcaDigestAlgorithm(jcaDigestAlgorithm);
+            offset++;
+        }
+        return result;
+    }
+
+    public static int getDigestOutputSizeBytes(int keymasterDigest) {
+        switch (keymasterDigest) {
+            case KeymasterDefs.KM_DIGEST_NONE:
+                return -1;
+            case KeymasterDefs.KM_DIGEST_MD5:
+                return 128 / 8;
+            case KeymasterDefs.KM_DIGEST_SHA1:
+                return 160 / 8;
+            case KeymasterDefs.KM_DIGEST_SHA_2_224:
+                return 224 / 8;
+            case KeymasterDefs.KM_DIGEST_SHA_2_256:
+                return 256 / 8;
+            case KeymasterDefs.KM_DIGEST_SHA_2_384:
+                return 384 / 8;
+            case KeymasterDefs.KM_DIGEST_SHA_2_512:
+                return 512 / 8;
+            default:
+                throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
+        }
+    }
+
+    public static int getKeymasterBlockModeFromJcaBlockMode(String jcaBlockMode) {
+        if ("ECB".equalsIgnoreCase(jcaBlockMode)) {
+            return KeymasterDefs.KM_MODE_ECB;
+        } else if ("CBC".equalsIgnoreCase(jcaBlockMode)) {
+            return KeymasterDefs.KM_MODE_CBC;
+        } else if ("CTR".equalsIgnoreCase(jcaBlockMode)) {
+            return KeymasterDefs.KM_MODE_CTR;
+        } else if ("GCM".equalsIgnoreCase(jcaBlockMode)) {
+            return KeymasterDefs.KM_MODE_GCM;
+        } else {
+            throw new IllegalArgumentException("Unsupported block mode: " + jcaBlockMode);
+        }
+    }
+
+    public static String getJcaBlockModeFromKeymasterBlockMode(int keymasterBlockMode) {
+        switch (keymasterBlockMode) {
+            case KeymasterDefs.KM_MODE_ECB:
+                return "ECB";
+            case KeymasterDefs.KM_MODE_CBC:
+                return "CBC";
+            case KeymasterDefs.KM_MODE_CTR:
+                return "CTR";
+            case KeymasterDefs.KM_MODE_GCM:
+                return "GCM";
+            default:
+                throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
+        }
+    }
+
+    public static String[] getJcaBlockModesFromKeymasterBlockModes(
+            Collection<Integer> keymasterBlockModes) {
+        if ((keymasterBlockModes == null) || (keymasterBlockModes.isEmpty())) {
+            return EmptyArray.STRING;
+        }
+        String[] result = new String[keymasterBlockModes.size()];
+        int offset = 0;
+        for (int keymasterBlockMode : keymasterBlockModes) {
+            result[offset] = getJcaBlockModeFromKeymasterBlockMode(keymasterBlockMode);
+            offset++;
+        }
+        return result;
+    }
+
+    public static int[] getKeymasterBlockModesFromJcaBlockModes(String[] jcaBlockModes) {
+        if ((jcaBlockModes == null) || (jcaBlockModes.length == 0)) {
+            return EmptyArray.INT;
+        }
+        int[] result = new int[jcaBlockModes.length];
+        for (int i = 0; i < jcaBlockModes.length; i++) {
+            result[i] = getKeymasterBlockModeFromJcaBlockMode(jcaBlockModes[i]);
+        }
+        return result;
+    }
+
+    public static boolean isKeymasterBlockModeIndCpaCompatible(int keymasterBlockMode) {
+        switch (keymasterBlockMode) {
+            case KeymasterDefs.KM_MODE_ECB:
+                return false;
+            case KeymasterDefs.KM_MODE_CBC:
+            case KeymasterDefs.KM_MODE_CTR:
+            case KeymasterDefs.KM_MODE_GCM:
+                return true;
+            default:
+                throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
+        }
+    }
+
+    public static int getKeymasterPaddingFromJcaEncryptionPadding(String jcaPadding) {
+        if ("NoPadding".equalsIgnoreCase(jcaPadding)) {
+            return KeymasterDefs.KM_PAD_NONE;
+        } else if ("PKCS7Padding".equalsIgnoreCase(jcaPadding)) {
+            return KeymasterDefs.KM_PAD_PKCS7;
+        } else if ("PKCS1Padding".equalsIgnoreCase(jcaPadding)) {
+            return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
+        } else if ("OEAPPadding".equalsIgnoreCase(jcaPadding)) {
+            return KeymasterDefs.KM_PAD_RSA_OAEP;
+        } else {
+            throw new IllegalArgumentException(
+                    "Unsupported encryption padding scheme: " + jcaPadding);
+        }
+    }
+
+    public static String getJcaEncryptionPaddingFromKeymasterPadding(int keymasterPadding) {
+        switch (keymasterPadding) {
+            case KeymasterDefs.KM_PAD_NONE:
+                return "NoPadding";
+            case KeymasterDefs.KM_PAD_PKCS7:
+                return "PKCS7Padding";
+            case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+                return "PKCS1Padding";
+            case KeymasterDefs.KM_PAD_RSA_OAEP:
+                return "OEAPPadding";
+            default:
+                throw new IllegalArgumentException(
+                        "Unsupported encryption padding: " + keymasterPadding);
+        }
+    }
+
+    public static int getKeymasterPaddingFromJcaSignaturePadding(String jcaPadding) {
+        if ("PKCS#1".equalsIgnoreCase(jcaPadding)) {
+            return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN;
+        } if ("PSS".equalsIgnoreCase(jcaPadding)) {
+            return KeymasterDefs.KM_PAD_RSA_PSS;
+        } else {
+            throw new IllegalArgumentException(
+                    "Unsupported signature padding scheme: " + jcaPadding);
+        }
+    }
+
+    public static String getJcaSignaturePaddingFromKeymasterPadding(int keymasterPadding) {
+        switch (keymasterPadding) {
+            case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN:
+                return "PKCS#1";
+            case KeymasterDefs.KM_PAD_RSA_PSS:
+                return "PSS";
+            default:
+                throw new IllegalArgumentException(
+                        "Unsupported signature padding: " + keymasterPadding);
+        }
+    }
+
+    public static int[] getKeymasterPaddingsFromJcaEncryptionPaddings(String[] jcaPaddings) {
+        if ((jcaPaddings == null) || (jcaPaddings.length == 0)) {
+            return EmptyArray.INT;
+        }
+        int[] result = new int[jcaPaddings.length];
+        for (int i = 0; i < jcaPaddings.length; i++) {
+            result[i] = getKeymasterPaddingFromJcaEncryptionPadding(jcaPaddings[i]);
+        }
+        return result;
+    }
+
+    public static int[] getKeymasterPaddingsFromJcaSignaturePaddings(String[] jcaPaddings) {
+        if ((jcaPaddings == null) || (jcaPaddings.length == 0)) {
+            return EmptyArray.INT;
+        }
+        int[] result = new int[jcaPaddings.length];
+        for (int i = 0; i < jcaPaddings.length; i++) {
+            result[i] = getKeymasterPaddingFromJcaSignaturePadding(jcaPaddings[i]);
+        }
+        return result;
     }
 }
diff --git a/keystore/java/android/security/NewFingerprintEnrolledException.java b/keystore/java/android/security/NewFingerprintEnrolledException.java
index 6da4a2a..806b214 100644
--- a/keystore/java/android/security/NewFingerprintEnrolledException.java
+++ b/keystore/java/android/security/NewFingerprintEnrolledException.java
@@ -19,8 +19,6 @@
 /**
  * Indicates that a cryptographic operation could not be performed because the key used by the
  * operation is permanently invalid because a new fingerprint was enrolled.
- *
- * @hide
  */
 public class NewFingerprintEnrolledException extends CryptoOperationException {
 
diff --git a/keystore/java/android/security/UserNotAuthenticatedException.java b/keystore/java/android/security/UserNotAuthenticatedException.java
index e6342ef..f5f5f41 100644
--- a/keystore/java/android/security/UserNotAuthenticatedException.java
+++ b/keystore/java/android/security/UserNotAuthenticatedException.java
@@ -19,8 +19,6 @@
 /**
  * Indicates that a cryptographic operation could not be performed because the user has not been
  * authenticated recently enough.
- *
- * @hide
  */
 public class UserNotAuthenticatedException extends CryptoOperationException {
 
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index b7a851f..fc0189c 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -53,6 +53,12 @@
     //---------------------------------------------------------
     // Constants
     //--------------------
+
+    /** Minimum value for sample rate */
+    private static final int SAMPLE_RATE_HZ_MIN = 4000;
+    /** Maximum value for sample rate */
+    private static final int SAMPLE_RATE_HZ_MAX = 96000;
+
     /**
      *  indicates AudioRecord state is not successfully initialized.
      */
@@ -571,7 +577,7 @@
 
         //--------------
         // sample rate
-        if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
+        if ((sampleRateInHz < SAMPLE_RATE_HZ_MIN) || (sampleRateInHz > SAMPLE_RATE_HZ_MAX)) {
             throw new IllegalArgumentException(sampleRateInHz
                     + "Hz is not a supported sample rate.");
         }
diff --git a/media/java/android/media/midi/package.html b/media/java/android/media/midi/package.html
new file mode 100644
index 0000000..9e7e8b1
--- /dev/null
+++ b/media/java/android/media/midi/package.html
@@ -0,0 +1,324 @@
+<html>
+<body>
+<p>Android MIDI User Guide</p>
+
+<h1 id=overview>Overview</h1>
+
+
+<p>This document describes how to use the Android MIDI API in Java.</p>
+
+<p>The Android MIDI package allows users to:</p>
+
+<ul>
+  <li> Connect a MIDI keyboard to Android to play a synthesizer or drive music apps.
+  <li> Connect alternative MIDI controllers to Android.
+  <li> Drive external MIDI synths from Android.
+  <li> Drive external peripherals, lights, show control, etc from Android.
+  <li> Generate music dynamically from games or music creation apps.
+  <li> Generate MIDI messages in one app and send them to a second app.
+  <li> Use an Android device running in <em>peripheral mode</em> as a multitouch controller connected to a laptop.
+</ul>
+
+<h2 id=the_api_features_include>The API features include:</h2>
+
+
+<ul>
+  <li> Enumeration of currently available devices. Information includes name, vendor,
+capabilities, etc.
+  <li> Provide notification when MIDI devices are plugged in or unplugged.
+  <li> Support efficient transmission of single or multiple short 1-3 byte MIDI
+messages.
+  <li> Support transmission of arbitrary length data for SysEx, etc.
+  <li> Timestamps to avoid jitter.
+  <li> Support direction connection or “patching” of devices for lower latency.
+</ul>
+
+<h2 id=transports_supported>Transports Supported</h2>
+
+
+<p>The API is “transport agnostic”. But there are several transports currently
+supported:</p>
+
+<ul>
+  <li> USB
+  <li> software routing
+  <li> BTLE
+</ul>
+
+<h1 id=android_midi_terminology>Android MIDI Terminology</h1>
+
+
+<h2 id=terminology>Terminology</h2>
+
+
+<p>A <strong>Device</strong> is a MIDI capable object that has zero or more InputPorts and OutputPorts.</p>
+
+<p>An <strong>InputPort</strong> has 16 channels and can <strong>receive</strong> MIDI messages from an OutputPort or an app.</p>
+
+<p>An <strong>OutputPort</strong> has 16 channels and can <strong>send</strong> MIDI messages to an InputPort or an app.</p>
+
+<p><strong>MidiService</strong> is a centralized process that keeps track of all devices and brokers
+communication between them.</p>
+
+<p><strong>MidiManager</strong> is a class that the application or a device manager calls to communicate with
+the MidiService.</p>
+
+<h1 id=writing_a_midi_application>Writing a MIDI Application</h1>
+
+
+<h2 id=the_midimanager>The MidiManager</h2>
+
+
+<p>The primary class for accessing the MIDI package is through the MidiManager.</p>
+
+<pre class=prettyprint>
+MidiManager m = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);
+</pre>
+
+
+<h2 id=get_list_of_already_plugged_in_entities>Get List of Already Plugged In Entities</h2>
+
+
+<p>When an app starts, it can get a list of all the available MIDI devices. This
+information can be presented to a user, allowing them to choose a device.</p>
+
+<pre class=prettyprint>
+MidiDeviceInfo[] infos = m.getDeviceList();
+</pre>
+
+
+<h2 id=notification_of_midi_devices_hotplug_events>Notification of MIDI Devices HotPlug Events</h2>
+
+
+<p>The application can request notification when, for example, keyboards are
+plugged in or unplugged.</p>
+
+<pre class=prettyprint>
+m.registerDeviceCallback(new MidiManager.DeviceCallback() {
+    public void onDeviceAdded( MidiDeviceInfo info ) {
+      ...
+    }
+    public void onDeviceRemoved( MidiDeviceInfo info ) {
+      ...
+    }
+  });
+</pre>
+
+
+<h2 id=device_and_port_information>Device and Port Information</h2>
+
+
+<p>You can query the number of input and output ports.</p>
+
+<pre class=prettyprint>
+int numInputs = info.getInputPortCount();
+int numOutputs = info.getOutputPortCount();
+</pre>
+
+
+<p>Note that “input” and “output” are from the standpoint of the device. So a
+synthesizer will have an “input” port that receives messages. A keyboard will
+have an “output” port that sends messages.</p>
+
+<p>The MidiDeviceInfo has a bundle of properties.</p>
+
+<pre class=prettyprint>
+Bundle properties = info.getProperties();
+String manufacturer = properties
+      .getString(MidiDeviceInfo.PROPERTY_MANUFACTURER);
+</pre>
+
+
+<p>Other properties include PROPERTY_PRODUCT, PROPERTY_NAME,
+PROPERTY_SERIAL_NUMBER</p>
+
+<p>You can get the names of the ports from a PortInfo object.</p>
+
+<pre class=prettyprint>
+PortInfo portInfo = info.getInputPortInfo(i);
+String portName = portInfo.getName();
+</pre>
+
+
+<h2 id=open_a_midi_device>Open a MIDI Device</h2>
+
+
+<p>To access a MIDI device you need to open it first. The open is asynchronous so
+you need to provide a callback for completion. You can specify an optional
+Handler if you want the callback to occur on a specific Thread.</p>
+
+<pre class=prettyprint>
+m.openDevice(info, new MidiManager.DeviceOpenCallback() {
+    &#64;Override
+    public void onDeviceOpened(MidiDeviceInfo deviceInfo,
+            MidiDevice device) {
+        if (device == null) {
+            Log.e(TAG, "could not open " + deviceInfo);
+        } else {
+            ...
+        }, new Handler(Looper.getMainLooper())
+    );
+</pre>
+
+
+<h2 id=open_a_midi_input_port>Open a MIDI Input Port</h2>
+
+
+<p>If you want to send a message to a MIDI Device then you need to open an “input”
+port with exclusive access.</p>
+
+<pre class=prettyprint>
+MidiInputPort inputPort = device.openInputPort(index);
+</pre>
+
+
+<h2 id=send_a_noteon>Send a NoteOn</h2>
+
+
+<p>MIDI messages are sent as byte arrays. Here we encode a NoteOn message.</p>
+
+<pre class=prettyprint>
+byte[] buffer = new buffer[64];
+int numBytes = 0;
+buffer[numBytes++] = 0x90 + channel; // note on
+buffer[numBytes++] = pitch;
+buffer[numBytes++] = velocity;
+int offset = 0;
+// post is non-blocking
+inputPort.send(buffer, offset, numBytes);
+</pre>
+
+
+<p>Sometimes it is convenient to send MIDI messages with a timestamp. By
+scheduling events in the future we can mask scheduling jitter. Android MIDI
+timestamps are based on the monotonic nanosecond system timer. This is
+consistent with the other audio and input timers.</p>
+
+<p>Here we send a message with a timestamp 2 seconds in the future.</p>
+
+<pre class=prettyprint>
+long now = System.nanoTime();
+long future = now + (2 * 1000000000);
+inputPort.sendWithTimestamp(buffer, offset, numBytes, future);
+</pre>
+
+
+<p>If you want to cancel events that you have scheduled in the future then call
+flush().</p>
+
+<pre class=prettyprint>
+inputPort.flush(); // discard events
+</pre>
+
+
+<p>If there were any MIDI NoteOff message left in the buffer then they will be
+discarded and you may get stuck notes. So we recommend sending “all notes off”
+after doing a flush.</p>
+
+<h2 id=receive_a_note>Receive a Note</h2>
+
+
+<p>To receive MIDI data from a device you need to extend MidiReceiver. Then
+connect your receiver to an output port of the device.</p>
+
+<pre class=prettyprint>
+class MyReceiver extends MidiReceiver {
+    public void onReceive(byte[] data, int offset,
+            int count, long timestamp) throws IOException {
+        // parse MIDI or whatever
+    }
+}
+MidiOutputPort outputPort = device.openOutputPort(index);
+outputPort.connect(new MyReceiver());
+</pre>
+
+
+<p>The data that arrives is not validated or aligned in any particular way. It is
+raw MIDI data and can contain multiple messages or partial messages. It might
+contain System Real-Time messages, which can be interleaved inside other
+messages. Some applications have their own MIDI parsers so pre-parsing the data
+would be redundant. If an application wants the data parsed and aligned then
+they can use the MidiFramer utility.</p>
+
+<h1 id=creating_a_midi_virtual_device_service>Creating a MIDI Virtual Device Service</h1>
+
+
+<p>An app can provide a MIDI Service that can be used by other apps. For example,
+an app can provide a custom synthesizer that other apps can send messages to. </p>
+
+<h2 id=manifest_files>Manifest Files</h2>
+
+
+<p>An app declares that it will function as a MIDI server in the
+AndroidManifest.xml file.</p>
+
+<pre class=prettyprint>
+&lt;service android:name="<strong>MySynthDeviceService</strong>">
+  &lt;intent-filter>
+    &lt;action android:name="android.media.midi.MidiDeviceService" />
+  &lt;/intent-filter>
+  &lt;meta-data android:name="android.media.midi.MidiDeviceService"
+      android:resource="@xml/<strong>synth_device_info</strong>" />
+&lt;/service>
+</pre>
+
+
+<p>The details of the resource in this example is stored in
+“res/xml/synth_device_info.xml”.</p>
+
+<pre class=prettyprint>
+&lt;devices>
+    &lt;device manufacturer="MyCompany" product="MidiSynthBasic">
+        &lt;input-port name="input" />
+    &lt;/device>
+&lt;/devices>
+</pre>
+
+
+<h2 id=extend_midideviceservice>Extend MidiDeviceService</h2>
+
+
+<p>You then define your server by extending android.media.midi.MidiDeviceService.
+Let’s assume you have a MySynthEngine class that extends MidiReceiver.</p>
+
+<pre class=prettyprint>
+import android.media.midi.MidiDeviceService;
+import android.media.midi.MidiDeviceStatus;
+import android.media.midi.MidiReceiver;
+
+public class MidiSynthDeviceService extends MidiDeviceService {
+    private static final String TAG = "MidiSynthDeviceService";
+    private MySynthEngine mSynthEngine = new MySynthEngine();
+    &#64;Override
+    public void onCreate() {
+        super.onCreate();
+    }
+
+    &#64;Override
+    public void onDestroy() {
+        mSynthEngine.stop();
+        super.onDestroy();
+    }
+
+    &#64;Override
+    // Declare the receivers associated with your input ports.
+    public MidiReceiver[] onGetInputPortReceivers() {
+        return new MidiReceiver[] { mSynthEngine };
+    }
+
+    /**
+     * This will get called when clients connect or disconnect.
+     * You can use it to turn on your synth only when needed.
+     */
+    &#64;Override
+    public void onDeviceStatusChanged(MidiDeviceStatus status) {
+        if (status.isInputPortOpen(0)) {
+            mSynthEngine.start();
+        } else {
+            mSynthEngine.stop();
+        }
+    }
+}
+</pre>
+</body>
+</html>
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 2f6bbf4..c6fa379 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -281,15 +281,16 @@
         return NULL;
     }
 
-    SkBitmap *bitmap = GraphicsJNI::getSkBitmap(env, jBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(env, jBitmap, &bitmap);
 
-    bitmap->lockPixels();
-    rotate((uint16_t*)bitmap->getPixels(),
+    bitmap.lockPixels();
+    rotate((uint16_t*)bitmap.getPixels(),
            (uint16_t*)((char*)videoFrame + sizeof(VideoFrame)),
            videoFrame->mWidth,
            videoFrame->mHeight,
            videoFrame->mRotationAngle);
-    bitmap->unlockPixels();
+    bitmap.unlockPixels();
 
     if (videoFrame->mDisplayWidth  != videoFrame->mWidth ||
         videoFrame->mDisplayHeight != videoFrame->mHeight) {
diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp
index ddb01a0..0521833 100644
--- a/native/graphics/jni/bitmap.cpp
+++ b/native/graphics/jni/bitmap.cpp
@@ -27,18 +27,16 @@
         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
     }
 
-    SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
-    if (NULL == bm) {
-        return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
-    }
+    SkBitmap bm;
+    GraphicsJNI::getSkBitmap(env, jbitmap, &bm);
 
     if (info) {
-        info->width     = bm->width();
-        info->height    = bm->height();
-        info->stride    = bm->rowBytes();
+        info->width     = bm.width();
+        info->height    = bm.height();
+        info->stride    = bm.rowBytes();
         info->flags     = 0;
 
-        switch (bm->colorType()) {
+        switch (bm.colorType()) {
             case kN32_SkColorType:
                 info->format = ANDROID_BITMAP_FORMAT_RGBA_8888;
                 break;
@@ -64,17 +62,18 @@
         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
     }
 
-    SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
-    if (NULL == bm) {
+    SkPixelRef* pixelRef = GraphicsJNI::getSkPixelRef(env, jbitmap);
+    if (!pixelRef) {
         return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
     }
 
-    bm->lockPixels();
-    void* addr = bm->getPixels();
+    pixelRef->lockPixels();
+    void* addr = pixelRef->pixels();
     if (NULL == addr) {
-        bm->unlockPixels();
+        pixelRef->unlockPixels();
         return ANDROID_BITMAP_RESULT_ALLOCATION_FAILED;
     }
+    pixelRef->ref();
 
     if (addrPtr) {
         *addrPtr = addr;
@@ -87,8 +86,8 @@
         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
     }
 
-    SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
-    if (NULL == bm) {
+    SkPixelRef* pixelRef = GraphicsJNI::getSkPixelRef(env, jbitmap);
+    if (!pixelRef) {
         return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
     }
 
@@ -96,9 +95,11 @@
     // bitmaps.  Note that this will slow down read-only accesses to the
     // bitmaps, but the NDK methods are primarily intended to be used for
     // writes.
-    bm->notifyPixelsChanged();
+    pixelRef->notifyPixelsChanged();
 
-    bm->unlockPixels();
+    pixelRef->unlockPixels();
+    pixelRef->unref();
+
     return ANDROID_BITMAP_RESULT_SUCCESS;
 }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 18615d9..147ac19 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -763,6 +763,10 @@
                             mSwitchingUser = false;
                             startListeningForFingerprint();
                         }
+                        @Override
+                        public void onForegroundProfileSwitch(int newProfileId) {
+                            // Ignore.
+                        }
                     });
         } catch (RemoteException e) {
             // TODO Auto-generated catch block
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index a40233a..783df68 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -1074,9 +1074,8 @@
 nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
                             jobject jbitmap, jint usage)
 {
-    SkBitmap const * nativeBitmap =
-            GraphicsJNI::getSkBitmap(_env, jbitmap);
-    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
 
     bitmap.lockPixels();
     const void* ptr = bitmap.getPixels();
@@ -1091,9 +1090,8 @@
 nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con, jlong type,
                                         jint mip, jobject jbitmap, jint usage)
 {
-    SkBitmap const * nativeBitmap =
-            GraphicsJNI::getSkBitmap(_env, jbitmap);
-    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
 
     bitmap.lockPixels();
     const void* ptr = bitmap.getPixels();
@@ -1108,9 +1106,8 @@
 nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
                                 jobject jbitmap, jint usage)
 {
-    SkBitmap const * nativeBitmap =
-            GraphicsJNI::getSkBitmap(_env, jbitmap);
-    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
 
     bitmap.lockPixels();
     const void* ptr = bitmap.getPixels();
@@ -1124,9 +1121,8 @@
 static void
 nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
 {
-    SkBitmap const * nativeBitmap =
-            GraphicsJNI::getSkBitmap(_env, jbitmap);
-    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
     int w = bitmap.width();
     int h = bitmap.height();
 
@@ -1141,9 +1137,8 @@
 static void
 nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
 {
-    SkBitmap const * nativeBitmap =
-            GraphicsJNI::getSkBitmap(_env, jbitmap);
-    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
 
     bitmap.lockPixels();
     void* ptr = bitmap.getPixels();
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index d92a89f..0f9090d 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -797,6 +797,11 @@
                         @Override
                         public void onUserSwitchComplete(int newUserId) throws RemoteException {
                         }
+
+                        @Override
+                        public void onForegroundProfileSwitch(int newProfileId) {
+                            // Ignore.
+                        }
                     });
             userId = ActivityManagerNative.getDefault().getCurrentUser().id;
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 5add88e..9a6f696 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -116,6 +116,11 @@
                         @Override
                         public void onUserSwitchComplete(int newUserId) throws RemoteException {
                         }
+
+                        @Override
+                        public void onForegroundProfileSwitch(int newProfileId) {
+                            // Ignore.
+                        }
                     });
             userId = ActivityManagerNative.getDefault().getCurrentUser().id;
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c2af765..6341807 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1284,6 +1284,7 @@
     static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 50;
     static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 51;
     static final int DELETE_DUMPHEAP_MSG = 52;
+    static final int FOREGROUND_PROFILE_CHANGED_MSG = 53;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1922,6 +1923,9 @@
                     mMemWatchDumpUid = -1;
                 }
             } break;
+            case FOREGROUND_PROFILE_CHANGED_MSG: {
+                dispatchForegroundProfileChanged(msg.arg1);
+            } break;
             }
         }
     };
@@ -2523,6 +2527,11 @@
                 mWindowManager.setFocusedApp(r.appToken, true);
             }
             applyUpdateLockStateLocked(r);
+            if (last != null && last.userId != mFocusedActivity.userId) {
+                mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
+                mHandler.sendMessage(mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG,
+                                mFocusedActivity.userId, 0));
+            }
         }
         EventLog.writeEvent(EventLogTags.AM_FOCUSED_ACTIVITY, mCurrentUserId,
                 mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName);
@@ -19072,6 +19081,18 @@
         return true;
     }
 
+    void dispatchForegroundProfileChanged(int userId) {
+        final int N = mUserSwitchObservers.beginBroadcast();
+        for (int i = 0; i < N; i++) {
+            try {
+                mUserSwitchObservers.getBroadcastItem(i).onForegroundProfileSwitch(userId);
+            } catch (RemoteException e) {
+                // Ignore
+            }
+        }
+        mUserSwitchObservers.finishBroadcast();
+    }
+
     void sendUserSwitchBroadcastsLocked(int oldUserId, int newUserId) {
         long ident = Binder.clearCallingIdentity();
         try {
diff --git a/services/core/java/com/android/server/display/DisplayBlanker.java b/services/core/java/com/android/server/display/DisplayBlanker.java
index eb0ae6a..816dc13 100644
--- a/services/core/java/com/android/server/display/DisplayBlanker.java
+++ b/services/core/java/com/android/server/display/DisplayBlanker.java
@@ -20,5 +20,5 @@
  * Interface used to update the actual display state.
  */
 public interface DisplayBlanker {
-    void requestDisplayState(int state);
+    void requestDisplayState(int state, int brightness);
 }
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 61631d4..e16be71 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -118,10 +118,12 @@
     /**
      * Sets the display state, if supported.
      *
+     * @param state The new display state.
+     * @param brightness The new display brightness.
      * @return A runnable containing work to be deferred until after we have
      * exited the critical section, or null if none.
      */
-    public Runnable requestDisplayStateLocked(int state) {
+    public Runnable requestDisplayStateLocked(int state, int brightness) {
         return null;
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 5f0ad9f..9ea0444 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -40,11 +40,13 @@
 import android.os.IBinder.DeathRecipient;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -179,7 +181,11 @@
 
     // The overall display state, independent of changes that might influence one
     // display or another in particular.
-    private int mGlobalDisplayState = Display.STATE_UNKNOWN;
+    private int mGlobalDisplayState = Display.STATE_ON;
+
+    // The overall display brightness.
+    // For now, this only applies to the built-in display but we may split it up eventually.
+    private int mGlobalDisplayBrightness = PowerManager.BRIGHTNESS_DEFAULT;
 
     // Set to true when there are pending display changes that have yet to be applied
     // to the surface flinger state.
@@ -226,6 +232,9 @@
         mUiHandler = UiThread.getHandler();
         mDisplayAdapterListener = new DisplayAdapterListener();
         mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
+
+        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
     }
 
     @Override
@@ -322,16 +331,34 @@
         }
     }
 
-    private void requestGlobalDisplayStateInternal(int state) {
+    private void requestGlobalDisplayStateInternal(int state, int brightness) {
+        if (state == Display.STATE_UNKNOWN) {
+            state = Display.STATE_ON;
+        }
+        if (state == Display.STATE_OFF) {
+            brightness = PowerManager.BRIGHTNESS_OFF;
+        } else if (brightness < 0) {
+            brightness = PowerManager.BRIGHTNESS_DEFAULT;
+        } else if (brightness > PowerManager.BRIGHTNESS_ON) {
+            brightness = PowerManager.BRIGHTNESS_ON;
+        }
+
         synchronized (mTempDisplayStateWorkQueue) {
             try {
                 // Update the display state within the lock.
                 synchronized (mSyncRoot) {
-                    if (mGlobalDisplayState != state) {
-                        mGlobalDisplayState = state;
-                        updateGlobalDisplayStateLocked(mTempDisplayStateWorkQueue);
-                        scheduleTraversalLocked(false);
+                    if (mGlobalDisplayState == state
+                            && mGlobalDisplayBrightness == brightness) {
+                        return; // no change
                     }
+
+                    Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestGlobalDisplayState("
+                            + Display.stateToString(state)
+                            + ", brightness=" + brightness + ")");
+                    mGlobalDisplayState = state;
+                    mGlobalDisplayBrightness = brightness;
+                    updateGlobalDisplayStateLocked(mTempDisplayStateWorkQueue);
+                    scheduleTraversalLocked(false);
                 }
 
                 // Setting the display power state can take hundreds of milliseconds
@@ -341,6 +368,7 @@
                 for (int i = 0; i < mTempDisplayStateWorkQueue.size(); i++) {
                     mTempDisplayStateWorkQueue.get(i).run();
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_POWER);
             } finally {
                 mTempDisplayStateWorkQueue.clear();
             }
@@ -708,7 +736,7 @@
         // by the display power controller (if known).
         DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
-            return device.requestDisplayStateLocked(mGlobalDisplayState);
+            return device.requestDisplayStateLocked(mGlobalDisplayState, mGlobalDisplayBrightness);
         }
         return null;
     }
@@ -1462,16 +1490,16 @@
             synchronized (mSyncRoot) {
                 DisplayBlanker blanker = new DisplayBlanker() {
                     @Override
-                    public void requestDisplayState(int state) {
+                    public void requestDisplayState(int state, int brightness) {
                         // The order of operations is important for legacy reasons.
                         if (state == Display.STATE_OFF) {
-                            requestGlobalDisplayStateInternal(state);
+                            requestGlobalDisplayStateInternal(state, brightness);
                         }
 
                         callbacks.onDisplayStateChange(state);
 
                         if (state != Display.STATE_OFF) {
-                            requestGlobalDisplayStateInternal(state);
+                            requestGlobalDisplayStateInternal(state, brightness);
                         }
                     }
                 };
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index cf1f4b0..f74601e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -19,7 +19,6 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.server.LocalServices;
 import com.android.server.am.BatteryStatsService;
-import com.android.server.lights.LightsManager;
 
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
@@ -122,9 +121,6 @@
     // Battery stats.
     private final IBatteryStats mBatteryStats;
 
-    // The lights service.
-    private final LightsManager mLights;
-
     // The sensor manager.
     private final SensorManager mSensorManager;
 
@@ -260,7 +256,6 @@
         mCallbacks = callbacks;
 
         mBatteryStats = BatteryStatsService.getService();
-        mLights = LocalServices.getService(LightsManager.class);
         mSensorManager = sensorManager;
         mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class);
         mBlanker = blanker;
@@ -443,7 +438,6 @@
         // Initialize the power state object for the default display.
         // In the future, we might manage multiple displays independently.
         mPowerState = new DisplayPowerState(mBlanker,
-                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
                 new ColorFade(Display.DEFAULT_DISPLAY));
 
         mColorFadeOnAnimator = ObjectAnimator.ofFloat(
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index a3c9738..f53ccc9 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -16,13 +16,10 @@
 
 package com.android.server.display;
 
-import com.android.server.lights.Light;
-
 import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
-import android.os.Trace;
 import android.util.FloatProperty;
 import android.util.IntProperty;
 import android.util.Slog;
@@ -56,7 +53,6 @@
     private final Handler mHandler;
     private final Choreographer mChoreographer;
     private final DisplayBlanker mBlanker;
-    private final Light mBacklight;
     private final ColorFade mColorFade;
     private final PhotonicModulator mPhotonicModulator;
 
@@ -72,12 +68,11 @@
 
     private Runnable mCleanListener;
 
-    public DisplayPowerState(DisplayBlanker blanker, Light backlight, ColorFade electronBeam) {
+    public DisplayPowerState(DisplayBlanker blanker, ColorFade colorFade) {
         mHandler = new Handler(true /*async*/);
         mChoreographer = Choreographer.getInstance();
         mBlanker = blanker;
-        mBacklight = backlight;
-        mColorFade = electronBeam;
+        mColorFade = colorFade;
         mPhotonicModulator = new PhotonicModulator();
         mPhotonicModulator.start();
 
@@ -415,35 +410,7 @@
                     Slog.d(TAG, "Updating screen state: state="
                             + Display.stateToString(state) + ", backlight=" + backlight);
                 }
-                boolean suspending = Display.isSuspendedState(state);
-                if (stateChanged && !suspending) {
-                    requestDisplayState(state);
-                }
-                if (backlightChanged) {
-                    setBrightness(backlight);
-                }
-                if (stateChanged && suspending) {
-                    requestDisplayState(state);
-                }
-            }
-        }
-
-        private void requestDisplayState(int state) {
-            Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
-                    + Display.stateToString(state) + ")");
-            try {
-                mBlanker.requestDisplayState(state);
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_POWER);
-            }
-        }
-
-        private void setBrightness(int backlight) {
-            Trace.traceBegin(Trace.TRACE_TAG_POWER, "setBrightness(" + backlight + ")");
-            try {
-                mBacklight.setBrightness(backlight);
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_POWER);
+                mBlanker.requestDisplayState(state, backlight);
             }
         }
     }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 5ebe64d..e87f265 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -16,10 +16,15 @@
 
 package com.android.server.display;
 
+import com.android.server.LocalServices;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
+
 import android.content.Context;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.PowerManager;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.Slog;
@@ -40,6 +45,7 @@
  */
 final class LocalDisplayAdapter extends DisplayAdapter {
     private static final String TAG = "LocalDisplayAdapter";
+    private static final boolean DEBUG = false;
 
     private static final String UNIQUE_ID_PREFIX = "local:";
 
@@ -132,14 +138,17 @@
         private final int mBuiltInDisplayId;
         private final SurfaceControl.PhysicalDisplayInfo mPhys;
         private final int mDefaultPhysicalDisplayInfo;
+        private final Light mBacklight;
 
         private DisplayDeviceInfo mInfo;
         private boolean mHavePendingChanges;
         private int mState = Display.STATE_UNKNOWN;
+        private int mBrightness = PowerManager.BRIGHTNESS_DEFAULT;
         private float[] mSupportedRefreshRates;
         private int[] mRefreshRateConfigIndices;
         private float mLastRequestedRefreshRate;
 
+
         public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
                 SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo) {
             super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + builtInDisplayId);
@@ -148,6 +157,13 @@
                     physicalDisplayInfos[activeDisplayInfo]);
             mDefaultPhysicalDisplayInfo = activeDisplayInfo;
             updateSupportedRefreshRatesLocked(physicalDisplayInfos, mPhys);
+
+            if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
+                LightsManager lights = LocalServices.getService(LightsManager.class);
+                mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT);
+            } else {
+                mBacklight = null;
+            }
         }
 
         public boolean updatePhysicalDisplayInfoLocked(
@@ -225,28 +241,91 @@
         }
 
         @Override
-        public Runnable requestDisplayStateLocked(final int state) {
-            if (mState != state) {
+        public Runnable requestDisplayStateLocked(final int state, final int brightness) {
+            // Assume that the brightness is off if the display is being turned off.
+            assert state != Display.STATE_OFF || brightness == PowerManager.BRIGHTNESS_OFF;
+
+            final boolean stateChanged = (mState != state);
+            final boolean brightnessChanged = (mBrightness != brightness) && mBacklight != null;
+            if (stateChanged || brightnessChanged) {
                 final int displayId = mBuiltInDisplayId;
                 final IBinder token = getDisplayTokenLocked();
-                final int mode = getPowerModeForState(state);
-                mState = state;
-                updateDeviceInfoLocked();
+                final int oldState = mState;
 
-                // Defer actually setting the display power mode until we have exited
+                if (stateChanged) {
+                    mState = state;
+                    updateDeviceInfoLocked();
+                }
+
+                if (brightnessChanged) {
+                    mBrightness = brightness;
+                }
+
+                // Defer actually setting the display state until after we have exited
                 // the critical section since it can take hundreds of milliseconds
                 // to complete.
                 return new Runnable() {
                     @Override
                     public void run() {
-                        Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
-                                + Display.stateToString(state) + ", id=" + displayId + ")");
+                        // Exit a suspended state before making any changes.
+                        int currentState = oldState;
+                        if (Display.isSuspendedState(oldState)
+                                || oldState == Display.STATE_UNKNOWN) {
+                            if (!Display.isSuspendedState(state)) {
+                                setDisplayState(state);
+                                currentState = state;
+                            } else if (state == Display.STATE_DOZE_SUSPEND
+                                    || oldState == Display.STATE_DOZE_SUSPEND) {
+                                setDisplayState(Display.STATE_DOZE);
+                                currentState = Display.STATE_DOZE;
+                            } else {
+                                return; // old state and new state is off
+                            }
+                        }
+
+                        // Apply brightness changes given that we are in a non-suspended state.
+                        if (brightnessChanged) {
+                            setDisplayBrightness(brightness);
+                        }
+
+                        // Enter the final desired state, possibly suspended.
+                        if (state != currentState) {
+                            setDisplayState(state);
+                        }
+                    }
+
+                    private void setDisplayState(int state) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "setDisplayState("
+                                    + "id=" + displayId
+                                    + ", state=" + Display.stateToString(state) + ")");
+                        }
+
+                        Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayState("
+                                + "id=" + displayId
+                                + ", state=" + Display.stateToString(state) + ")");
                         try {
+                            final int mode = getPowerModeForState(state);
                             SurfaceControl.setDisplayPowerMode(token, mode);
                         } finally {
                             Trace.traceEnd(Trace.TRACE_TAG_POWER);
                         }
                     }
+
+                    private void setDisplayBrightness(int brightness) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "setDisplayBrightness("
+                                    + "id=" + displayId + ", brightness=" + brightness + ")");
+                        }
+
+                        Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness("
+                                + "id=" + displayId + ", brightness=" + brightness + ")");
+                        try {
+                            mBacklight.setBrightness(brightness);
+                        } finally {
+                            Trace.traceEnd(Trace.TRACE_TAG_POWER);
+                        }
+                    }
                 };
             }
             return null;
@@ -278,6 +357,8 @@
             pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
             pw.println("mPhys=" + mPhys);
             pw.println("mState=" + Display.stateToString(mState));
+            pw.println("mBrightness=" + mBrightness);
+            pw.println("mBacklight=" + mBacklight);
         }
 
         private void updateDeviceInfoLocked() {
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index f181cd5..6f59b54 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -221,7 +221,7 @@
         }
 
         @Override
-        public Runnable requestDisplayStateLocked(int state) {
+        public Runnable requestDisplayStateLocked(int state, int brightness) {
             if (state != mDisplayState) {
                 mDisplayState = state;
                 if (state == Display.STATE_OFF) {
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 2da9d8e..ed884ef 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -19,16 +19,11 @@
 import com.android.server.SystemService;
 
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.os.Handler;
-import android.os.IHardwareService;
 import android.os.Message;
 import android.os.Trace;
 import android.util.Slog;
 
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-
 public class LightsService extends SystemService {
     static final String TAG = "LightsService";
     static final boolean DEBUG = false;
@@ -124,46 +119,6 @@
         private boolean mFlashing;
     }
 
-    /* This class implements an obsolete API that was removed after eclair and re-added during the
-     * final moments of the froyo release to support flashlight apps that had been using the private
-     * IHardwareService API. This is expected to go away in the next release.
-     */
-    private final IHardwareService.Stub mLegacyFlashlightHack = new IHardwareService.Stub() {
-
-        private static final String FLASHLIGHT_FILE = "/sys/class/leds/spotlight/brightness";
-
-        public boolean getFlashlightEnabled() {
-            try {
-                FileInputStream fis = new FileInputStream(FLASHLIGHT_FILE);
-                int result = fis.read();
-                fis.close();
-                return (result != '0');
-            } catch (Exception e) {
-                return false;
-            }
-        }
-
-        public void setFlashlightEnabled(boolean on) {
-            final Context context = getContext();
-            if (context.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
-                    != PackageManager.PERMISSION_GRANTED &&
-                    context.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
-                    != PackageManager.PERMISSION_GRANTED) {
-                throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission");
-            }
-            try {
-                FileOutputStream fos = new FileOutputStream(FLASHLIGHT_FILE);
-                byte[] bytes = new byte[2];
-                bytes[0] = (byte)(on ? '1' : '0');
-                bytes[1] = '\n';
-                fos.write(bytes);
-                fos.close();
-            } catch (Exception e) {
-                // fail silently
-            }
-        }
-    };
-
     public LightsService(Context context) {
         super(context);
 
@@ -176,13 +131,12 @@
 
     @Override
     public void onStart() {
-        publishBinderService("hardware", mLegacyFlashlightHack);
         publishLocalService(LightsManager.class, mService);
     }
 
     private final LightsManager mService = new LightsManager() {
         @Override
-        public com.android.server.lights.Light getLight(int id) {
+        public Light getLight(int id) {
             if (id < LIGHT_ID_COUNT) {
                 return mLights[id];
             } else {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 04059fc..a260b0e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6645,86 +6645,94 @@
             r = null;
             for (i=0; i<N; i++) {
                 PackageParser.Permission p = pkg.permissions.get(i);
+
+                // Now that permission groups have a special meaning, we ignore permission
+                // groups for legacy apps to prevent unexpected behavior. In particular,
+                // permissions for one app being granted to someone just becuase they happen
+                // to be in a group defined by another app (before this had no implications).
+                if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
+                    p.group = mPermissionGroups.get(p.info.group);
+                    // Warn for a permission in an unknown group.
+                    if (p.info.group != null && p.group == null) {
+                        Slog.w(TAG, "Permission " + p.info.name + " from package "
+                                + p.info.packageName + " in an unknown group " + p.info.group);
+                    }
+                }
+
                 ArrayMap<String, BasePermission> permissionMap =
                         p.tree ? mSettings.mPermissionTrees
-                        : mSettings.mPermissions;
-                p.group = mPermissionGroups.get(p.info.group);
-                if (p.info.group == null || p.group != null) {
-                    BasePermission bp = permissionMap.get(p.info.name);
+                                : mSettings.mPermissions;
+                BasePermission bp = permissionMap.get(p.info.name);
 
-                    // Allow system apps to redefine non-system permissions
-                    if (bp != null && !Objects.equals(bp.sourcePackage, p.info.packageName)) {
-                        final boolean currentOwnerIsSystem = (bp.perm != null
-                                && isSystemApp(bp.perm.owner));
-                        if (isSystemApp(p.owner)) {
-                            if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
-                                // It's a built-in permission and no owner, take ownership now
-                                bp.packageSetting = pkgSetting;
-                                bp.perm = p;
-                                bp.uid = pkg.applicationInfo.uid;
-                                bp.sourcePackage = p.info.packageName;
-                            } else if (!currentOwnerIsSystem) {
-                                String msg = "New decl " + p.owner + " of permission  "
-                                        + p.info.name + " is system; overriding " + bp.sourcePackage;
-                                reportSettingsProblem(Log.WARN, msg);
-                                bp = null;
-                            }
+                // Allow system apps to redefine non-system permissions
+                if (bp != null && !Objects.equals(bp.sourcePackage, p.info.packageName)) {
+                    final boolean currentOwnerIsSystem = (bp.perm != null
+                            && isSystemApp(bp.perm.owner));
+                    if (isSystemApp(p.owner)) {
+                        if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
+                            // It's a built-in permission and no owner, take ownership now
+                            bp.packageSetting = pkgSetting;
+                            bp.perm = p;
+                            bp.uid = pkg.applicationInfo.uid;
+                            bp.sourcePackage = p.info.packageName;
+                        } else if (!currentOwnerIsSystem) {
+                            String msg = "New decl " + p.owner + " of permission  "
+                                    + p.info.name + " is system; overriding " + bp.sourcePackage;
+                            reportSettingsProblem(Log.WARN, msg);
+                            bp = null;
                         }
                     }
+                }
 
-                    if (bp == null) {
-                        bp = new BasePermission(p.info.name, p.info.packageName,
-                                BasePermission.TYPE_NORMAL);
-                        permissionMap.put(p.info.name, bp);
-                    }
+                if (bp == null) {
+                    bp = new BasePermission(p.info.name, p.info.packageName,
+                            BasePermission.TYPE_NORMAL);
+                    permissionMap.put(p.info.name, bp);
+                }
 
-                    if (bp.perm == null) {
-                        if (bp.sourcePackage == null
-                                || bp.sourcePackage.equals(p.info.packageName)) {
-                            BasePermission tree = findPermissionTreeLP(p.info.name);
-                            if (tree == null
-                                    || tree.sourcePackage.equals(p.info.packageName)) {
-                                bp.packageSetting = pkgSetting;
-                                bp.perm = p;
-                                bp.uid = pkg.applicationInfo.uid;
-                                bp.sourcePackage = p.info.packageName;
-                                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
-                                    if (r == null) {
-                                        r = new StringBuilder(256);
-                                    } else {
-                                        r.append(' ');
-                                    }
-                                    r.append(p.info.name);
+                if (bp.perm == null) {
+                    if (bp.sourcePackage == null
+                            || bp.sourcePackage.equals(p.info.packageName)) {
+                        BasePermission tree = findPermissionTreeLP(p.info.name);
+                        if (tree == null
+                                || tree.sourcePackage.equals(p.info.packageName)) {
+                            bp.packageSetting = pkgSetting;
+                            bp.perm = p;
+                            bp.uid = pkg.applicationInfo.uid;
+                            bp.sourcePackage = p.info.packageName;
+                            if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
+                                if (r == null) {
+                                    r = new StringBuilder(256);
+                                } else {
+                                    r.append(' ');
                                 }
-                            } else {
-                                Slog.w(TAG, "Permission " + p.info.name + " from package "
-                                        + p.info.packageName + " ignored: base tree "
-                                        + tree.name + " is from package "
-                                        + tree.sourcePackage);
+                                r.append(p.info.name);
                             }
                         } else {
                             Slog.w(TAG, "Permission " + p.info.name + " from package "
-                                    + p.info.packageName + " ignored: original from "
-                                    + bp.sourcePackage);
+                                    + p.info.packageName + " ignored: base tree "
+                                    + tree.name + " is from package "
+                                    + tree.sourcePackage);
                         }
-                    } else if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
-                        if (r == null) {
-                            r = new StringBuilder(256);
-                        } else {
-                            r.append(' ');
-                        }
-                        r.append("DUP:");
-                        r.append(p.info.name);
+                    } else {
+                        Slog.w(TAG, "Permission " + p.info.name + " from package "
+                                + p.info.packageName + " ignored: original from "
+                                + bp.sourcePackage);
                     }
-                    if (bp.perm == p) {
-                        bp.protectionLevel = p.info.protectionLevel;
+                } else if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
+                    if (r == null) {
+                        r = new StringBuilder(256);
+                    } else {
+                        r.append(' ');
                     }
-                } else {
-                    Slog.w(TAG, "Permission " + p.info.name + " from package "
-                            + p.info.packageName + " ignored: no group "
-                            + p.group);
+                    r.append("DUP:");
+                    r.append(p.info.name);
+                }
+                if (bp.perm == p) {
+                    bp.protectionLevel = p.info.protectionLevel;
                 }
             }
+
             if (r != null) {
                 if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Permissions: " + r);
             }
@@ -11928,7 +11936,7 @@
                         if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");
                         removeUser = user.getIdentifier();
                         appId = ps.appId;
-                        mSettings.writePackageRestrictionsLPr(removeUser);
+                        scheduleWritePackageRestrictionsLocked(removeUser);
                     } else {
                         // We need to set it back to 'installed' so the uninstall
                         // broadcasts will be sent correctly.
@@ -11943,7 +11951,7 @@
                     if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app");
                     removeUser = user.getIdentifier();
                     appId = ps.appId;
-                    mSettings.writePackageRestrictionsLPr(removeUser);
+                    scheduleWritePackageRestrictionsLocked(removeUser);
                 }
             }
         }
@@ -11960,6 +11968,11 @@
             mInstaller.clearUserData(packageName, removeUser);
             removeKeystoreDataIfNeeded(removeUser, appId);
             schedulePackageCleaning(packageName, removeUser, false);
+            synchronized (mPackages) {
+                if (clearPackagePreferredActivitiesLPw(packageName, removeUser)) {
+                    scheduleWritePackageRestrictionsLocked(removeUser);
+                }
+            }
             return true;
         }
 
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 99cf8df..54be380 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -538,6 +538,11 @@
                         @Override
                         public void onUserSwitchComplete(int newUserId) throws RemoteException {
                         }
+
+                        @Override
+                        public void onForegroundProfileSwitch(int newProfileId) {
+                            // Ignore.
+                        }
                     });
         } catch (RemoteException e) {
             // TODO Auto-generated catch block
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index bb3085e..3677132 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3027,9 +3027,14 @@
 
     @Override
     public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, String alias) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
-        synchronized (this) {
-            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+        if (who == null) {
+            if (!isCallerDelegatedCertInstaller()) {
+                throw new SecurityException("who == null, but caller is not cert installer");
+            }
+        } else {
+            synchronized (this) {
+                getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            }
         }
         final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
         final long id = Binder.clearCallingIdentity();
@@ -5715,6 +5720,40 @@
         }
     }
 
+    @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);
+            }
+        }
+    }
+
     /**
      * We need to update the internal state of whether a user has completed setup once. After
      * that, we ignore any changes that reset the Settings.Secure.USER_SETUP_COMPLETE changes
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 53da75b..593853c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -325,6 +325,9 @@
         // initialize power management features.
         mActivityManagerService.initPowerManagement();
 
+        // Manages LEDs and display backlight so we need it to bring up the display.
+        mSystemServiceManager.startService(LightsService.class);
+
         // Display manager is needed to provide display metrics before package manager
         // starts up.
         mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
@@ -363,9 +366,6 @@
      * Starts some essential services that are not tangled up in the bootstrap process.
      */
     private void startCoreServices() {
-        // Manages LEDs and display backlight.
-        mSystemServiceManager.startService(LightsService.class);
-
         // Tracks the battery level.  Requires LightService.
         mSystemServiceManager.startService(BatteryService.class);