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() {
+ @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>
+<service android:name="<strong>MySynthDeviceService</strong>">
+ <intent-filter>
+ <action android:name="android.media.midi.MidiDeviceService" />
+ </intent-filter>
+ <meta-data android:name="android.media.midi.MidiDeviceService"
+ android:resource="@xml/<strong>synth_device_info</strong>" />
+</service>
+</pre>
+
+
+<p>The details of the resource in this example is stored in
+“res/xml/synth_device_info.xml”.</p>
+
+<pre class=prettyprint>
+<devices>
+ <device manufacturer="MyCompany" product="MidiSynthBasic">
+ <input-port name="input" />
+ </device>
+</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();
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ }
+
+ @Override
+ public void onDestroy() {
+ mSynthEngine.stop();
+ super.onDestroy();
+ }
+
+ @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.
+ */
+ @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);