diff options
76 files changed, 1062 insertions, 858 deletions
diff --git a/api/current.txt b/api/current.txt index 2f63509..578f808 100644 --- a/api/current.txt +++ b/api/current.txt @@ -505,7 +505,6 @@ package android { field public static final int dropDownWidth = 16843362; // 0x1010262 field public static final int duplicateParentState = 16842985; // 0x10100e9 field public static final int duration = 16843160; // 0x1010198 - field public static final int durationScaleHint = 16844014; // 0x10104ee field public static final int dynamicResources = 16844019; // 0x10104f3 field public static final int editTextBackground = 16843602; // 0x1010352 field public static final int editTextColor = 16843601; // 0x1010351 @@ -996,6 +995,7 @@ package android { field public static final int readPermission = 16842759; // 0x1010007 field public static final int recognitionService = 16843932; // 0x101049c field public static final int relinquishTaskIdentity = 16843894; // 0x1010476 + field public static final int removeBeforeMRelease = 16844014; // 0x10104ee field public static final int reparent = 16843964; // 0x10104bc field public static final int reparentWithOverlay = 16843965; // 0x10104bd field public static final int repeatCount = 16843199; // 0x10101bf @@ -2868,7 +2868,6 @@ package android.animation { method public void cancel(); method public android.animation.Animator clone(); method public void end(); - method public long getDistanceBasedDuration(); method public abstract long getDuration(); method public android.animation.TimeInterpolator getInterpolator(); method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners(); @@ -2882,16 +2881,12 @@ package android.animation { method public void removePauseListener(android.animation.Animator.AnimatorPauseListener); method public void resume(); method public abstract android.animation.Animator setDuration(long); - method public void setDurationScaleHint(int, android.content.res.Resources); method public abstract void setInterpolator(android.animation.TimeInterpolator); method public abstract void setStartDelay(long); method public void setTarget(java.lang.Object); method public void setupEndValues(); method public void setupStartValues(); method public void start(); - field public static final int HINT_DISTANCE_DEFINED_IN_DP = 2; // 0x2 - field public static final int HINT_DISTANCE_PROPORTIONAL_TO_SCREEN_SIZE = 1; // 0x1 - field public static final int HINT_NO_SCALE = 0; // 0x0 } public static abstract interface Animator.AnimatorListener { @@ -6132,6 +6127,7 @@ package android.app.usage { } public final class UsageStatsManager { + method public boolean isAppIdle(java.lang.String); method public java.util.Map<java.lang.String, android.app.usage.UsageStats> queryAndAggregateUsageStats(long, long); method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long); method public android.app.usage.UsageEvents queryEvents(long, long); @@ -14746,7 +14742,8 @@ package android.media { field public static final int CHANNEL_IN_Y_AXIS = 4096; // 0x1000 field public static final int CHANNEL_IN_Z_AXIS = 8192; // 0x2000 field public static final int CHANNEL_OUT_5POINT1 = 252; // 0xfc - field public static final int CHANNEL_OUT_7POINT1 = 1020; // 0x3fc + field public static final deprecated int CHANNEL_OUT_7POINT1 = 1020; // 0x3fc + field public static final int CHANNEL_OUT_7POINT1_SURROUND = 6396; // 0x18fc field public static final int CHANNEL_OUT_BACK_CENTER = 1024; // 0x400 field public static final int CHANNEL_OUT_BACK_LEFT = 64; // 0x40 field public static final int CHANNEL_OUT_BACK_RIGHT = 128; // 0x80 @@ -14892,6 +14889,8 @@ package android.media { field public static final deprecated int NUM_STREAMS = 5; // 0x5 field public static final java.lang.String PROPERTY_OUTPUT_FRAMES_PER_BUFFER = "android.media.property.OUTPUT_FRAMES_PER_BUFFER"; field public static final java.lang.String PROPERTY_OUTPUT_SAMPLE_RATE = "android.media.property.OUTPUT_SAMPLE_RATE"; + field public static final java.lang.String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND"; + field public static final java.lang.String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND"; field public static final java.lang.String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED"; field public static final int RINGER_MODE_NORMAL = 2; // 0x2 field public static final int RINGER_MODE_SILENT = 0; // 0x0 @@ -16392,10 +16391,13 @@ package android.media { method public final void release(); method public void setAudioTrack(android.media.AudioTrack); method public void setCallback(android.media.MediaSync.Callback, android.os.Handler); + method public void setOnErrorListener(android.media.MediaSync.OnErrorListener, android.os.Handler); method public void setPlaybackRate(float, int); method public void setPlaybackSettings(android.media.PlaybackSettings); method public void setSurface(android.view.Surface); method public void setSyncSettings(android.media.SyncSettings); + field public static final int MEDIASYNC_ERROR_AUDIOTRACK_FAIL = 1; // 0x1 + field public static final int MEDIASYNC_ERROR_SURFACE_FAIL = 2; // 0x2 field public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0; // 0x0 field public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 2; // 0x2 field public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1; // 0x1 @@ -16403,7 +16405,11 @@ package android.media { public static abstract class MediaSync.Callback { ctor public MediaSync.Callback(); - method public abstract void onReturnAudioBuffer(android.media.MediaSync, java.nio.ByteBuffer, int); + method public abstract void onAudioBufferConsumed(android.media.MediaSync, java.nio.ByteBuffer, int); + } + + public static abstract interface MediaSync.OnErrorListener { + method public abstract void onError(android.media.MediaSync, int, int); } public class MediaSyncEvent { @@ -16429,6 +16435,14 @@ package android.media { method public abstract void onAudioDeviceConnection(); } + public abstract interface OnAudioRecordRoutingListener { + method public abstract void onAudioRecordRouting(android.media.AudioRecord); + } + + public abstract interface OnAudioTrackRoutingListener { + method public abstract void onAudioTrackRouting(android.media.AudioTrack); + } + public final class PlaybackSettings { ctor public PlaybackSettings(); method public android.media.PlaybackSettings allowDefaults(); @@ -16447,14 +16461,6 @@ package android.media { field public static final int AUDIO_STRETCH_MODE_VOICE = 1; // 0x1 } - public abstract interface OnAudioRecordRoutingListener { - method public abstract void onAudioRecordRouting(android.media.AudioRecord); - } - - public abstract interface OnAudioTrackRoutingListener { - method public abstract void onAudioTrackRouting(android.media.AudioTrack); - } - public final class Rating implements android.os.Parcelable { method public int describeContents(); method public float getPercentRating(); @@ -17819,6 +17825,7 @@ package android.media.tv { method public java.lang.String getRatingSystem(); method public java.util.List<java.lang.String> getSubRatings(); method public static android.media.tv.TvContentRating unflattenFromString(java.lang.String); + field public static final android.media.tv.TvContentRating UNRATED; } public final class TvContract { @@ -23404,6 +23411,7 @@ package android.os { method public final android.os.IBinder readStrongBinder(); method public final void readTypedArray(T[], android.os.Parcelable.Creator<T>); method public final void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>); + method public final T readTypedObject(android.os.Parcelable.Creator<T>); method public final java.lang.Object readValue(java.lang.ClassLoader); method public final void recycle(); method public final void setDataCapacity(int); @@ -23448,6 +23456,7 @@ package android.os { method public final void writeStrongInterface(android.os.IInterface); method public final void writeTypedArray(T[], int); method public final void writeTypedList(java.util.List<T>); + method public final void writeTypedObject(T, int); method public final void writeValue(java.lang.Object); field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR; } @@ -28444,13 +28453,6 @@ package android.sax { 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(); @@ -28507,7 +28509,7 @@ package android.security { ctor public KeyChainException(java.lang.Throwable); } - public class KeyExpiredException extends android.security.CryptoOperationException { + public class KeyExpiredException extends java.security.InvalidKeyException { ctor public KeyExpiredException(); ctor public KeyExpiredException(java.lang.String); ctor public KeyExpiredException(java.lang.String, java.lang.Throwable); @@ -28549,7 +28551,7 @@ package android.security { method public android.security.KeyGeneratorSpec.Builder setUserAuthenticators(int); } - public class KeyNotYetValidException extends android.security.CryptoOperationException { + public class KeyNotYetValidException extends java.security.InvalidKeyException { ctor public KeyNotYetValidException(); ctor public KeyNotYetValidException(java.lang.String); ctor public KeyNotYetValidException(java.lang.String, java.lang.Throwable); @@ -28697,12 +28699,12 @@ package android.security { method public boolean isCleartextTrafficPermitted(); } - public class NewFingerprintEnrolledException extends android.security.CryptoOperationException { + public class NewFingerprintEnrolledException extends java.security.InvalidKeyException { ctor public NewFingerprintEnrolledException(); ctor public NewFingerprintEnrolledException(java.lang.String); } - public class UserNotAuthenticatedException extends android.security.CryptoOperationException { + public class UserNotAuthenticatedException extends java.security.InvalidKeyException { ctor public UserNotAuthenticatedException(); ctor public UserNotAuthenticatedException(java.lang.String); ctor public UserNotAuthenticatedException(java.lang.String, java.lang.Throwable); @@ -28915,6 +28917,7 @@ package android.service.notification { method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); + method public final void setNotificationsShown(java.lang.String[]); field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4 field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1 @@ -30607,6 +30610,7 @@ package android.telecom { method public void cancelMissedCallsNotification(); method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle); method public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(); + method public java.lang.String getDefaultDialerPackage(); method public android.telecom.PhoneAccountHandle getDefaultOutgoingPhoneAccount(java.lang.String); method public java.lang.String getLine1Number(android.telecom.PhoneAccountHandle); method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle); @@ -30621,6 +30625,7 @@ package android.telecom { method public void showInCallScreen(boolean); method public void silenceRinger(); method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle); + field public static final java.lang.String ACTION_CHANGE_DEFAULT_DIALER = "android.telecom.action.CHANGE_DEFAULT_DIALER"; field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS"; field public static final java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL"; field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS"; @@ -30631,6 +30636,7 @@ package android.telecom { field public static final java.lang.String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER"; field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE"; field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE"; + field public static final java.lang.String EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME = "android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME"; field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS"; field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS"; field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE"; diff --git a/api/system-current.txt b/api/system-current.txt index 5c24e8e..2ea68c6 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -578,7 +578,6 @@ package android { field public static final int dropDownWidth = 16843362; // 0x1010262 field public static final int duplicateParentState = 16842985; // 0x10100e9 field public static final int duration = 16843160; // 0x1010198 - field public static final int durationScaleHint = 16844014; // 0x10104ee field public static final int dynamicResources = 16844019; // 0x10104f3 field public static final int editTextBackground = 16843602; // 0x1010352 field public static final int editTextColor = 16843601; // 0x1010351 @@ -1069,6 +1068,7 @@ package android { field public static final int readPermission = 16842759; // 0x1010007 field public static final int recognitionService = 16843932; // 0x101049c field public static final int relinquishTaskIdentity = 16843894; // 0x1010476 + field public static final int removeBeforeMRelease = 16844014; // 0x10104ee field public static final int reparent = 16843964; // 0x10104bc field public static final int reparentWithOverlay = 16843965; // 0x10104bd field public static final int repeatCount = 16843199; // 0x10101bf @@ -2948,7 +2948,6 @@ package android.animation { method public void cancel(); method public android.animation.Animator clone(); method public void end(); - method public long getDistanceBasedDuration(); method public abstract long getDuration(); method public android.animation.TimeInterpolator getInterpolator(); method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners(); @@ -2962,16 +2961,12 @@ package android.animation { method public void removePauseListener(android.animation.Animator.AnimatorPauseListener); method public void resume(); method public abstract android.animation.Animator setDuration(long); - method public void setDurationScaleHint(int, android.content.res.Resources); method public abstract void setInterpolator(android.animation.TimeInterpolator); method public abstract void setStartDelay(long); method public void setTarget(java.lang.Object); method public void setupEndValues(); method public void setupStartValues(); method public void start(); - field public static final int HINT_DISTANCE_DEFINED_IN_DP = 2; // 0x2 - field public static final int HINT_DISTANCE_PROPORTIONAL_TO_SCREEN_SIZE = 1; // 0x1 - field public static final int HINT_NO_SCALE = 0; // 0x0 } public static abstract interface Animator.AnimatorListener { @@ -6320,6 +6315,7 @@ package android.app.usage { } public final class UsageStatsManager { + method public boolean isAppIdle(java.lang.String); method public java.util.Map<java.lang.String, android.app.usage.UsageStats> queryAndAggregateUsageStats(long, long); method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long); method public android.app.usage.UsageEvents queryEvents(long, long); @@ -15947,7 +15943,8 @@ package android.media { field public static final int CHANNEL_IN_Y_AXIS = 4096; // 0x1000 field public static final int CHANNEL_IN_Z_AXIS = 8192; // 0x2000 field public static final int CHANNEL_OUT_5POINT1 = 252; // 0xfc - field public static final int CHANNEL_OUT_7POINT1 = 1020; // 0x3fc + field public static final deprecated int CHANNEL_OUT_7POINT1 = 1020; // 0x3fc + field public static final int CHANNEL_OUT_7POINT1_SURROUND = 6396; // 0x18fc field public static final int CHANNEL_OUT_BACK_CENTER = 1024; // 0x400 field public static final int CHANNEL_OUT_BACK_LEFT = 64; // 0x40 field public static final int CHANNEL_OUT_BACK_RIGHT = 128; // 0x80 @@ -16102,6 +16099,8 @@ package android.media { field public static final deprecated int NUM_STREAMS = 5; // 0x5 field public static final java.lang.String PROPERTY_OUTPUT_FRAMES_PER_BUFFER = "android.media.property.OUTPUT_FRAMES_PER_BUFFER"; field public static final java.lang.String PROPERTY_OUTPUT_SAMPLE_RATE = "android.media.property.OUTPUT_SAMPLE_RATE"; + field public static final java.lang.String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND"; + field public static final java.lang.String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND"; field public static final java.lang.String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED"; field public static final int RINGER_MODE_NORMAL = 2; // 0x2 field public static final int RINGER_MODE_SILENT = 0; // 0x0 @@ -17608,10 +17607,13 @@ package android.media { method public final void release(); method public void setAudioTrack(android.media.AudioTrack); method public void setCallback(android.media.MediaSync.Callback, android.os.Handler); + method public void setOnErrorListener(android.media.MediaSync.OnErrorListener, android.os.Handler); method public void setPlaybackRate(float, int); method public void setPlaybackSettings(android.media.PlaybackSettings); method public void setSurface(android.view.Surface); method public void setSyncSettings(android.media.SyncSettings); + field public static final int MEDIASYNC_ERROR_AUDIOTRACK_FAIL = 1; // 0x1 + field public static final int MEDIASYNC_ERROR_SURFACE_FAIL = 2; // 0x2 field public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0; // 0x0 field public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 2; // 0x2 field public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1; // 0x1 @@ -17619,7 +17621,11 @@ package android.media { public static abstract class MediaSync.Callback { ctor public MediaSync.Callback(); - method public abstract void onReturnAudioBuffer(android.media.MediaSync, java.nio.ByteBuffer, int); + method public abstract void onAudioBufferConsumed(android.media.MediaSync, java.nio.ByteBuffer, int); + } + + public static abstract interface MediaSync.OnErrorListener { + method public abstract void onError(android.media.MediaSync, int, int); } public class MediaSyncEvent { @@ -17645,6 +17651,14 @@ package android.media { method public abstract void onAudioDeviceConnection(); } + public abstract interface OnAudioRecordRoutingListener { + method public abstract void onAudioRecordRouting(android.media.AudioRecord); + } + + public abstract interface OnAudioTrackRoutingListener { + method public abstract void onAudioTrackRouting(android.media.AudioTrack); + } + public final class PlaybackSettings { ctor public PlaybackSettings(); method public android.media.PlaybackSettings allowDefaults(); @@ -17663,14 +17677,6 @@ package android.media { field public static final int AUDIO_STRETCH_MODE_VOICE = 1; // 0x1 } - public abstract interface OnAudioRecordRoutingListener { - method public abstract void onAudioRecordRouting(android.media.AudioRecord); - } - - public abstract interface OnAudioTrackRoutingListener { - method public abstract void onAudioTrackRouting(android.media.AudioTrack); - } - public final class Rating implements android.os.Parcelable { method public int describeContents(); method public float getPercentRating(); @@ -19104,6 +19110,7 @@ package android.media.tv { method public java.lang.String getRatingSystem(); method public java.util.List<java.lang.String> getSubRatings(); method public static android.media.tv.TvContentRating unflattenFromString(java.lang.String); + field public static final android.media.tv.TvContentRating UNRATED; } public final class TvContentRatingSystemInfo implements android.os.Parcelable { @@ -25293,6 +25300,7 @@ package android.os { method public final android.os.IBinder readStrongBinder(); method public final void readTypedArray(T[], android.os.Parcelable.Creator<T>); method public final void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>); + method public final T readTypedObject(android.os.Parcelable.Creator<T>); method public final java.lang.Object readValue(java.lang.ClassLoader); method public final void recycle(); method public final void setDataCapacity(int); @@ -25337,6 +25345,7 @@ package android.os { method public final void writeStrongInterface(android.os.IInterface); method public final void writeTypedArray(T[], int); method public final void writeTypedList(java.util.List<T>); + method public final void writeTypedObject(T, int); method public final void writeValue(java.lang.Object); field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR; } @@ -30448,13 +30457,6 @@ package android.sax { 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(); @@ -30511,7 +30513,7 @@ package android.security { ctor public KeyChainException(java.lang.Throwable); } - public class KeyExpiredException extends android.security.CryptoOperationException { + public class KeyExpiredException extends java.security.InvalidKeyException { ctor public KeyExpiredException(); ctor public KeyExpiredException(java.lang.String); ctor public KeyExpiredException(java.lang.String, java.lang.Throwable); @@ -30553,7 +30555,7 @@ package android.security { method public android.security.KeyGeneratorSpec.Builder setUserAuthenticators(int); } - public class KeyNotYetValidException extends android.security.CryptoOperationException { + public class KeyNotYetValidException extends java.security.InvalidKeyException { ctor public KeyNotYetValidException(); ctor public KeyNotYetValidException(java.lang.String); ctor public KeyNotYetValidException(java.lang.String, java.lang.Throwable); @@ -30701,12 +30703,12 @@ package android.security { method public boolean isCleartextTrafficPermitted(); } - public class NewFingerprintEnrolledException extends android.security.CryptoOperationException { + public class NewFingerprintEnrolledException extends java.security.InvalidKeyException { ctor public NewFingerprintEnrolledException(); ctor public NewFingerprintEnrolledException(java.lang.String); } - public class UserNotAuthenticatedException extends android.security.CryptoOperationException { + public class UserNotAuthenticatedException extends java.security.InvalidKeyException { ctor public UserNotAuthenticatedException(); ctor public UserNotAuthenticatedException(java.lang.String); ctor public UserNotAuthenticatedException(java.lang.String, java.lang.Throwable); @@ -30960,6 +30962,7 @@ package android.service.notification { method public void registerAsSystemService(android.content.Context, android.content.ComponentName, int) throws android.os.RemoteException; method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); + method public final void setNotificationsShown(java.lang.String[]); method public final void setOnNotificationPostedTrim(int); method public void unregisterAsSystemService() throws android.os.RemoteException; field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 @@ -32751,8 +32754,9 @@ package android.telecom { method public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(); method public int getCallState(); method public android.telecom.PhoneAccountHandle getConnectionManager(); + method public java.lang.String getDefaultDialerPackage(); method public android.telecom.PhoneAccountHandle getDefaultOutgoingPhoneAccount(java.lang.String); - method public android.content.ComponentName getDefaultPhoneApp(); + method public deprecated android.content.ComponentName getDefaultPhoneApp(); method public java.lang.String getLine1Number(android.telecom.PhoneAccountHandle); method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle); method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage(); @@ -32771,6 +32775,7 @@ package android.telecom { method public void showInCallScreen(boolean); method public void silenceRinger(); method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle); + field public static final java.lang.String ACTION_CHANGE_DEFAULT_DIALER = "android.telecom.action.CHANGE_DEFAULT_DIALER"; field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS"; field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.telecom.action.CONNECTION_SERVICE_CONFIGURE"; field public static final java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL"; @@ -32783,6 +32788,7 @@ package android.telecom { field public static final java.lang.String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER"; field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE"; field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE"; + field public static final java.lang.String EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME = "android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME"; field public static final java.lang.String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE"; field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS"; field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS"; diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 8ba2a5a..219d35b 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -142,6 +142,8 @@ public class Am extends BaseCommand { " am task resizeable <TASK_ID> [true|false]\n" + " am task resize <TASK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" + " am get-config\n" + + " am set-idle [--user <USER_ID>] <PACKAGE> true|false\n" + + " am get-idle [--user <USER_ID>] <PACKAGE>\n" + "\n" + "am start: start an Activity. Options are:\n" + " -D: enable debugging\n" + @@ -282,6 +284,11 @@ public class Am extends BaseCommand { "am get-config: retrieve the configuration and any recent configurations\n" + " of the device\n" + "\n" + + "am set-idle: sets the idle state of an app\n" + + "\n" + + "am get-idle: returns the idle state of an app\n" + + "\n" + + "\n" + "<INTENT> specifications include these flags and arguments:\n" + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + @@ -388,6 +395,10 @@ public class Am extends BaseCommand { runTask(); } else if (op.equals("get-config")) { runGetConfig(); + } else if (op.equals("set-idle")) { + runSetIdle(); + } else if (op.equals("get-idle")) { + runGetIdle(); } else { showError("Error: unknown command '" + op + "'"); } @@ -2019,6 +2030,46 @@ public class Am extends BaseCommand { } } + private void runSetIdle() throws Exception { + int userId = UserHandle.USER_OWNER; + + String opt; + while ((opt=nextOption()) != null) { + if (opt.equals("--user")) { + userId = parseUserArg(nextArgRequired()); + } else { + System.err.println("Error: Unknown option: " + opt); + return; + } + } + String packageName = nextArgRequired(); + String value = nextArgRequired(); + + IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService( + Context.USAGE_STATS_SERVICE)); + usm.setAppIdle(packageName, Boolean.parseBoolean(value), userId); + } + + private void runGetIdle() throws Exception { + int userId = UserHandle.USER_OWNER; + + String opt; + while ((opt=nextOption()) != null) { + if (opt.equals("--user")) { + userId = parseUserArg(nextArgRequired()); + } else { + System.err.println("Error: Unknown option: " + opt); + return; + } + } + String packageName = nextArgRequired(); + + IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService( + Context.USAGE_STATS_SERVICE)); + boolean isIdle = usm.isAppIdle(packageName, userId); + System.out.println("Idle=" + isIdle); + } + /** * Open the given file for sending into the system process. This verifies * with SELinux that the system will have access to the file. diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java index 02a329d..da48709 100644 --- a/core/java/android/animation/Animator.java +++ b/core/java/android/animation/Animator.java @@ -16,12 +16,7 @@ package android.animation; -import android.content.res.Configuration; import android.content.res.ConstantState; -import android.content.res.Resources; -import android.util.DisplayMetrics; -import android.util.Log; -import android.view.animation.AnimationUtils; import java.util.ArrayList; @@ -30,29 +25,6 @@ import java.util.ArrayList; * started, ended, and have <code>AnimatorListeners</code> added to them. */ public abstract class Animator implements Cloneable { - /** - * Set this hint when duration for the animation does not need to be scaled. By default, no - * scaling is applied to the duration. - */ - public static final int HINT_NO_SCALE = 0; - - /** - * Set this scale hint (using {@link #setDurationScaleHint(int, Resources)} when the animation's - * moving distance is proportional to the screen size. (e.g. a view coming in from the bottom of - * the screen to top/center). With this scale hint set, the animation duration will be - * automatically scaled based on screen size. - */ - public static final int HINT_DISTANCE_PROPORTIONAL_TO_SCREEN_SIZE = 1; - - /** - * Set this scale hint (using {@link #setDurationScaleHint(int, Resources)}) if the animation - * has pre-defined moving distance in dp that does not vary from device to device. This is - * extremely useful when the animation needs to run on both phones/tablets and TV, because TV - * has inflated dp and therefore will have a longer visual arc for the same animation than on - * the phone. This hint is used to calculate a scaling factor to compensate for different - * visual arcs while maintaining the same angular velocity for the animation. - */ - public static final int HINT_DISTANCE_DEFINED_IN_DP = 2; /** * The set of listeners to be sent events through the life of an animation. @@ -83,24 +55,6 @@ public abstract class Animator implements Cloneable { private AnimatorConstantState mConstantState; /** - * Scaling factor for an animation that moves across the whole screen. - */ - float mScreenSizeBasedDurationScale = 1.0f; - - /** - * Scaling factor for an animation that is defined to move the same amount of dp across all - * devices. - */ - float mDpBasedDurationScale = 1.0f; - - /** - * By default, the scaling assumes the animation moves across the entire screen. - */ - int mDurationScaleHint = HINT_NO_SCALE; - - private final static boolean ANIM_DEBUG = false; - - /** * Starts this animation. If the animation has a nonzero startDelay, the animation will start * running after that delay elapses. A non-delayed animation will have its initial * value(s) set immediately, followed by calls to @@ -230,78 +184,6 @@ public abstract class Animator implements Cloneable { public abstract long getDuration(); /** - * Hints how duration scaling factor should be calculated. The duration will not be scaled when - * hint is set to {@link #HINT_NO_SCALE}. Otherwise, the duration will be automatically scaled - * per device to achieve the same look and feel across different devices. In order to do - * that, the same angular velocity of the animation will be needed on different devices in - * users' field of view. Therefore, the duration scale factor is determined by the ratio of the - * angular movement on current devices to that on the baseline device (i.e. Nexus 5). - * - * @param hint an indicator on how the animation is defined. The hint could be - * {@link #HINT_NO_SCALE}, {@link #HINT_DISTANCE_PROPORTIONAL_TO_SCREEN_SIZE} or - * {@link #HINT_DISTANCE_DEFINED_IN_DP}. - * @param res The resources {@see android.content.res.Resources} for getting display metrics - */ - public void setDurationScaleHint(int hint, Resources res) { - if (ANIM_DEBUG) { - Log.d("ANIM_DEBUG", "distance based duration hint: " + hint); - } - if (hint == mDurationScaleHint) { - return; - } - mDurationScaleHint = hint; - if (hint != HINT_NO_SCALE) { - int uiMode = res.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK; - DisplayMetrics metrics = res.getDisplayMetrics(); - float width = metrics.widthPixels / metrics.xdpi; - float height = metrics.heightPixels / metrics.ydpi; - float viewingDistance = AnimationUtils.getViewingDistance(width, height, uiMode); - if (ANIM_DEBUG) { - Log.d("ANIM_DEBUG", "width, height, viewing distance, uimode: " - + width + ", " + height + ", " + viewingDistance + ", " + uiMode); - } - mScreenSizeBasedDurationScale = AnimationUtils - .getScreenSizeBasedDurationScale(width, height, viewingDistance); - mDpBasedDurationScale = AnimationUtils.getDpBasedDurationScale( - metrics.density, metrics.xdpi, viewingDistance); - if (ANIM_DEBUG) { - Log.d("ANIM_DEBUG", "screen based scale, dp based scale: " + - mScreenSizeBasedDurationScale + ", " + mDpBasedDurationScale); - } - } - } - - // Copies duration scale hint and scaling factors to the new animation. - void copyDurationScaleInfoTo(Animator anim) { - anim.mDurationScaleHint = mDurationScaleHint; - anim.mScreenSizeBasedDurationScale = mScreenSizeBasedDurationScale; - anim.mDpBasedDurationScale = mDpBasedDurationScale; - } - - /** - * @return The scaled duration calculated based on distance of movement (as defined by the - * animation) and perceived velocity (derived from the duration set on the animation for - * baseline device) - */ - public long getDistanceBasedDuration() { - return (long) (getDuration() * getDistanceBasedDurationScale()); - } - - /** - * @return scaling factor of duration based on the duration scale hint. A scaling factor of 1 - * means no scaling will be applied to the duration. - */ - float getDistanceBasedDurationScale() { - if (mDurationScaleHint == HINT_DISTANCE_PROPORTIONAL_TO_SCREEN_SIZE) { - return mScreenSizeBasedDurationScale; - } else if (mDurationScaleHint == HINT_DISTANCE_DEFINED_IN_DP) { - return mDpBasedDurationScale; - } else { - return 1f; - } - } - - /** * The time interpolator used in calculating the elapsed fraction of the * animation. The interpolator determines whether the animation runs with * linear or non-linear motion, such as acceleration and deceleration. The diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java index e47d017..427ecce 100644 --- a/core/java/android/animation/AnimatorInflater.java +++ b/core/java/android/animation/AnimatorInflater.java @@ -70,13 +70,6 @@ public class AnimatorInflater { private static final int VALUE_TYPE_COLOR = 3; private static final int VALUE_TYPE_UNDEFINED = 4; - /** - * Enum values used in XML attributes to indicate the duration scale hint. - */ - private static final int HINT_NO_SCALE = 0; - private static final int HINT_PROPORTIONAL_TO_SCREEN = 1; - private static final int HINT_DEFINED_IN_DP = 2; - private static final boolean DBG_ANIMATOR_INFLATER = false; // used to calculate changing configs for resource references @@ -698,9 +691,6 @@ public class AnimatorInflater { 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.AnimatorSet_durationScaleHint, - HINT_NO_SCALE); - anim.setDurationScaleHint(hint, res); a.recycle(); } else if (name.equals("propertyValuesHolder")) { PropertyValuesHolder[] values = loadValues(res, theme, parser, @@ -1065,9 +1055,6 @@ public class AnimatorInflater { anim.setInterpolator(interpolator); } - final int hint = arrayAnimator.getInt(R.styleable.Animator_durationScaleHint, - HINT_NO_SCALE); - anim.setDurationScaleHint(hint, res); arrayAnimator.recycle(); if (arrayObjectAnimator != null) { arrayObjectAnimator.recycle(); diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java index f6ad847..6503d89 100644 --- a/core/java/android/animation/AnimatorSet.java +++ b/core/java/android/animation/AnimatorSet.java @@ -519,7 +519,6 @@ public final class AnimatorSet extends Animator { for (Node node : mNodes) { node.animation.setAllowRunningAsynchronously(false); - copyDurationScaleInfoTo(node.animation); } if (mDuration >= 0) { diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 292507b..a455f8b 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -17,12 +17,9 @@ package android.animation; import android.annotation.CallSuper; -import android.content.res.Configuration; -import android.content.res.Resources; import android.os.Looper; import android.os.Trace; import android.util.AndroidRuntimeException; -import android.util.DisplayMetrics; import android.util.Log; import android.view.Choreographer; import android.view.animation.AccelerateDecelerateInterpolator; @@ -564,7 +561,7 @@ public class ValueAnimator extends Animator { } private void updateScaledDuration() { - mDuration = (long)(mUnscaledDuration * sDurationScale * getDistanceBasedDurationScale()); + mDuration = (long)(mUnscaledDuration * sDurationScale); } /** diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index ab5f811..9bad9bb 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -255,23 +255,18 @@ public final class ActivityThread { } } - static final class AcquiringProviderRecord { - IActivityManager.ContentProviderHolder holder; - boolean acquiring = true; - int requests = 1; - // Set if there was a runtime exception when trying to acquire the provider. - RuntimeException runtimeException = null; - } - // The lock of mProviderMap protects the following variables. - final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap = new ArrayMap<>(); - final ArrayMap<ProviderKey, AcquiringProviderRecord> mAcquiringProviderMap = new ArrayMap<>(); - final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap = new ArrayMap<>(); - final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders = new ArrayMap<>(); - final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName = new ArrayMap<>(); + final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap + = new ArrayMap<ProviderKey, ProviderClientRecord>(); + final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap + = new ArrayMap<IBinder, ProviderRefCount>(); + final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders + = new ArrayMap<IBinder, ProviderClientRecord>(); + final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName + = new ArrayMap<ComponentName, ProviderClientRecord>(); final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners - = new ArrayMap<>(); + = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>(); final GcIdler mGcIdler = new GcIdler(); boolean mGcIdlerScheduled = false; @@ -351,7 +346,7 @@ public final class ActivityThread { } } - static final class ProviderClientRecord { + final class ProviderClientRecord { final String[] mNames; final IContentProvider mProvider; final ContentProvider mLocalProvider; @@ -4716,74 +4711,23 @@ public final class ActivityThread { public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) { - final ProviderKey key = new ProviderKey(auth, userId); - final IContentProvider provider = acquireExistingProvider(c, key, stable); + final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable); if (provider != null) { return provider; } - AcquiringProviderRecord r; - boolean first = false; - synchronized (mAcquiringProviderMap) { - r = mAcquiringProviderMap.get(key); - if (r == null) { - r = new AcquiringProviderRecord(); - mAcquiringProviderMap.put(key, r); - first = true; - } else { - r.requests++; - } - } + // There is a possible race here. Another thread may try to acquire + // the same provider at the same time. When this happens, we want to ensure + // that the first one wins. + // Note that we cannot hold the lock while acquiring and installing the + // provider since it might take a long time to run and it could also potentially + // be re-entrant in the case where the provider is in the same process. IActivityManager.ContentProviderHolder holder = null; try { - if (first) { - // Multiple threads may try to acquire the same provider at the same time. - // When this happens, we only let the first one really gets provider. - // Other threads just wait for its result. - // Note that we cannot hold the lock while acquiring and installing the - // provider since it might take a long time to run and it could also potentially - // be re-entrant in the case where the provider is in the same process. - holder = ActivityManagerNative.getDefault().getContentProvider( - getApplicationThread(), auth, userId, stable); - } else { - synchronized (r) { - while (r.acquiring) { - try { - r.wait(); - } catch (InterruptedException e) { - } - } - holder = r.holder; - } - } + holder = ActivityManagerNative.getDefault().getContentProvider( + getApplicationThread(), auth, userId, stable); } catch (RemoteException ex) { - } catch (RuntimeException e) { - synchronized (r) { - r.runtimeException = e; - } - } finally { - if (first) { - synchronized (r) { - r.holder = holder; - r.acquiring = false; - r.notifyAll(); - } - } - - synchronized (mAcquiringProviderMap) { - if (--r.requests == 0) { - mAcquiringProviderMap.remove(key); - } - } - - if (r.runtimeException != null) { - // Was set when the first thread tried to acquire the provider, - // but we should make sure it is thrown for all threads trying to - // acquire the provider. - throw r.runtimeException; - } } - if (holder == null) { Slog.e(TAG, "Failed to find provider info for " + auth); return null; @@ -4866,12 +4810,8 @@ public final class ActivityThread { public final IContentProvider acquireExistingProvider( Context c, String auth, int userId, boolean stable) { - return acquireExistingProvider(c, new ProviderKey(auth, userId), stable); - } - - final IContentProvider acquireExistingProvider( - Context c, ProviderKey key, boolean stable) { synchronized (mProviderMap) { + final ProviderKey key = new ProviderKey(auth, userId); final ProviderClientRecord pr = mProviderMap.get(key); if (pr == null) { return null; @@ -4882,7 +4822,7 @@ public final class ActivityThread { if (!jBinder.isBinderAlive()) { // The hosting process of the provider has died; we can't // use this one. - Log.i(TAG, "Acquiring provider " + key.authority + " for user " + key.userId + Log.i(TAG, "Acquiring provider " + auth + " for user " + userId + ": existing object's process dead"); handleUnstableProviderDiedLocked(jBinder, true); return null; @@ -5204,12 +5144,18 @@ public final class ActivityThread { if (DEBUG_PROVIDER) { Slog.v(TAG, "installProvider: lost the race, updating ref count"); } - // The provider has already been installed, so we need - // to increase reference count to the existing one, but - // only if release is needed (that is, it is not running - // in the system process or local to the process). + // We need to transfer our new reference to the existing + // ref count, releasing the old one... but only if + // release is needed (that is, it is not running in the + // system process). if (!noReleaseNeeded) { incProviderRefLocked(prc, stable); + try { + ActivityManagerNative.getDefault().removeContentProvider( + holder.connection, stable); + } catch (RemoteException e) { + //do nothing content provider object is dead any way + } } } else { ProviderClientRecord client = installProviderAuthoritiesLocked( diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index e275df0..ac8d5d8 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -67,6 +67,8 @@ interface INotificationManager void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id); void cancelNotificationsFromListener(in INotificationListener token, in String[] keys); + void setNotificationsShownFromListener(in INotificationListener token, in String[] keys); + ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys, int trim); void requestHintsFromListener(in INotificationListener token, int hints); int getHintsFromListener(in INotificationListener token); diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index 4ed1489..23659e3 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -30,4 +30,6 @@ interface IUsageStatsManager { ParceledListSlice queryConfigurationStats(int bucketType, long beginTime, long endTime, String callingPackage); UsageEvents queryEvents(long beginTime, long endTime, String callingPackage); + void setAppIdle(String packageName, boolean idle, int userId); + boolean isAppIdle(String packageName, int userId); } diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index bc6099a..8a01d66 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -19,6 +19,7 @@ package android.app.usage; import android.content.Context; import android.content.pm.ParceledListSlice; import android.os.RemoteException; +import android.os.UserHandle; import android.util.ArrayMap; import java.util.Collections; @@ -217,4 +218,20 @@ public final class UsageStatsManager { } return aggregatedStats; } + + /** + * Returns whether the specified app is currently considered idle. This will be true if the + * app hasn't been used directly or indirectly for a period of time defined by the system. This + * could be of the order of several hours or days. + * @param packageName The package name of the app to query + * @return whether the app is currently considered idle + */ + public boolean isAppIdle(String packageName) { + try { + return mService.isAppIdle(packageName, UserHandle.myUserId()); + } catch (RemoteException e) { + // fall through and return default + } + return false; + } } diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java index 691798f..a4d6be0 100644 --- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java +++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java @@ -326,6 +326,9 @@ public class RequestThreadManager { } try { + startPreview(); // If preview is not running (i.e. after a JPEG capture), we need to + // explicitely start and stop preview before setting preview surface. + // null. stopPreview(); } catch (RuntimeException e) { Log.e(TAG, "Received device exception in configure call: ", e); diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 481fc2f..1b57055 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1440,7 +1440,8 @@ public class InputMethodService extends AbstractInputMethodService { void showWindowInner(boolean showInput) { boolean doShowInput = false; - boolean wasVisible = mWindowVisible; + final int previousImeWindowStatus = + (mWindowVisible ? IME_ACTIVE : 0) | (isInputViewShown() ? IME_VISIBLE : 0); mWindowVisible = true; if (!mShowInputRequested) { if (mInputStarted) { @@ -1485,9 +1486,12 @@ public class InputMethodService extends AbstractInputMethodService { startExtractingText(false); } - if (!wasVisible) { + final int nextImeWindowStatus = IME_ACTIVE | (isInputViewShown() ? IME_VISIBLE : 0); + if (previousImeWindowStatus != nextImeWindowStatus) { + mImm.setImeWindowStatus(mToken, nextImeWindowStatus, mBackDisposition); + } + if ((previousImeWindowStatus & IME_ACTIVE) == 0) { if (DEBUG) Log.v(TAG, "showWindow: showing!"); - mImm.setImeWindowStatus(mToken, IME_ACTIVE, mBackDisposition); onWindowShown(); mWindow.show(); } diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 43309c0..8c1f44f 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -115,15 +115,15 @@ import java.util.Set; * later reading.</p> * * <p>There are also some methods that provide a more efficient way to work - * with Parcelables: {@link #writeTypedArray}, - * {@link #writeTypedList(List)}, - * {@link #readTypedArray} and {@link #readTypedList}. These methods + * with Parcelables: {@link #writeTypedObject}, {@link #writeTypedArray}, + * {@link #writeTypedList}, {@link #readTypedObject}, + * {@link #createTypedArray} and {@link #createTypedArrayList}. These methods * do not write the class information of the original object: instead, the * caller of the read function must know what type to expect and pass in the * appropriate {@link Parcelable.Creator Parcelable.Creator} instead to * properly construct the new object and read its data. (To more efficient - * write and read a single Parceable object, you can directly call - * {@link Parcelable#writeToParcel Parcelable.writeToParcel} and + * write and read a single Parceable object that is not null, you can directly + * call {@link Parcelable#writeToParcel Parcelable.writeToParcel} and * {@link Parcelable.Creator#createFromParcel Parcelable.Creator.createFromParcel} * yourself.)</p> * @@ -1223,6 +1223,24 @@ public final class Parcel { } /** + * Flatten the Parcelable object into the parcel. + * + * @param val The Parcelable object to be written. + * @param parcelableFlags Contextual flags as per + * {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}. + * + * @see #readTypedObject + */ + public final <T extends Parcelable> void writeTypedObject(T val, int parcelableFlags) { + if (val != null) { + writeInt(1); + val.writeToParcel(this, parcelableFlags); + } else { + writeInt(0); + } + } + + /** * Flatten a generic object in to a parcel. The given Object value may * currently be one of the following types: * @@ -2138,6 +2156,25 @@ public final class Parcel { } /** + * Read and return a typed Parcelable object from a parcel. + * Returns null if the previous written object was null. + * The object <em>must</em> have previous been written via + * {@link #writeTypedObject} with the same object type. + * + * @return A newly created object of the type that was previously + * written. + * + * @see #writeTypedObject + */ + public final <T> T readTypedObject(Parcelable.Creator<T> c) { + if (readInt() != 0) { + return c.createFromParcel(this); + } else { + return null; + } + } + + /** * Write a heterogeneous array of Parcelable objects into the Parcel. * Each object in the array is written along with its class name, so * that the correct class can later be instantiated. As a result, this diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index cc7f880..35b8819 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -358,6 +358,20 @@ public abstract class NotificationListenerService extends Service { } /** + * Inform the notification manager that these notifications have been viewed by the + * user. + * @param keys Notifications to mark as seen. + */ + public final void setNotificationsShown(String[] keys) { + if (!isBound()) return; + try { + getNotificationInterface().setNotificationsShownFromListener(mWrapper, keys); + } catch (android.os.RemoteException ex) { + Log.v(TAG, "Unable to contact notification manager", ex); + } + } + + /** * Sets the notification trim that will be received via {@link #onNotificationPosted}. * * <p> diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java index 0417921..4d1209a 100644 --- a/core/java/android/view/animation/AnimationUtils.java +++ b/core/java/android/view/animation/AnimationUtils.java @@ -16,7 +16,6 @@ package android.view.animation; -import android.content.res.Configuration; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -45,16 +44,6 @@ public class AnimationUtils { private static final int TOGETHER = 0; private static final int SEQUENTIALLY = 1; - private static final float RECOMMENDED_FIELD_OF_VIEW_FOR_TV = 40f; - private static final float ESTIMATED_VIEWING_DISTANCE_FOR_WATCH = 11f; - private static final float AVERAGE_VIEWING_DISTANCE_FOR_PHONES = 14.2f; - private static final float N5_DIAGONAL_VIEW_ANGLE = 19.58f; - private static final float N5_DENSITY = 3.0f; - private static final float N5_DPI = 443f; - - private static final float COTANGENT_OF_HALF_TV_ANGLE = (float) (1 / Math.tan(Math.toRadians - (RECOMMENDED_FIELD_OF_VIEW_FOR_TV / 2))); - /** * Returns the current animation time in milliseconds. This time should be used when invoking @@ -378,78 +367,4 @@ public class AnimationUtils { } return interpolator; } - - /** - * Derives the viewing distance of a device based on the device size (in inches), and the - * device type. - * @hide - */ - public static float getViewingDistance(float width, float height, int uiMode) { - if (uiMode == Configuration.UI_MODE_TYPE_TELEVISION) { - // TV - return (width / 2) * COTANGENT_OF_HALF_TV_ANGLE; - } else if (uiMode == Configuration.UI_MODE_TYPE_WATCH) { - // Watch - return ESTIMATED_VIEWING_DISTANCE_FOR_WATCH; - } else { - // Tablet, phone, etc - return AVERAGE_VIEWING_DISTANCE_FOR_PHONES; - } - } - - /** - * Calculates the duration scaling factor of an animation based on the hint that the animation - * will move across the entire screen. A scaling factor of 1 means the duration on this given - * device will be the same as the duration set through - * {@link android.animation.Animator#setDuration(long)}. The calculation uses Nexus 5 as a - * baseline device. That is, the duration of the animation on a given device will scale its - * duration so that it has the same look and feel as the animation on Nexus 5. In order to - * achieve the same perceived effect of the animation across different devices, we maintain - * the same angular speed of the same animation in users' field of view. Therefore, the - * duration scale factor is determined by the ratio of the angular movement on current - * devices to that on the baseline device. - * - * @param width width of the screen (in inches) - * @param height height of the screen (in inches) - * @param viewingDistance the viewing distance of the device (i.e. watch, phone, TV, etc) in - * inches - * @return scaling factor (or multiplier) of the duration set through - * {@link android.animation.Animator#setDuration(long)} on current device. - * @hide - */ - public static float getScreenSizeBasedDurationScale(float width, float height, - float viewingDistance) { - // Animation's moving distance is proportional to the screen size. - float diagonal = (float) Math.sqrt(width * width + height * height); - float diagonalViewAngle = (float) Math.toDegrees(Math.atan((diagonal / 2f) - / viewingDistance) * 2); - return diagonalViewAngle / N5_DIAGONAL_VIEW_ANGLE; - } - - /** - * Calculates the duration scaling factor of an animation under the assumption that the - * animation is defined to move the same amount of distance (in dp) across all devices. A - * scaling factor of 1 means the duration on this given device will be the same as the - * duration set through {@link android.animation.Animator#setDuration(long)}. The calculation - * uses Nexus 5 as a baseline device. That is, the duration of the animation on a given - * device will scale its duration so that it has the same look and feel as the animation on - * Nexus 5. In order to achieve the same perceived effect of the animation across different - * devices, we maintain the same angular velocity of the same animation in users' field of - * view. Therefore, the duration scale factor is determined by the ratio of the angular - * movement on current devices to that on the baseline device. - * - * @param density logical density of the display. {@link android.util.DisplayMetrics#density} - * @param dpi pixels per inch - * @param viewingDistance viewing distance of the device (in inches) - * @return the scaling factor of duration - * @hide - */ - public static float getDpBasedDurationScale(float density, float dpi, - float viewingDistance) { - // Angle in users' field of view per dp: - float anglePerDp = (float) Math.atan2((density / dpi) / 2, viewingDistance) * 2; - float baselineAnglePerDp = (float) Math.atan2((N5_DENSITY / N5_DPI) / 2, - AVERAGE_VIEWING_DISTANCE_FOR_PHONES) * 2; - return anglePerDp / baselineAnglePerDp; - } } diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index 9ecdc9c..c959774 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -1854,20 +1854,19 @@ public class GridView extends AbsListView { moved = true; } break; - case FOCUS_LEFT: - if (selectedPosition > startOfRowPos) { - mLayoutMode = LAYOUT_MOVE_SELECTION; - setSelectionInt(Math.max(0, selectedPosition - 1)); - moved = true; - } - break; - case FOCUS_RIGHT: - if (selectedPosition < endOfRowPos) { - mLayoutMode = LAYOUT_MOVE_SELECTION; - setSelectionInt(Math.min(selectedPosition + 1, mItemCount - 1)); - moved = true; - } - break; + } + + final boolean isLayoutRtl = isLayoutRtl(); + if (selectedPosition > startOfRowPos && ((direction == FOCUS_LEFT && !isLayoutRtl) || + (direction == FOCUS_RIGHT && isLayoutRtl))) { + mLayoutMode = LAYOUT_MOVE_SELECTION; + setSelectionInt(Math.max(0, selectedPosition - 1)); + moved = true; + } else if (selectedPosition < endOfRowPos && ((direction == FOCUS_LEFT && isLayoutRtl) || + (direction == FOCUS_RIGHT && !isLayoutRtl))) { + mLayoutMode = LAYOUT_MOVE_SELECTION; + setSelectionInt(Math.min(selectedPosition + 1, mItemCount - 1)); + moved = true; } if (moved) { diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java index a50941b..10e4db3 100644 --- a/core/java/android/widget/RemoteViewsAdapter.java +++ b/core/java/android/widget/RemoteViewsAdapter.java @@ -1335,10 +1335,6 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback // If we are not connected, queue up the notifyDataSetChanged to be handled when we do // connect if (!mServiceConnection.isConnected()) { - if (mNotifyDataSetChangedAfterOnServiceConnected) { - return; - } - mNotifyDataSetChangedAfterOnServiceConnected = true; requestBindService(); return; diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java index f7e9648..c0c8aec 100644 --- a/core/java/android/widget/ZoomButtonsController.java +++ b/core/java/android/widget/ZoomButtonsController.java @@ -403,7 +403,7 @@ public class ZoomButtonsController implements View.OnTouchListener { // No longer care about configuration changes mContext.unregisterReceiver(mConfigurationChangedReceiver); - mWindowManager.removeView(mContainer); + mWindowManager.removeViewImmediate(mContainer); mHandler.removeCallbacks(mPostedVisibleInitializer); if (mCallback != null) { @@ -490,7 +490,7 @@ public class ZoomButtonsController implements View.OnTouchListener { setVisible(false); return true; } - + } else { dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT); } diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index 8b2c269..2f6a69c 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -189,32 +189,44 @@ sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audio return getAudioTrack(env, audioTrackObj); } +// This function converts Java channel masks to a native channel mask. +// validity should be checked with audio_is_output_channel(). +static inline audio_channel_mask_t nativeChannelMaskFromJavaChannelMasks( + jint channelPositionMask, jint channelIndexMask) +{ + if (channelIndexMask != 0) { // channel index mask takes priority + // To convert to a native channel mask, the Java channel index mask + // requires adding the index representation. + return audio_channel_mask_from_representation_and_bits( + AUDIO_CHANNEL_REPRESENTATION_INDEX, + channelIndexMask); + } + // To convert to a native channel mask, the Java channel position mask + // requires a shift by 2 to skip the two deprecated channel + // configurations "default" and "mono". + return (audio_channel_mask_t)(channelPositionMask >> 2); +} + // ---------------------------------------------------------------------------- static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, jobject jaa, - jint sampleRateInHertz, jint javaChannelMask, + jint sampleRateInHertz, jint channelPositionMask, jint channelIndexMask, jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession) { - ALOGV("sampleRate=%d, audioFormat(from Java)=%d, channel mask=%x, buffSize=%d", - sampleRateInHertz, audioFormat, javaChannelMask, buffSizeInBytes); + ALOGV("sampleRate=%d, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d", + sampleRateInHertz, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes); if (jaa == 0) { ALOGE("Error creating AudioTrack: invalid audio attributes"); return (jint) AUDIO_JAVA_ERROR; } - // Java channel masks don't map directly to the native definition for positional - // channel masks: it's a shift by 2 to skip the two deprecated channel - // configurations "default" and "mono". // Invalid channel representations are caught by !audio_is_output_channel() below. - audio_channel_mask_t nativeChannelMask = - audio_channel_mask_get_representation(javaChannelMask) - == AUDIO_CHANNEL_REPRESENTATION_POSITION - ? javaChannelMask >> 2 : javaChannelMask; - + audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks( + channelPositionMask, channelIndexMask); if (!audio_is_output_channel(nativeChannelMask)) { - ALOGE("Error creating AudioTrack: invalid channel mask %#x.", javaChannelMask); + ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask); return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK; } @@ -982,7 +994,7 @@ static JNINativeMethod gMethods[] = { {"native_stop", "()V", (void *)android_media_AudioTrack_stop}, {"native_pause", "()V", (void *)android_media_AudioTrack_pause}, {"native_flush", "()V", (void *)android_media_AudioTrack_flush}, - {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;IIIII[I)I", + {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;IIIIII[I)I", (void *)android_media_AudioTrack_setup}, {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize}, {"native_release", "()V", (void *)android_media_AudioTrack_release}, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 4f26eb2..018c1a1 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2106,6 +2106,11 @@ android:protectionLevel="signature|development|appop" /> <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" /> + <!-- @hide Allows an application to change the app idle state of an app. + <p>Not for use by third-party applications. --> + <permission android:name="android.permission.CHANGE_APP_IDLE_STATE" + android:protectionLevel="signature" /> + <!-- @SystemApi Allows an application to collect battery statistics --> <permission android:name="android.permission.BATTERY_STATS" android:protectionLevel="signature|system|development" /> diff --git a/core/res/res/drawable/list_highlight_material.xml b/core/res/res/drawable/list_choice_background_material.xml index 5a930c4..5a930c4 100644 --- a/core/res/res/drawable/list_highlight_material.xml +++ b/core/res/res/drawable/list_choice_background_material.xml diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 00c771d..887b0a5 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -6038,19 +6038,8 @@ <!-- values are colors, which are integers starting with "#". --> <enum name="colorType" value="3" /> </attr> - <!-- Defines whether the animation should adjust duration in order to achieve the same - perceived effects on different devices. --> - <attr name="durationScaleHint" > - <!-- Default value for scale hint. When set, duration will not be scaled.--> - <enum name="noScale" value="0"/> - <!-- This should be used when the animation's moving distance is proportional to screen, - as the scaling is based on screen size. --> - <enum name="screenBased" value="1"/> - <!-- This is for animations that have a distance defined in dp, which will be the same - across different devices. In this case, scaling is based on the physical distance - per dp on the current device. --> - <enum name="dpBased" value="2"/> - </attr> + <!-- Placeholder for a deleted attribute. This should be removed before M release. --> + <attr name="removeBeforeMRelease" format="integer" /> </declare-styleable> <declare-styleable name="PropertyValuesHolder"> @@ -6099,7 +6088,6 @@ <!-- 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/public.xml b/core/res/res/values/public.xml index baccafd..875659d 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2664,8 +2664,8 @@ <public type="attr" name="supportsAssistGesture" /> <public type="attr" name="thumbPosition" /> - <!-- Animation --> - <public type="attr" name="durationScaleHint" /> + <!-- Placeholder for a removed attribute. Remove this before M release. --> + <public type="attr" name="removeBeforeMRelease" /> <public type="attr" name="lockTaskMode" /> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index db178fa..f81ee8c 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -614,7 +614,7 @@ please see styles_device_defaults.xml. <style name="Widget.Material.GestureOverlayView" parent="Widget.GestureOverlayView"/> <style name="Widget.Material.GridView" parent="Widget.GridView"> - <item name="listSelector">?attr/selectableItemBackground</item> + <item name="listSelector">?attr/listChoiceBackgroundIndicator</item> </style> <style name="Widget.Material.CalendarView" parent="Widget.CalendarView"> diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml index a413d91..e8aab07 100644 --- a/core/res/res/values/themes_material.xml +++ b/core/res/res/values/themes_material.xml @@ -129,8 +129,8 @@ please see themes_device_defaults.xml. <item name="listChoiceIndicatorSingle">@drawable/btn_radio_material_anim</item> <item name="listChoiceIndicatorMultiple">@drawable/btn_check_material_anim</item> - <item name="listChoiceBackgroundIndicator">@drawable/list_highlight_material</item> - <item name="activatedBackgroundIndicator">@null</item> + <item name="listChoiceBackgroundIndicator">@drawable/list_choice_background_material</item> + <item name="activatedBackgroundIndicator">@drawable/activated_background_material</item> <item name="listDividerAlertDialog">@null</item> @@ -485,7 +485,7 @@ please see themes_device_defaults.xml. <item name="listChoiceIndicatorSingle">@drawable/btn_radio_material_anim</item> <item name="listChoiceIndicatorMultiple">@drawable/btn_check_material_anim</item> - <item name="listChoiceBackgroundIndicator">?attr/selectableItemBackground</item> + <item name="listChoiceBackgroundIndicator">@drawable/list_choice_background_material</item> <item name="activatedBackgroundIndicator">@drawable/activated_background_material</item> <item name="expandableListPreferredItemPaddingLeft">40dip</item> diff --git a/docs/html/google/play-services/index.jd b/docs/html/google/play-services/index.jd index d674f7f..5ccdcb9 100644 --- a/docs/html/google/play-services/index.jd +++ b/docs/html/google/play-services/index.jd @@ -74,30 +74,8 @@ announcement <a href="http://android-developers.blogspot.com/2015/04/theres-lot-to-explore-with-google-play.html" class="external-link">blog post</a>.</p> <ul> - <li><strong>Maps</strong> - This release makes the Google Maps Android API v2 available on -<a href="https://developers.google.com/maps/documentation/android/wear" class="external-link"> -Android Wear</a>, so you can now create map-based apps that run directly on wearable devices. In -addition, the Maps API now offers a new -<a href="{@docRoot}reference/com/google/android/gms/maps/StreetViewPanorama.OnStreetViewPanoramaLongClickListener.html"> -{@code OnStreetViewPanoramaLongClickListener}</a> interface, similar to the existing -<a href="{@docRoot}reference/com/google/android/gms/maps/GoogleMap.OnMapLongClickListener.html"> -{@code OnMapLongClickListener}</a> interface. These listeners are particularly helpful -for wearable devices, so you can let users exit from the app by long-clicking on a map or panorama. -On a wearable device, the swipe gesture is used to pan the map instead of exiting the app. - <ul> - <li><a href="https://developers.google.com/maps/documentation/android/wear" - class="external-link">Google Maps on Android Wear developer guide</a> - </li> - <li><a href="https://github.com/googlemaps/android-samples/tree/master/BasicWearMap" - class="external-link">Google Maps on Android Wear sample</a> - </li> - <li><a href="https://developers.google.com/maps/documentation/android/releases" - class="external-link">Release notes</a> - </li> - </ul> - </li> <li> - <strong>Wear</strong> - In addition to Maps support, this release provides you with the ability + <strong>Wear</strong> - This release provides you with the ability to advertise and discover the capabilities of devices that are connected in a Wear network, through the new <a href="{@docRoot}reference/com/google/android/gms/wearable/CapabilityApi.html"> {@code CapabilityApi}</a> class. The new diff --git a/keystore/java/android/security/AndroidKeyPairGenerator.java b/keystore/java/android/security/AndroidKeyPairGenerator.java index 5fae831..3b25ba6 100644 --- a/keystore/java/android/security/AndroidKeyPairGenerator.java +++ b/keystore/java/android/security/AndroidKeyPairGenerator.java @@ -17,7 +17,7 @@ package android.security; import com.android.org.bouncycastle.x509.X509V3CertificateGenerator; -import com.android.org.conscrypt.NativeCrypto; +import com.android.org.conscrypt.NativeConstants; import com.android.org.conscrypt.OpenSSLEngine; import java.security.InvalidAlgorithmParameterException; @@ -206,9 +206,9 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { } private static int getDefaultKeySize(int keyType) { - if (keyType == NativeCrypto.EVP_PKEY_EC) { + if (keyType == NativeConstants.EVP_PKEY_EC) { return EC_DEFAULT_KEY_SIZE; - } else if (keyType == NativeCrypto.EVP_PKEY_RSA) { + } else if (keyType == NativeConstants.EVP_PKEY_RSA) { return RSA_DEFAULT_KEY_SIZE; } return -1; @@ -216,12 +216,12 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { private static void checkValidKeySize(String keyAlgorithm, int keyType, int keySize) throws InvalidAlgorithmParameterException { - if (keyType == NativeCrypto.EVP_PKEY_EC) { + if (keyType == NativeConstants.EVP_PKEY_EC) { if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) { throw new InvalidAlgorithmParameterException("EC keys must be >= " + EC_MIN_KEY_SIZE + " and <= " + EC_MAX_KEY_SIZE); } - } else if (keyType == NativeCrypto.EVP_PKEY_RSA) { + } else if (keyType == NativeConstants.EVP_PKEY_RSA) { if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) { throw new InvalidAlgorithmParameterException("RSA keys must be >= " + RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE); @@ -234,7 +234,7 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { private static void checkCorrectParametersSpec(int keyType, int keySize, AlgorithmParameterSpec spec) throws InvalidAlgorithmParameterException { - if (keyType == NativeCrypto.EVP_PKEY_RSA && spec != null) { + if (keyType == NativeConstants.EVP_PKEY_RSA && spec != null) { if (spec instanceof RSAKeyGenParameterSpec) { RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) spec; if (keySize != -1 && keySize != rsaSpec.getKeysize()) { @@ -260,7 +260,7 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { private static byte[][] getArgsForKeyType(int keyType, AlgorithmParameterSpec spec) { switch (keyType) { - case NativeCrypto.EVP_PKEY_RSA: + case NativeConstants.EVP_PKEY_RSA: if (spec instanceof RSAKeyGenParameterSpec) { RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) spec; return new byte[][] { rsaSpec.getPublicExponent().toByteArray() }; diff --git a/keystore/java/android/security/CryptoOperationException.java b/keystore/java/android/security/CryptoOperationException.java deleted file mode 100644 index 1c9d005..0000000 --- a/keystore/java/android/security/CryptoOperationException.java +++ /dev/null @@ -1,59 +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; - -/** - * Base class for exceptions during cryptographic operations which cannot throw a suitable checked - * exception. - * - * <p>The contract of the majority of crypto primitives/operations (e.g. {@code Cipher} or - * {@code Signature}) is that they can throw a checked exception during initialization, but are not - * 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. - */ -public class CryptoOperationException extends RuntimeException { - - /** - * Constructs a new {@code CryptoOperationException} without detail message and cause. - */ - public CryptoOperationException() { - super(); - } - - /** - * Constructs a new {@code CryptoOperationException} with the provided detail message and no - * cause. - */ - public CryptoOperationException(String message) { - super(message); - } - - /** - * Constructs a new {@code CryptoOperationException} with the provided detail message and cause. - */ - public CryptoOperationException(String message, Throwable cause) { - super(message, cause); - } - - /** - * Constructs a new {@code CryptoOperationException} with the provided cause. - */ - public CryptoOperationException(Throwable cause) { - super(cause); - } -} diff --git a/keystore/java/android/security/KeyExpiredException.java b/keystore/java/android/security/KeyExpiredException.java index a02dc33..f58e48a 100644 --- a/keystore/java/android/security/KeyExpiredException.java +++ b/keystore/java/android/security/KeyExpiredException.java @@ -16,11 +16,13 @@ package android.security; +import java.security.InvalidKeyException; + /** * Indicates that a cryptographic operation failed because the employed key's validity end date * is in the past. */ -public class KeyExpiredException extends CryptoOperationException { +public class KeyExpiredException extends InvalidKeyException { /** * Constructs a new {@code KeyExpiredException} without detail message and cause. diff --git a/keystore/java/android/security/KeyNotYetValidException.java b/keystore/java/android/security/KeyNotYetValidException.java index 964cd7e..4ea27ef 100644 --- a/keystore/java/android/security/KeyNotYetValidException.java +++ b/keystore/java/android/security/KeyNotYetValidException.java @@ -16,11 +16,13 @@ package android.security; +import java.security.InvalidKeyException; + /** * Indicates that a cryptographic operation failed because the employed key's validity start date * is in the future. */ -public class KeyNotYetValidException extends CryptoOperationException { +public class KeyNotYetValidException extends InvalidKeyException { /** * Constructs a new {@code KeyNotYetValidException} without detail message and cause. diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 5af0527..8c49ff0 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -16,7 +16,7 @@ package android.security; -import com.android.org.conscrypt.NativeCrypto; +import com.android.org.conscrypt.NativeConstants; import android.os.Binder; import android.os.IBinder; @@ -30,6 +30,7 @@ import android.security.keymaster.KeymasterDefs; import android.security.keymaster.OperationResult; import android.util.Log; +import java.security.InvalidKeyException; import java.util.Locale; /** @@ -87,9 +88,9 @@ public class KeyStore { static int getKeyTypeForAlgorithm(String keyType) { if ("RSA".equalsIgnoreCase(keyType)) { - return NativeCrypto.EVP_PKEY_RSA; + return NativeConstants.EVP_PKEY_RSA; } else if ("EC".equalsIgnoreCase(keyType)) { - return NativeCrypto.EVP_PKEY_EC; + return NativeConstants.EVP_PKEY_EC; } else { return -1; } @@ -508,7 +509,11 @@ public class KeyStore { } } - public static KeyStoreException getKeyStoreException(int errorCode) { + /** + * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error + * code. + */ + static KeyStoreException getKeyStoreException(int errorCode) { if (errorCode > 0) { // KeyStore layer error switch (errorCode) { @@ -544,7 +549,11 @@ public class KeyStore { } } - public static CryptoOperationException getCryptoOperationException(KeyStoreException e) { + /** + * Returns an {@link InvalidKeyException} corresponding to the provided + * {@link KeyStoreException}. + */ + static InvalidKeyException getInvalidKeyException(KeyStoreException e) { switch (e.getErrorCode()) { case KeymasterDefs.KM_ERROR_KEY_EXPIRED: return new KeyExpiredException(); @@ -556,11 +565,15 @@ public class KeyStore { // case KeymasterDefs.KM_ERROR_TBD // return new NewFingerprintEnrolledException(); default: - return new CryptoOperationException("Crypto operation failed", e); + return new InvalidKeyException("Keystore operation failed", e); } } - public static CryptoOperationException getCryptoOperationException(int errorCode) { - return getCryptoOperationException(getKeyStoreException(errorCode)); + /** + * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error + * code. + */ + static InvalidKeyException getInvalidKeyException(int errorCode) { + return getInvalidKeyException(getKeyStoreException(errorCode)); } } diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java index 1f8d8ec..3b13e83 100644 --- a/keystore/java/android/security/KeyStoreCipherSpi.java +++ b/keystore/java/android/security/KeyStoreCipherSpi.java @@ -136,6 +136,14 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry private Long mOperationHandle; private KeyStoreCryptoOperationChunkedStreamer mMainDataStreamer; + /** + * Encountered exception which could not be immediately thrown because it was encountered inside + * a method that does not throw checked exception. This exception will be thrown from + * {@code engineDoFinal}. Once such an exception is encountered, {@code engineUpdate} and + * {@code engineDoFinal} start ignoring input data. + */ + private Exception mCachedException; + protected KeyStoreCipherSpi( int keymasterAlgorithm, int keymasterBlockMode, @@ -158,7 +166,11 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry try { init(opmode, key, random); initAlgorithmSpecificParameters(); - ensureKeystoreOperationInitialized(); + try { + ensureKeystoreOperationInitialized(); + } catch (InvalidAlgorithmParameterException e) { + throw new InvalidKeyException(e); + } success = true; } finally { if (!success) { @@ -236,6 +248,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry mOperationToken = null; mOperationHandle = null; mMainDataStreamer = null; + mCachedException = null; } private void resetWhilePreservingInitState() { @@ -247,12 +260,17 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry mOperationHandle = null; mMainDataStreamer = null; mAdditionalEntropyForBegin = null; + mCachedException = null; } - private void ensureKeystoreOperationInitialized() { + private void ensureKeystoreOperationInitialized() throws InvalidKeyException, + InvalidAlgorithmParameterException { if (mMainDataStreamer != null) { return; } + if (mCachedException != null) { + return; + } if (mKey == null) { throw new IllegalStateException("Not initialized"); } @@ -281,11 +299,15 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry if (opResult == null) { throw new KeyStoreConnectException(); } else if (opResult.resultCode != KeyStore.NO_ERROR) { - throw KeyStore.getCryptoOperationException(opResult.resultCode); + switch (opResult.resultCode) { + case KeymasterDefs.KM_ERROR_INVALID_NONCE: + throw new InvalidAlgorithmParameterException("Invalid IV"); + } + throw KeyStore.getInvalidKeyException(opResult.resultCode); } if (opResult.token == null) { - throw new CryptoOperationException("Keystore returned null operation token"); + throw new IllegalStateException("Keystore returned null operation token"); } mOperationToken = opResult.token; mOperationHandle = opResult.operationHandle; @@ -299,7 +321,15 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry @Override protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { - ensureKeystoreOperationInitialized(); + if (mCachedException != null) { + return null; + } + try { + ensureKeystoreOperationInitialized(); + } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { + mCachedException = e; + return null; + } if (inputLen == 0) { return null; @@ -309,7 +339,8 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry try { output = mMainDataStreamer.update(input, inputOffset, inputLen); } catch (KeyStoreException e) { - throw KeyStore.getCryptoOperationException(e); + mCachedException = e; + return null; } if (output.length == 0) { @@ -338,7 +369,16 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry @Override protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { - ensureKeystoreOperationInitialized(); + if (mCachedException != null) { + throw (IllegalBlockSizeException) + new IllegalBlockSizeException().initCause(mCachedException); + } + + try { + ensureKeystoreOperationInitialized(); + } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { + throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e); + } byte[] output; try { @@ -352,7 +392,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED: throw new AEADBadTagException(); default: - throw KeyStore.getCryptoOperationException(e); + throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e); } } @@ -613,11 +653,11 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry if (mIv == null) { mIv = returnedIv; } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) { - throw new CryptoOperationException("IV in use differs from provided IV"); + throw new IllegalStateException("IV in use differs from provided IV"); } } else { if (returnedIv != null) { - throw new CryptoOperationException( + throw new IllegalStateException( "IV in use despite IV not being used by this transformation"); } } diff --git a/keystore/java/android/security/KeyStoreConnectException.java b/keystore/java/android/security/KeyStoreConnectException.java index 8ed6e04..1aa3aec 100644 --- a/keystore/java/android/security/KeyStoreConnectException.java +++ b/keystore/java/android/security/KeyStoreConnectException.java @@ -21,7 +21,7 @@ package android.security; * * @hide */ -public class KeyStoreConnectException extends CryptoOperationException { +public class KeyStoreConnectException extends IllegalStateException { public KeyStoreConnectException() { super("Failed to communicate with keystore service"); } diff --git a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java index aafd2fa..0619199 100644 --- a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java +++ b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java @@ -136,7 +136,7 @@ public class KeyStoreCryptoOperationChunkedStreamer { // More input is available, but it wasn't included into the previous chunk // because the chunk reached its maximum permitted size. // Shouldn't have happened. - throw new CryptoOperationException("Nothing consumed from max-sized chunk: " + throw new IllegalStateException("Nothing consumed from max-sized chunk: " + chunk.length + " bytes"); } mBuffered = chunk; @@ -148,7 +148,7 @@ public class KeyStoreCryptoOperationChunkedStreamer { mBufferedOffset = opResult.inputConsumed; mBufferedLength = chunk.length - opResult.inputConsumed; } else { - throw new CryptoOperationException("Consumed more than provided: " + throw new IllegalStateException("Consumed more than provided: " + opResult.inputConsumed + ", provided: " + chunk.length); } @@ -160,7 +160,7 @@ public class KeyStoreCryptoOperationChunkedStreamer { try { bufferedOutput.write(opResult.output); } catch (IOException e) { - throw new CryptoOperationException("Failed to buffer output", e); + throw new IllegalStateException("Failed to buffer output", e); } } } else { @@ -173,7 +173,7 @@ public class KeyStoreCryptoOperationChunkedStreamer { try { bufferedOutput.write(opResult.output); } catch (IOException e) { - throw new CryptoOperationException("Failed to buffer output", e); + throw new IllegalStateException("Failed to buffer output", e); } return bufferedOutput.toByteArray(); } @@ -233,10 +233,10 @@ public class KeyStoreCryptoOperationChunkedStreamer { } if (opResult.inputConsumed < chunk.length) { - throw new CryptoOperationException("Keystore failed to consume all input. Provided: " + throw new IllegalStateException("Keystore failed to consume all input. Provided: " + chunk.length + ", consumed: " + opResult.inputConsumed); } else if (opResult.inputConsumed > chunk.length) { - throw new CryptoOperationException("Keystore consumed more input than provided" + throw new IllegalStateException("Keystore consumed more input than provided" + " . Provided: " + chunk.length + ", consumed: " + opResult.inputConsumed); } diff --git a/keystore/java/android/security/KeyStoreHmacSpi.java b/keystore/java/android/security/KeyStoreHmacSpi.java index f8b6fef..175369c 100644 --- a/keystore/java/android/security/KeyStoreHmacSpi.java +++ b/keystore/java/android/security/KeyStoreHmacSpi.java @@ -147,7 +147,7 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp resetWhilePreservingInitState(); } - private void ensureKeystoreOperationInitialized() { + private void ensureKeystoreOperationInitialized() throws InvalidKeyException { if (mChunkedStreamer != null) { return; } @@ -169,10 +169,10 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp if (opResult == null) { throw new KeyStoreConnectException(); } else if (opResult.resultCode != KeyStore.NO_ERROR) { - throw KeyStore.getCryptoOperationException(opResult.resultCode); + throw KeyStore.getInvalidKeyException(opResult.resultCode); } if (opResult.token == null) { - throw new CryptoOperationException("Keystore returned null operation token"); + throw new IllegalStateException("Keystore returned null operation token"); } mOperationToken = opResult.token; mOperationHandle = opResult.operationHandle; @@ -188,28 +188,36 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp @Override protected void engineUpdate(byte[] input, int offset, int len) { - ensureKeystoreOperationInitialized(); + try { + ensureKeystoreOperationInitialized(); + } catch (InvalidKeyException e) { + throw new IllegalStateException("Failed to reinitialize MAC", e); + } byte[] output; try { output = mChunkedStreamer.update(input, offset, len); } catch (KeyStoreException e) { - throw KeyStore.getCryptoOperationException(e); + throw new IllegalStateException("Keystore operation failed", e); } if ((output != null) && (output.length != 0)) { - throw new CryptoOperationException("Update operation unexpectedly produced output"); + throw new IllegalStateException("Update operation unexpectedly produced output"); } } @Override protected byte[] engineDoFinal() { - ensureKeystoreOperationInitialized(); + try { + ensureKeystoreOperationInitialized(); + } catch (InvalidKeyException e) { + throw new IllegalStateException("Failed to reinitialize MAC", e); + } byte[] result; try { result = mChunkedStreamer.doFinal(null, 0, 0); } catch (KeyStoreException e) { - throw KeyStore.getCryptoOperationException(e); + throw new IllegalStateException("Keystore operation failed", e); } resetWhilePreservingInitState(); diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java index d1abe12..293c4c9 100644 --- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java @@ -210,7 +210,8 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { int errorCode = mKeyStore.generateKey( keyAliasInKeystore, args, additionalEntropy, flags, new KeyCharacteristics()); if (errorCode != KeyStore.NO_ERROR) { - throw KeyStore.getCryptoOperationException(errorCode); + throw new IllegalStateException( + "Keystore operation failed", KeyStore.getKeyStoreException(errorCode)); } String keyAlgorithmJCA = KeymasterUtils.getJcaSecretKeyAlgorithm(mKeymasterAlgorithm, mKeymasterDigest); diff --git a/keystore/java/android/security/NewFingerprintEnrolledException.java b/keystore/java/android/security/NewFingerprintEnrolledException.java index 806b214..4fe210b 100644 --- a/keystore/java/android/security/NewFingerprintEnrolledException.java +++ b/keystore/java/android/security/NewFingerprintEnrolledException.java @@ -16,11 +16,13 @@ package android.security; +import java.security.InvalidKeyException; + /** * 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. */ -public class NewFingerprintEnrolledException extends CryptoOperationException { +public class NewFingerprintEnrolledException extends InvalidKeyException { /** * Constructs a new {@code NewFingerprintEnrolledException} without detail message and cause. diff --git a/keystore/java/android/security/UserNotAuthenticatedException.java b/keystore/java/android/security/UserNotAuthenticatedException.java index f5f5f41..66f4dd8 100644 --- a/keystore/java/android/security/UserNotAuthenticatedException.java +++ b/keystore/java/android/security/UserNotAuthenticatedException.java @@ -16,11 +16,13 @@ package android.security; +import java.security.InvalidKeyException; + /** * Indicates that a cryptographic operation could not be performed because the user has not been * authenticated recently enough. */ -public class UserNotAuthenticatedException extends CryptoOperationException { +public class UserNotAuthenticatedException extends InvalidKeyException { /** * Constructs a new {@code UserNotAuthenticatedException} without detail message and cause. diff --git a/keystore/tests/src/android/security/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/AndroidKeyStoreTest.java index 7a88dee..a7046dd 100644 --- a/keystore/tests/src/android/security/AndroidKeyStoreTest.java +++ b/keystore/tests/src/android/security/AndroidKeyStoreTest.java @@ -18,7 +18,7 @@ package android.security; import com.android.org.bouncycastle.x509.X509V3CertificateGenerator; -import com.android.org.conscrypt.NativeCrypto; +import com.android.org.conscrypt.NativeConstants; import com.android.org.conscrypt.OpenSSLEngine; import android.test.AndroidTestCase; @@ -768,7 +768,7 @@ public class AndroidKeyStoreTest extends AndroidTestCase { assertAliases(new String[] {}); assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, - KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, + KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null)); assertAliases(new String[] { TEST_ALIAS_1 }); @@ -797,7 +797,7 @@ public class AndroidKeyStoreTest extends AndroidTestCase { assertAliases(new String[] {}); assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, - KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, + KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null)); assertTrue("Should contain generated private key", mKeyStore.containsAlias(TEST_ALIAS_1)); @@ -1963,7 +1963,7 @@ public class AndroidKeyStoreTest extends AndroidTestCase { { final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1; assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, - NativeCrypto.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null)); + NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null)); Key key = mKeyStore.getKey(TEST_ALIAS_1, null); @@ -2019,7 +2019,7 @@ public class AndroidKeyStoreTest extends AndroidTestCase { { final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1; assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, - NativeCrypto.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null)); + NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null)); X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1, TEST_SERIAL_1, TEST_DN_1, NOW, NOW_PLUS_10_YEARS); @@ -2032,7 +2032,7 @@ public class AndroidKeyStoreTest extends AndroidTestCase { { final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_2; assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, - NativeCrypto.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null)); + NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null)); X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_2, TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS); @@ -2064,7 +2064,7 @@ public class AndroidKeyStoreTest extends AndroidTestCase { { final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1; assertTrue(mAndroidKeyStore.generate(privateKeyAlias, - android.security.KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, 1024, + android.security.KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, android.security.KeyStore.FLAG_NONE, null)); X509Certificate cert = @@ -2116,7 +2116,7 @@ public class AndroidKeyStoreTest extends AndroidTestCase { assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2 }); assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_3, - KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, + KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null)); assertEquals("The keystore size should match expected", 3, mKeyStore.size()); @@ -2184,7 +2184,7 @@ public class AndroidKeyStoreTest extends AndroidTestCase { private void setupKey() throws Exception { final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1; assertTrue(mAndroidKeyStore - .generate(privateKeyAlias, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, 1024, + .generate(privateKeyAlias, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null)); X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1, TEST_SERIAL_1, diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java index 1a5552a..916b1ba 100644 --- a/keystore/tests/src/android/security/KeyStoreTest.java +++ b/keystore/tests/src/android/security/KeyStoreTest.java @@ -32,7 +32,7 @@ import android.test.ActivityUnitTestCase; import android.test.AssertionFailedError; import android.test.MoreAsserts; import android.test.suitebuilder.annotation.MediumTest; -import com.android.org.conscrypt.NativeCrypto; +import com.android.org.conscrypt.NativeConstants; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Date; @@ -365,7 +365,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { public void testGenerate_NotInitialized_Fail() throws Exception { assertFalse("Should fail when keystore is not initialized", - mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); } @@ -373,7 +373,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { mKeyStore.password(TEST_PASSWD); mKeyStore.lock(); assertFalse("Should fail when keystore is locked", - mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); } @@ -381,7 +381,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { assertTrue(mKeyStore.password(TEST_PASSWD)); assertTrue("Should be able to generate key when unlocked", - mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); assertTrue(mKeyStore.contains(TEST_KEYNAME)); assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); @@ -391,7 +391,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { assertTrue(mKeyStore.password(TEST_PASSWD)); assertTrue("Should be able to generate key when unlocked", - mKeyStore.generate(TEST_KEYNAME, Process.WIFI_UID, NativeCrypto.EVP_PKEY_RSA, + mKeyStore.generate(TEST_KEYNAME, Process.WIFI_UID, NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); assertFalse(mKeyStore.contains(TEST_KEYNAME)); @@ -401,7 +401,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { assertTrue(mKeyStore.password(TEST_PASSWD)); assertFalse(mKeyStore.generate(TEST_KEYNAME, Process.BLUETOOTH_UID, - NativeCrypto.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); assertFalse(mKeyStore.contains(TEST_KEYNAME)); @@ -447,7 +447,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { public void testSign_Success() throws Exception { mKeyStore.password(TEST_PASSWD); - assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, + assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); assertTrue(mKeyStore.contains(TEST_KEYNAME)); final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA); @@ -458,7 +458,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { public void testVerify_Success() throws Exception { mKeyStore.password(TEST_PASSWD); - assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, + assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); assertTrue(mKeyStore.contains(TEST_KEYNAME)); final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA); @@ -486,7 +486,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { mKeyStore.password(TEST_PASSWD)); assertTrue("Should be able to generate key for testcase", - mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); assertTrue("Should be able to grant key to other user", @@ -520,7 +520,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { mKeyStore.password(TEST_PASSWD)); assertTrue("Should be able to generate key for testcase", - mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); assertTrue("Should be able to grant key to other user", @@ -554,7 +554,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { mKeyStore.password(TEST_PASSWD)); assertTrue("Should be able to generate key for testcase", - mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); assertFalse("Should not be able to revoke not existent grant", @@ -566,7 +566,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { mKeyStore.password(TEST_PASSWD)); assertTrue("Should be able to generate key for testcase", - mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); assertTrue("Should be able to grant key to other user", @@ -584,7 +584,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { mKeyStore.password(TEST_PASSWD)); assertTrue("Should be able to generate key for testcase", - mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); assertTrue("Should be able to grant key to other user", @@ -605,7 +605,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { assertFalse(mKeyStore.contains(TEST_KEYNAME)); - assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, + assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); assertTrue(mKeyStore.contains(TEST_KEYNAME)); @@ -644,7 +644,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { assertFalse(mKeyStore.contains(TEST_KEYNAME)); - assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, + assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); assertTrue(mKeyStore.contains(TEST_KEYNAME)); diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index ff6fed2..a7e092f 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -55,16 +55,16 @@ public class AudioFormat { public static final int ENCODING_DTS_HD = 8; /** Invalid audio channel configuration */ - /** @deprecated use CHANNEL_INVALID instead */ + /** @deprecated Use {@link #CHANNEL_INVALID} instead. */ @Deprecated public static final int CHANNEL_CONFIGURATION_INVALID = 0; /** Default audio channel configuration */ - /** @deprecated use CHANNEL_OUT_DEFAULT or CHANNEL_IN_DEFAULT instead */ + /** @deprecated Use {@link #CHANNEL_OUT_DEFAULT} or {@link #CHANNEL_IN_DEFAULT} instead. */ @Deprecated public static final int CHANNEL_CONFIGURATION_DEFAULT = 1; /** Mono audio configuration */ - /** @deprecated use CHANNEL_OUT_MONO or CHANNEL_IN_MONO instead */ + /** @deprecated Use {@link #CHANNEL_OUT_MONO} or {@link #CHANNEL_IN_MONO} instead. */ @Deprecated public static final int CHANNEL_CONFIGURATION_MONO = 2; /** Stereo (2 channel) audio configuration */ - /** @deprecated use CHANNEL_OUT_STEREO or CHANNEL_IN_STEREO instead */ + /** @deprecated Use {@link #CHANNEL_OUT_STEREO} or {@link #CHANNEL_IN_STEREO} instead. */ @Deprecated public static final int CHANNEL_CONFIGURATION_STEREO = 3; /** Invalid audio channel mask */ @@ -117,12 +117,11 @@ public class AudioFormat { public static final int CHANNEL_OUT_5POINT1_SIDE = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT); - // TODO does this need an @deprecated ? - // different from AUDIO_CHANNEL_OUT_7POINT1 - public static final int CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | + // different from AUDIO_CHANNEL_OUT_7POINT1 used internally, and not accepted by AudioRecord. + /** @deprecated Not the typical 7.1 surround configuration. Use {@link #CHANNEL_OUT_7POINT1_SURROUND} instead. */ + @Deprecated public static final int CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT | CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER); - /** @hide */ // matches AUDIO_CHANNEL_OUT_7POINT1 public static final int CHANNEL_OUT_7POINT1_SURROUND = ( CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_FRONT_RIGHT | diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index cb70e8b..d851ad7 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -3147,6 +3147,20 @@ public class AudioManager { "android.media.property.OUTPUT_FRAMES_PER_BUFFER"; /** + * Used as a key for {@link #getProperty} to determine if the default microphone audio source + * supports near-ultrasound frequencies (range of 18 - 21 kHz). + */ + public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = + "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND"; + + /** + * Used as a key for {@link #getProperty} to determine if the default speaker audio path + * supports near-ultrasound frequencies (range of 18 - 21 kHz). + */ + public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = + "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND"; + + /** * Returns the value of the property with the specified key. * @param key One of the strings corresponding to a property key: either * {@link #PROPERTY_OUTPUT_SAMPLE_RATE} or diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 3577357..9bd5c55 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -491,7 +491,7 @@ public class AudioTrack session[0] = sessionId; // native initialization int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes, - mSampleRate, mChannels, mAudioFormat, + mSampleRate, mChannels, mChannelIndexMask, mAudioFormat, mNativeBufferSizeInBytes, mDataLoadMode, session); if (initResult != SUCCESS) { loge("Error code "+initResult+" when initializing AudioTrack."); @@ -701,48 +701,6 @@ public class AudioTrack AudioFormat.CHANNEL_OUT_SIDE_LEFT | AudioFormat.CHANNEL_OUT_SIDE_RIGHT; - // Java channel mask definitions below match those - // in /system/core/include/system/audio.h in the JNI code of AudioTrack. - - // internal maximum size for bits parameter, not part of public API - private static final int AUDIO_CHANNEL_BITS_LOG2 = 30; - - // log(2) of maximum number of representations, not part of public API - private static final int AUDIO_CHANNEL_REPRESENTATION_LOG2 = 2; - - // used to create a channel index mask or channel position mask - // with getChannelMaskFromRepresentationAndBits(); - private static final int CHANNEL_OUT_REPRESENTATION_POSITION = 0; - private static final int CHANNEL_OUT_REPRESENTATION_INDEX = 2; - - /** - * Return the channel mask from its representation and bits. - * - * This creates a channel mask for mChannels which combines a - * representation field and a bits field. This is for internal - * communication to native code, not part of the public API. - * - * @param representation the type of channel mask, - * either CHANNEL_OUT_REPRESENTATION_POSITION - * or CHANNEL_OUT_REPRESENTATION_INDEX - * @param bits is the channel bits specifying occupancy - * @return the channel mask - * @throws java.lang.IllegalArgumentException if representation is not recognized or - * the bits field is not acceptable for that representation - */ - private static int getChannelMaskFromRepresentationAndBits(int representation, int bits) { - switch (representation) { - case CHANNEL_OUT_REPRESENTATION_POSITION: - case CHANNEL_OUT_REPRESENTATION_INDEX: - if ((bits & ~((1 << AUDIO_CHANNEL_BITS_LOG2) - 1)) != 0) { - throw new IllegalArgumentException("invalid bits " + bits); - } - return representation << AUDIO_CHANNEL_BITS_LOG2 | bits; - default: - throw new IllegalArgumentException("invalid representation " + representation); - } - } - // Convenience method for the constructor's parameter checks. // This is where constructor IllegalArgumentException-s are thrown // postconditions: @@ -804,11 +762,6 @@ public class AudioTrack } else if (mChannelCount != channelIndexCount) { throw new IllegalArgumentException("Channel count must match"); } - - // AudioTrack prefers to use the channel index configuration - // over the channel position configuration if both are specified. - mChannels = getChannelMaskFromRepresentationAndBits( - CHANNEL_OUT_REPRESENTATION_INDEX, mChannelIndexMask); } //-------------- @@ -2362,7 +2315,7 @@ public class AudioTrack // AudioAttributes.USAGE_MEDIA will map to AudioManager.STREAM_MUSIC private native final int native_setup(Object /*WeakReference<AudioTrack>*/ audiotrack_this, Object /*AudioAttributes*/ attributes, - int sampleRate, int channelMask, int audioFormat, + int sampleRate, int channelMask, int channelIndexMask, int audioFormat, int buffSizeInBytes, int mode, int[] sessionId); private native final void native_finalize(); diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java index 75901fd..195c987 100644 --- a/media/java/android/media/Image.java +++ b/media/java/android/media/Image.java @@ -50,10 +50,25 @@ public abstract class Image implements AutoCloseable { /** * @hide */ + protected boolean mIsImageValid = false; + + /** + * @hide + */ protected Image() { } /** + * Throw IllegalStateException if the image is invalid (already closed). + * + * @hide + */ + protected void throwISEIfImageIsInvalid() { + if (!mIsImageValid) { + throw new IllegalStateException("Image is already closed"); + } + } + /** * Get the format for this image. This format determines the number of * ByteBuffers needed to represent the image, and the general layout of the * pixel data in each in ByteBuffer. @@ -160,7 +175,7 @@ public abstract class Image implements AutoCloseable { * Set the timestamp associated with this frame. * <p> * The timestamp is measured in nanoseconds, and is normally monotonically - * increasing. However, However, the behavior of the timestamp depends on + * increasing. However, the behavior of the timestamp depends on * the destination of this image. See {@link android.hardware.Camera Camera} * , {@link android.hardware.camera2.CameraDevice CameraDevice}, * {@link MediaPlayer} and {@link MediaCodec} for more details. @@ -176,6 +191,7 @@ public abstract class Image implements AutoCloseable { * @param timestamp The timestamp to be set for this image. */ public void setTimestamp(long timestamp) { + throwISEIfImageIsInvalid(); return; } @@ -187,6 +203,7 @@ public abstract class Image implements AutoCloseable { * </p> */ public boolean isOpaque() { + throwISEIfImageIsInvalid(); return false; } @@ -199,6 +216,8 @@ public abstract class Image implements AutoCloseable { * using coordinates in the largest-resolution plane. */ public Rect getCropRect() { + throwISEIfImageIsInvalid(); + if (mCropRect == null) { return new Rect(0, 0, getWidth(), getHeight()); } else { @@ -213,6 +232,8 @@ public abstract class Image implements AutoCloseable { * using coordinates in the largest-resolution plane. */ public void setCropRect(Rect cropRect) { + throwISEIfImageIsInvalid(); + if (cropRect != null) { cropRect = new Rect(cropRect); // make a copy cropRect.intersect(0, 0, getWidth(), getHeight()); @@ -260,6 +281,8 @@ public abstract class Image implements AutoCloseable { * a new owner. */ boolean isAttachable() { + throwISEIfImageIsInvalid(); + return false; } @@ -279,6 +302,8 @@ public abstract class Image implements AutoCloseable { * @return The owner of the Image. */ Object getOwner() { + throwISEIfImageIsInvalid(); + return null; } @@ -294,6 +319,8 @@ public abstract class Image implements AutoCloseable { * @return native context associated with this Image. */ long getNativeContext() { + throwISEIfImageIsInvalid(); + return 0; } diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java index e54525d..6d30208 100644 --- a/media/java/android/media/ImageReader.java +++ b/media/java/android/media/ImageReader.java @@ -368,7 +368,7 @@ public class ImageReader implements AutoCloseable { switch (status) { case ACQUIRE_SUCCESS: si.createSurfacePlanes(); - si.setImageValid(true); + si.mIsImageValid = true; case ACQUIRE_NO_BUFS: case ACQUIRE_MAX_IMAGES: break; @@ -444,7 +444,7 @@ public class ImageReader implements AutoCloseable { si.clearSurfacePlanes(); nativeReleaseImage(i); - si.setImageValid(false); + si.mIsImageValid = false; } /** @@ -686,7 +686,6 @@ public class ImageReader implements AutoCloseable { private class SurfaceImage extends android.media.Image { public SurfaceImage(int format) { - mIsImageValid = false; mFormat = format; } @@ -784,16 +783,6 @@ public class ImageReader implements AutoCloseable { mIsDetached.getAndSet(detached); } - private void setImageValid(boolean isValid) { - mIsImageValid = isValid; - } - - private void throwISEIfImageIsInvalid() { - if (!mIsImageValid) { - throw new IllegalStateException("Image is already closed"); - } - } - private void clearSurfacePlanes() { if (mIsImageValid) { for (int i = 0; i < mPlanes.length; i++) { @@ -877,7 +866,6 @@ public class ImageReader implements AutoCloseable { private long mTimestamp; private SurfacePlane[] mPlanes; - private boolean mIsImageValid; private int mHeight = -1; private int mWidth = -1; private int mFormat = ImageFormat.UNKNOWN; diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java index c18b463..f805339 100644 --- a/media/java/android/media/ImageWriter.java +++ b/media/java/android/media/ImageWriter.java @@ -29,7 +29,6 @@ import java.nio.ByteOrder; import java.nio.NioUtils; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; /** * <p> @@ -204,7 +203,7 @@ public class ImageWriter implements AutoCloseable { WriterSurfaceImage newImage = new WriterSurfaceImage(this); nativeDequeueInputImage(mNativeContext, newImage); mDequeuedImages.add(newImage); - newImage.setImageValid(true); + newImage.mIsImageValid = true; return newImage; } @@ -260,7 +259,7 @@ public class ImageWriter implements AutoCloseable { throw new IllegalArgumentException("image shouldn't be null"); } boolean ownedByMe = isImageOwnedByMe(image); - if (ownedByMe && !(((WriterSurfaceImage) image).isImageValid())) { + if (ownedByMe && !(((WriterSurfaceImage) image).mIsImageValid)) { throw new IllegalStateException("Image from ImageWriter is invalid"); } @@ -312,7 +311,7 @@ public class ImageWriter implements AutoCloseable { // Do not call close here, as close is essentially cancel image. WriterSurfaceImage wi = (WriterSurfaceImage) image; wi.clearSurfacePlanes(); - wi.setImageValid(false); + wi.mIsImageValid = false; } } @@ -555,7 +554,7 @@ public class ImageWriter implements AutoCloseable { WriterSurfaceImage wi = (WriterSurfaceImage) image; - if (!wi.isImageValid()) { + if (!wi.mIsImageValid) { throw new IllegalStateException("Image is invalid"); } @@ -568,7 +567,7 @@ public class ImageWriter implements AutoCloseable { cancelImage(mNativeContext, image); mDequeuedImages.remove(image); wi.clearSurfacePlanes(); - wi.setImageValid(false); + wi.mIsImageValid = false; } private boolean isImageOwnedByMe(Image image) { @@ -585,7 +584,6 @@ public class ImageWriter implements AutoCloseable { private static class WriterSurfaceImage extends android.media.Image { private ImageWriter mOwner; - private AtomicBoolean mIsImageValid = new AtomicBoolean(false); // This field is used by native code, do not access or modify. private long mNativeBuffer; private int mNativeFenceFd = -1; @@ -604,9 +602,8 @@ public class ImageWriter implements AutoCloseable { @Override public int getFormat() { - if (!mIsImageValid.get()) { - throw new IllegalStateException("Image is already released"); - } + throwISEIfImageIsInvalid(); + if (mFormat == -1) { mFormat = nativeGetFormat(); } @@ -615,9 +612,7 @@ public class ImageWriter implements AutoCloseable { @Override public int getWidth() { - if (!mIsImageValid.get()) { - throw new IllegalStateException("Image is already released"); - } + throwISEIfImageIsInvalid(); if (mWidth == -1) { mWidth = nativeGetWidth(); @@ -628,9 +623,7 @@ public class ImageWriter implements AutoCloseable { @Override public int getHeight() { - if (!mIsImageValid.get()) { - throw new IllegalStateException("Image is already released"); - } + throwISEIfImageIsInvalid(); if (mHeight == -1) { mHeight = nativeGetHeight(); @@ -641,36 +634,28 @@ public class ImageWriter implements AutoCloseable { @Override public long getTimestamp() { - if (!mIsImageValid.get()) { - throw new IllegalStateException("Image is already released"); - } + throwISEIfImageIsInvalid(); return mTimestamp; } @Override public void setTimestamp(long timestamp) { - if (!mIsImageValid.get()) { - throw new IllegalStateException("Image is already released"); - } + throwISEIfImageIsInvalid(); mTimestamp = timestamp; } @Override public boolean isOpaque() { - if (!mIsImageValid.get()) { - throw new IllegalStateException("Image is already released"); - } + throwISEIfImageIsInvalid(); return getFormat() == ImageFormat.PRIVATE; } @Override public Plane[] getPlanes() { - if (!mIsImageValid.get()) { - throw new IllegalStateException("Image is already released"); - } + throwISEIfImageIsInvalid(); if (mPlanes == null) { int numPlanes = ImageUtils.getNumPlanesForFormat(getFormat()); @@ -682,9 +667,7 @@ public class ImageWriter implements AutoCloseable { @Override boolean isAttachable() { - if (!mIsImageValid.get()) { - throw new IllegalStateException("Image is already released"); - } + throwISEIfImageIsInvalid(); // Don't allow Image to be detached from ImageWriter for now, as no // detach API is exposed. return false; @@ -692,17 +675,21 @@ public class ImageWriter implements AutoCloseable { @Override ImageWriter getOwner() { + throwISEIfImageIsInvalid(); + return mOwner; } @Override long getNativeContext() { + throwISEIfImageIsInvalid(); + return mNativeBuffer; } @Override public void close() { - if (mIsImageValid.get()) { + if (mIsImageValid) { getOwner().abortImage(this); } } @@ -716,16 +703,8 @@ public class ImageWriter implements AutoCloseable { } } - private boolean isImageValid() { - return mIsImageValid.get(); - } - - private void setImageValid(boolean isValid) { - mIsImageValid.getAndSet(isValid); - } - private void clearSurfacePlanes() { - if (mIsImageValid.get()) { + if (mIsImageValid) { for (int i = 0; i < mPlanes.length; i++) { if (mPlanes[i] != null) { mPlanes[i].clearBuffer(); @@ -756,26 +735,19 @@ public class ImageWriter implements AutoCloseable { @Override public int getRowStride() { - if (WriterSurfaceImage.this.isImageValid() == false) { - throw new IllegalStateException("Image is already released"); - } + throwISEIfImageIsInvalid(); return mRowStride; } @Override public int getPixelStride() { - if (WriterSurfaceImage.this.isImageValid() == false) { - throw new IllegalStateException("Image is already released"); - } + throwISEIfImageIsInvalid(); return mPixelStride; } @Override public ByteBuffer getBuffer() { - if (WriterSurfaceImage.this.isImageValid() == false) { - throw new IllegalStateException("Image is already released"); - } - + throwISEIfImageIsInvalid(); return mBuffer; } diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 1f00c7b..d22cfda 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -2059,7 +2059,6 @@ final public class MediaCodec { /** @hide */ public static class MediaImage extends Image { private final boolean mIsReadOnly; - private boolean mIsValid; private final int mWidth; private final int mHeight; private final int mFormat; @@ -2072,36 +2071,42 @@ final public class MediaCodec { private final static int TYPE_YUV = 1; + @Override public int getFormat() { - checkValid(); + throwISEIfImageIsInvalid(); return mFormat; } + @Override public int getHeight() { - checkValid(); + throwISEIfImageIsInvalid(); return mHeight; } + @Override public int getWidth() { - checkValid(); + throwISEIfImageIsInvalid(); return mWidth; } + @Override public long getTimestamp() { - checkValid(); + throwISEIfImageIsInvalid(); return mTimestamp; } + @Override @NonNull public Plane[] getPlanes() { - checkValid(); + throwISEIfImageIsInvalid(); return Arrays.copyOf(mPlanes, mPlanes.length); } + @Override public void close() { - if (mIsValid) { + if (mIsImageValid) { java.nio.NioUtils.freeDirectBuffer(mBuffer); - mIsValid = false; + mIsImageValid = false; } } @@ -2111,6 +2116,7 @@ final public class MediaCodec { * The crop rectangle specifies the region of valid pixels in the image, * using coordinates in the largest-resolution plane. */ + @Override public void setCropRect(@Nullable Rect cropRect) { if (mIsReadOnly) { throw new ReadOnlyBufferException(); @@ -2118,11 +2124,6 @@ final public class MediaCodec { super.setCropRect(cropRect); } - private void checkValid() { - if (!mIsValid) { - throw new IllegalStateException("Image is already released"); - } - } private int readInt(@NonNull ByteBuffer buffer, boolean asLong) { if (asLong) { @@ -2137,7 +2138,7 @@ final public class MediaCodec { long timestamp, int xOffset, int yOffset, @Nullable Rect cropRect) { mFormat = ImageFormat.YUV_420_888; mTimestamp = timestamp; - mIsValid = true; + mIsImageValid = true; mIsReadOnly = buffer.isReadOnly(); mBuffer = buffer.duplicate(); @@ -2208,20 +2209,20 @@ final public class MediaCodec { @Override public int getRowStride() { - checkValid(); + throwISEIfImageIsInvalid(); return mRowInc; } @Override public int getPixelStride() { - checkValid(); + throwISEIfImageIsInvalid(); return mColInc; } @Override @NonNull public ByteBuffer getBuffer() { - checkValid(); + throwISEIfImageIsInvalid(); return mData; } diff --git a/media/java/android/media/MediaSync.java b/media/java/android/media/MediaSync.java index 3b4f8e5..dc6760d 100644 --- a/media/java/android/media/MediaSync.java +++ b/media/java/android/media/MediaSync.java @@ -49,7 +49,7 @@ import java.util.List; * sync.setAudioTrack(audioTrack); * sync.setCallback(new MediaSync.Callback() { * {@literal @Override} - * public void onReturnAudioBuffer(MediaSync sync, ByteBuffer audioBuffer, int bufferIndex) { + * public void onAudioBufferConsumed(MediaSync sync, ByteBuffer audioBuffer, int bufferIndex) { * ... * } * }, null); @@ -88,7 +88,7 @@ import java.util.List; * } * * // This is the callback from MediaSync. - * onReturnAudioBuffer(MediaSync sync, ByteBuffer buffer, int bufferIndex) { + * onAudioBufferConsumed(MediaSync sync, ByteBuffer buffer, int bufferIndex) { * // ... * audioDecoder.releaseBuffer(bufferIndex, false); * // ... @@ -104,7 +104,7 @@ import java.util.List; * <p> * For audio, the client needs to set up audio track correctly, e.g., using {@link * AudioTrack#MODE_STREAM}. The audio buffers are sent to MediaSync directly via {@link - * #queueAudio}, and are returned to the client via {@link Callback#onReturnAudioBuffer} + * #queueAudio}, and are returned to the client via {@link Callback#onAudioBufferConsumed} * asynchronously. The client should not modify an audio buffer till it's returned. * <p> * The client can optionally pre-fill audio/video buffers by setting playback rate to 0.0, @@ -125,10 +125,41 @@ final public class MediaSync { * @param audioBuffer The returned audio buffer. * @param bufferIndex The index associated with the audio buffer */ - public abstract void onReturnAudioBuffer( + public abstract void onAudioBufferConsumed( @NonNull MediaSync sync, @NonNull ByteBuffer audioBuffer, int bufferIndex); } + /** Audio track failed. + * @see android.media.MediaSync.OnErrorListener + */ + public static final int MEDIASYNC_ERROR_AUDIOTRACK_FAIL = 1; + + /** The surface failed to handle video buffers. + * @see android.media.MediaSync.OnErrorListener + */ + public static final int MEDIASYNC_ERROR_SURFACE_FAIL = 2; + + /** + * Interface definition of a callback to be invoked when there + * has been an error during an asynchronous operation (other errors + * will throw exceptions at method call time). + */ + public interface OnErrorListener { + /** + * Called to indicate an error. + * + * @param sync The MediaSync the error pertains to + * @param what The type of error that has occurred: + * <ul> + * <li>{@link #MEDIASYNC_ERROR_AUDIOTRACK_FAIL} + * <li>{@link #MEDIASYNC_ERROR_SURFACE_FAIL} + * </ul> + * @param extra an extra code, specific to the error. Typically + * implementation dependent. + */ + void onError(@NonNull MediaSync sync, int what, int extra); + } + private static final String TAG = "MediaSync"; private static final int EVENT_CALLBACK = 1; @@ -155,6 +186,10 @@ final public class MediaSync { private Handler mCallbackHandler = null; private MediaSync.Callback mCallback = null; + private final Object mOnErrorListenerLock = new Object(); + private Handler mOnErrorListenerHandler = null; + private MediaSync.OnErrorListener mOnErrorListener = null; + private Thread mAudioThread = null; // Created on mAudioThread when mAudioThread is started. When used on user thread, they should // be guarded by checking mAudioThread. @@ -235,6 +270,39 @@ final public class MediaSync { } /** + * Sets an asynchronous callback for error events. + * <p> + * This method can be called multiple times to update a previously set listener. If the + * handler is changed, undelivered notifications scheduled for the old handler may be dropped. + * <p> + * <b>Do not call this inside callback.</b> + * + * @param listener The callback that will run. Use {@code null} to stop receiving callbacks. + * @param handler The Handler that will run the callback. Use {@code null} to use MediaSync's + * internal handler if it exists. + */ + public void setOnErrorListener(@Nullable /* MediaSync. */ OnErrorListener listener, + @Nullable Handler handler) { + synchronized(mOnErrorListenerLock) { + if (handler != null) { + mOnErrorListenerHandler = handler; + } else { + Looper looper; + if ((looper = Looper.myLooper()) == null) { + looper = Looper.getMainLooper(); + } + if (looper == null) { + mOnErrorListenerHandler = null; + } else { + mOnErrorListenerHandler = new Handler(looper); + } + } + + mOnErrorListener = listener; + } + } + + /** * Sets the output surface for MediaSync. * <p> * Currently, this is only supported in the Initialized state. @@ -614,7 +682,7 @@ final public class MediaSync { return; } if (mCallback != null) { - mCallback.onReturnAudioBuffer(sync, audioBuffer.mByteBuffer, + mCallback.onAudioBufferConsumed(sync, audioBuffer.mByteBuffer, audioBuffer.mBufferIndex); } } diff --git a/media/java/android/media/tv/TvContentRating.java b/media/java/android/media/tv/TvContentRating.java index 754facd..966e41a 100644 --- a/media/java/android/media/tv/TvContentRating.java +++ b/media/java/android/media/tv/TvContentRating.java @@ -16,9 +16,12 @@ package android.media.tv; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.text.TextUtils; +import com.android.internal.util.Preconditions; + import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -693,6 +696,12 @@ public final class TvContentRating { private final int mHashCode; /** + * Rating constant denoting unrated content. + */ + public static final TvContentRating UNRATED = new TvContentRating("com.android.tv", "", + "UNRATED", null); + + /** * Creates a {@code TvContentRating} object with predefined content rating strings. * * @param domain The domain string. For example, "com.android.tv". @@ -833,10 +842,8 @@ public final class TvContentRating { * @hide */ @SystemApi - public final boolean contains(TvContentRating rating) { - if (rating == null) { - throw new IllegalArgumentException("rating cannot be null"); - } + public final boolean contains(@NonNull TvContentRating rating) { + Preconditions.checkNotNull(rating); if (!rating.getMainRating().equals(mRating)) { return false; } diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index 0f265de..601fa45 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -40,6 +40,8 @@ import android.view.KeyEvent; import android.view.Surface; import android.view.View; +import com.android.internal.util.Preconditions; + import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; @@ -934,9 +936,7 @@ public final class TvInputManager { */ @Nullable public TvInputInfo getTvInputInfo(@NonNull String inputId) { - if (inputId == null) { - throw new IllegalArgumentException("inputId cannot be null"); - } + Preconditions.checkNotNull(inputId); try { return mService.getTvInputInfo(inputId, mUserId); } catch (RemoteException e) { @@ -958,9 +958,7 @@ public final class TvInputManager { * @throws IllegalArgumentException if the argument is {@code null}. */ public int getInputState(@NonNull String inputId) { - if (inputId == null) { - throw new IllegalArgumentException("inputId cannot be null"); - } + Preconditions.checkNotNull(inputId); synchronized (mLock) { Integer state = mStateMap.get(inputId); if (state == null) { @@ -976,15 +974,10 @@ public final class TvInputManager { * * @param callback A callback used to monitor status of the TV inputs. * @param handler A {@link Handler} that the status change will be delivered to. - * @throws IllegalArgumentException if any of the arguments is {@code null}. */ public void registerCallback(@NonNull TvInputCallback callback, @NonNull Handler handler) { - if (callback == null) { - throw new IllegalArgumentException("callback cannot be null"); - } - if (handler == null) { - throw new IllegalArgumentException("handler cannot be null"); - } + Preconditions.checkNotNull(callback); + Preconditions.checkNotNull(handler); synchronized (mLock) { mCallbackRecords.add(new TvInputCallbackRecord(callback, handler)); } @@ -994,12 +987,9 @@ public final class TvInputManager { * Unregisters the existing {@link TvInputCallback}. * * @param callback The existing callback to remove. - * @throws IllegalArgumentException if any of the arguments is {@code null}. */ public void unregisterCallback(@NonNull final TvInputCallback callback) { - if (callback == null) { - throw new IllegalArgumentException("callback cannot be null"); - } + Preconditions.checkNotNull(callback); synchronized (mLock) { for (Iterator<TvInputCallbackRecord> it = mCallbackRecords.iterator(); it.hasNext(); ) { @@ -1049,9 +1039,7 @@ public final class TvInputManager { * @return {@code true} if the given TV content rating is blocked, {@code false} otherwise. */ public boolean isRatingBlocked(@NonNull TvContentRating rating) { - if (rating == null) { - throw new IllegalArgumentException("rating cannot be null"); - } + Preconditions.checkNotNull(rating); try { return mService.isRatingBlocked(rating.flattenToString(), mUserId); } catch (RemoteException e) { @@ -1087,10 +1075,8 @@ public final class TvInputManager { * @hide */ @SystemApi - public void addBlockedRating(TvContentRating rating) { - if (rating == null) { - throw new IllegalArgumentException("rating cannot be null"); - } + public void addBlockedRating(@NonNull TvContentRating rating) { + Preconditions.checkNotNull(rating); try { mService.addBlockedRating(rating.flattenToString(), mUserId); } catch (RemoteException e) { @@ -1107,10 +1093,8 @@ public final class TvInputManager { * @hide */ @SystemApi - public void removeBlockedRating(TvContentRating rating) { - if (rating == null) { - throw new IllegalArgumentException("rating cannot be null"); - } + public void removeBlockedRating(@NonNull TvContentRating rating) { + Preconditions.checkNotNull(rating); try { mService.removeBlockedRating(rating.flattenToString(), mUserId); } catch (RemoteException e) { @@ -1140,21 +1124,14 @@ public final class TvInputManager { * @param inputId The id of the TV input. * @param callback A callback used to receive the created session. * @param handler A {@link Handler} that the session creation will be delivered to. - * @throws IllegalArgumentException if any of the arguments is {@code null}. * @hide */ @SystemApi - public void createSession(String inputId, final SessionCallback callback, - Handler handler) { - if (inputId == null) { - throw new IllegalArgumentException("id cannot be null"); - } - if (callback == null) { - throw new IllegalArgumentException("callback cannot be null"); - } - if (handler == null) { - throw new IllegalArgumentException("handler cannot be null"); - } + public void createSession(@NonNull String inputId, @NonNull final SessionCallback callback, + @NonNull Handler handler) { + Preconditions.checkNotNull(inputId); + Preconditions.checkNotNull(callback); + Preconditions.checkNotNull(handler); SessionCallbackRecord record = new SessionCallbackRecord(callback, handler); synchronized (mSessionCallbackRecordMap) { int seq = mNextSeq++; @@ -1436,7 +1413,6 @@ public final class TvInputManager { * Tunes to a given channel. * * @param channelUri The URI of a channel. - * @throws IllegalArgumentException if the argument is {@code null}. */ public void tune(Uri channelUri) { tune(channelUri, null); @@ -1447,14 +1423,11 @@ public final class TvInputManager { * * @param channelUri The URI of a channel. * @param params A set of extra parameters which might be handled with this tune event. - * @throws IllegalArgumentException if {@code channelUri} is {@code null}. * @hide */ @SystemApi - public void tune(Uri channelUri, Bundle params) { - if (channelUri == null) { - throw new IllegalArgumentException("channelUri cannot be null"); - } + public void tune(@NonNull Uri channelUri, Bundle params) { + Preconditions.checkNotNull(channelUri); if (mToken == null) { Log.w(TAG, "The session has been already released"); return; @@ -1790,16 +1763,11 @@ public final class TvInputManager { * * @param view A view playing TV. * @param frame A position of the overlay view. - * @throws IllegalArgumentException if any of the arguments is {@code null}. * @throws IllegalStateException if {@code view} is not attached to a window. */ - void createOverlayView(View view, Rect frame) { - if (view == null) { - throw new IllegalArgumentException("view cannot be null"); - } - if (frame == null) { - throw new IllegalArgumentException("frame cannot be null"); - } + void createOverlayView(@NonNull View view, @NonNull Rect frame) { + Preconditions.checkNotNull(view); + Preconditions.checkNotNull(frame); if (view.getWindowToken() == null) { throw new IllegalStateException("view must be attached to a window"); } @@ -1818,12 +1786,9 @@ public final class TvInputManager { * Relayouts the current overlay view. * * @param frame A new position of the overlay view. - * @throws IllegalArgumentException if the arguments is {@code null}. */ - void relayoutOverlayView(Rect frame) { - if (frame == null) { - throw new IllegalArgumentException("frame cannot be null"); - } + void relayoutOverlayView(@NonNull Rect frame) { + Preconditions.checkNotNull(frame); if (mToken == null) { Log.w(TAG, "The session has been already released"); return; @@ -1853,14 +1818,12 @@ public final class TvInputManager { /** * Requests to unblock content blocked by parental controls. */ - void requestUnblockContent(TvContentRating unblockedRating) { + void requestUnblockContent(@NonNull TvContentRating unblockedRating) { + Preconditions.checkNotNull(unblockedRating); if (mToken == null) { Log.w(TAG, "The session has been already released"); return; } - if (unblockedRating == null) { - throw new IllegalArgumentException("unblockedRating cannot be null"); - } try { mService.requestUnblockContent(mToken, unblockedRating.flattenToString(), mUserId); } catch (RemoteException e) { @@ -1871,25 +1834,22 @@ public final class TvInputManager { /** * Dispatches an input event to this session. * - * @param event An {@link InputEvent} to dispatch. + * @param event An {@link InputEvent} to dispatch. Cannot be {@code null}. * @param token A token used to identify the input event later in the callback. - * @param callback A callback used to receive the dispatch result. - * @param handler A {@link Handler} that the dispatch result will be delivered to. + * @param callback A callback used to receive the dispatch result. Cannot be {@code null}. + * @param handler A {@link Handler} that the dispatch result will be delivered to. Cannot be + * {@code null}. * @return Returns {@link #DISPATCH_HANDLED} if the event was handled. Returns * {@link #DISPATCH_NOT_HANDLED} if the event was not handled. Returns * {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the callback will * be invoked later. - * @throws IllegalArgumentException if any of the necessary arguments is {@code null}. * @hide */ - public int dispatchInputEvent(InputEvent event, Object token, - FinishedInputEventCallback callback, Handler handler) { - if (event == null) { - throw new IllegalArgumentException("event cannot be null"); - } - if (callback != null && handler == null) { - throw new IllegalArgumentException("handler cannot be null"); - } + public int dispatchInputEvent(@NonNull InputEvent event, Object token, + @NonNull FinishedInputEventCallback callback, @NonNull Handler handler) { + Preconditions.checkNotNull(event); + Preconditions.checkNotNull(callback); + Preconditions.checkNotNull(handler); synchronized (mHandler) { if (mChannel == null) { return DISPATCH_NOT_HANDLED; diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index 4258534..5156ae8 100644 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -51,6 +51,7 @@ import android.view.accessibility.CaptioningManager; import android.widget.FrameLayout; import com.android.internal.os.SomeArgs; +import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.HashSet; @@ -313,10 +314,8 @@ public abstract class TvInputService extends Service { * @hide */ @SystemApi - public void notifySessionEvent(final String eventType, final Bundle eventArgs) { - if (eventType == null) { - throw new IllegalArgumentException("eventType cannot be null"); - } + public void notifySessionEvent(@NonNull final String eventType, final Bundle eventArgs) { + Preconditions.checkNotNull(eventType); executeOrPostRunnable(new Runnable() { @Override public void run() { @@ -546,9 +545,7 @@ public abstract class TvInputService extends Service { * @see TvInputManager */ public void notifyContentBlocked(@NonNull final TvContentRating rating) { - if (rating == null) { - throw new IllegalArgumentException("rating cannot be null"); - } + Preconditions.checkNotNull(rating); executeOrPostRunnable(new Runnable() { @Override public void run() { diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java index 6eedeb4..2c956e9 100644 --- a/media/java/android/media/tv/TvTrackInfo.java +++ b/media/java/android/media/tv/TvTrackInfo.java @@ -16,10 +16,13 @@ package android.media.tv; +import android.annotation.NonNull; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.util.Preconditions; + /** * Encapsulates the format of tracks played in {@link TvInputService}. */ @@ -245,15 +248,13 @@ public final class TvTrackInfo implements Parcelable { * @param id The ID of the track that uniquely identifies the current track among all the * other tracks in the same TV program. */ - public Builder(int type, String id) { + public Builder(int type, @NonNull String id) { if (type != TYPE_AUDIO && type != TYPE_VIDEO && type != TYPE_SUBTITLE) { throw new IllegalArgumentException("Unknown type: " + type); } - if (id == null) { - throw new IllegalArgumentException("id cannot be null"); - } + Preconditions.checkNotNull(id); mType = type; mId = id; } diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp index d2c614e..8c76665 100644 --- a/media/jni/android_media_ImageWriter.cpp +++ b/media/jni/android_media_ImageWriter.cpp @@ -338,7 +338,7 @@ static void ImageWriter_dequeueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, status_t res = anw->dequeueBuffer(anw.get(), &anb, &fenceFd); if (res != OK) { // TODO: handle different error cases here. - ALOGE("%s: Set buffer count failed: %s (%d)", __FUNCTION__, strerror(-res), res); + ALOGE("%s: Dequeue buffer failed: %s (%d)", __FUNCTION__, strerror(-res), res); jniThrowRuntimeException(env, "dequeue buffer failed"); return; } diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java index e0af29d..1cf7248 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java @@ -32,6 +32,7 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageVolume; @@ -76,6 +77,9 @@ public class StorageMeasurement { Environment.DIRECTORY_DOWNLOADS, Environment.DIRECTORY_ANDROID); public static class MeasurementDetails { + public long totalSize; + public long availSize; + /** * Total apps disk usage. * <p> @@ -121,7 +125,7 @@ public class StorageMeasurement { } public interface MeasurementReceiver { - public void onDetailsChanged(MeasurementDetails details); + void onDetailsChanged(MeasurementDetails details); } private WeakReference<MeasurementReceiver> mReceiver; @@ -370,6 +374,10 @@ public class StorageMeasurement { } } + final File file = mVolume.getPath(); + details.totalSize = file.getTotalSpace(); + details.availSize = file.getFreeSpace(); + // Measure all apps hosted on this volume for all users if (mVolume.getType() == VolumeInfo.TYPE_PRIVATE) { final List<ApplicationInfo> apps = packageManager.getInstalledApplications( diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 35e9636..5b4b4fd 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -94,6 +94,7 @@ <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/> <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" /> + <uses-permission android:name="android.permission.CHANGE_APP_IDLE_STATE" /> <application android:label="@string/app_label"> <provider diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index 292c9c2..0d331d1 100755 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -328,7 +328,7 @@ public class BatteryMeterView extends View implements DemoMode, int fillColor = getFillColor(darkIntensity); mIconTint = fillColor; mFramePaint.setColor(backgroundColor); - mBoltPaint.setColor(backgroundColor); + mBoltPaint.setColor(fillColor); mChargeColor = fillColor; invalidate(); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index b828e78..7b555fc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -1549,6 +1549,7 @@ public class KeyguardViewMediator extends SystemUI { try { callback.onSimSecureStateChanged(mUpdateMonitor.isSimPinSecure()); callback.onShowingStateChanged(mShowing); + callback.onInputRestrictedStateChanged(mInputRestricted); } catch (RemoteException e) { Slog.w(TAG, "Failed to call onShowingStateChanged or onSimSecureStateChanged", e); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index de4874f..e542264 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -700,6 +700,26 @@ public abstract class BaseStatusBar extends SystemUI implements return isCurrentProfile(notificationUserId); } + protected void setNotificationShown(StatusBarNotification n) { + mNotificationListener.setNotificationsShown(new String[] { n.getKey() }); + } + + protected void setNotificationsShown(String[] keys) { + mNotificationListener.setNotificationsShown(keys); + } + + protected void setNotificationsShownAll() { + ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); + final int N = activeNotifications.size(); + + String[] keys = new String[N]; + for (int i = 0; i < N; i++) { + NotificationData.Entry entry = activeNotifications.get(i); + keys[i] = entry.key; + } + setNotificationsShown(keys); + } + protected boolean isCurrentProfile(int userId) { synchronized (mCurrentProfiles) { return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null; @@ -1681,6 +1701,7 @@ public abstract class BaseStatusBar extends SystemUI implements boolean clearNotificationEffects = (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED); mBarService.onPanelRevealed(clearNotificationEffects); + setNotificationsShownAll(); } else { mBarService.onPanelHidden(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index c854d63..d058892 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -1119,6 +1119,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, boolean isHeadsUped = mUseHeadsUp && shouldInterrupt(notification); if (isHeadsUped) { mHeadsUpManager.showNotification(shadeEntry); + // Mark as seen immediately + setNotificationShown(notification); } if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) { diff --git a/preloaded-classes b/preloaded-classes index 95d0b42..c94623a 100644 --- a/preloaded-classes +++ b/preloaded-classes @@ -402,6 +402,7 @@ android.app.SharedPreferencesImpl$EditorImpl android.app.SharedPreferencesImpl$EditorImpl$1 android.app.SharedPreferencesImpl$EditorImpl$2 android.app.SharedPreferencesImpl$MemoryCommitResult +android.app.SystemServiceRegistry android.app.admin.DevicePolicyManager android.app.admin.IDevicePolicyManager$Stub android.app.admin.IDevicePolicyManager$Stub$Proxy diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index 89a7173..81088c4 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -1758,6 +1758,9 @@ class MountService extends IMountService.Stub @Override public void finishMediaUpdate() { + if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { + throw new SecurityException("no permission to call finishMediaUpdate()"); + } if (mUnmountSignal != null) { mUnmountSignal.countDown(); } else { @@ -1791,7 +1794,7 @@ class MountService extends IMountService.Stub warnOnNotMounted(); final ObbState state; - synchronized (mObbPathToStateMap) { + synchronized (mObbMounts) { state = mObbPathToStateMap.get(rawPath); } if (state == null) { @@ -1843,7 +1846,7 @@ class MountService extends IMountService.Stub Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); final ObbState existingState; - synchronized (mObbPathToStateMap) { + synchronized (mObbMounts) { existingState = mObbPathToStateMap.get(rawPath); } @@ -2093,6 +2096,8 @@ class MountService extends IMountService.Stub @Override public String getPassword() throws RemoteException { + mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, + "only keyguard can retrieve password"); if (!isReady()) { return new String(); } diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 1b32f57..999e91b 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -734,12 +734,15 @@ public class AccountManagerService throw new IllegalArgumentException("account is null"); } checkAuthenticateAccountsPermission(account); - - final UserAccounts accounts = getUserAccountsForCaller(); int userId = Binder.getCallingUserHandle().getIdentifier(); if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) { return false; } + return updateLastAuthenticatedTime(account); + } + + private boolean updateLastAuthenticatedTime(Account account) { + final UserAccounts accounts = getUserAccountsForCaller(); synchronized (accounts.cacheLock) { final ContentValues values = new ContentValues(); values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis()); @@ -2022,7 +2025,7 @@ public class AccountManagerService try { new Session(accounts, response, account.type, expectActivityLaunch, true /* stripAuthTokenFromResult */, account.name, - true /* authDetailsRequired */) { + true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) { @Override public void run() throws RemoteException { mAuthenticator.confirmCredentials(this, account, options); @@ -2059,7 +2062,7 @@ public class AccountManagerService try { new Session(accounts, response, account.type, expectActivityLaunch, true /* stripAuthTokenFromResult */, account.name, - false /* authDetailsRequired */) { + false /* authDetailsRequired */, true /* updateLastCredentialTime */) { @Override public void run() throws RemoteException { mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions); @@ -2492,6 +2495,11 @@ public class AccountManagerService final String mAccountName; // Indicates if we need to add auth details(like last credential time) final boolean mAuthDetailsRequired; + // If set, we need to update the last authenticated time. This is + // currently + // used on + // successful confirming credentials. + final boolean mUpdateLastAuthenticatedTime; public int mNumResults = 0; private int mNumRequestContinued = 0; @@ -2505,6 +2513,13 @@ public class AccountManagerService public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType, boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName, boolean authDetailsRequired) { + this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult, + accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */); + } + + public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType, + boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName, + boolean authDetailsRequired, boolean updateLastAuthenticatedTime) { super(); //if (response == null) throw new IllegalArgumentException("response is null"); if (accountType == null) throw new IllegalArgumentException("accountType is null"); @@ -2516,6 +2531,7 @@ public class AccountManagerService mCreationTime = SystemClock.elapsedRealtime(); mAccountName = accountName; mAuthDetailsRequired = authDetailsRequired; + mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime; synchronized (mSessions) { mSessions.put(toString(), this); @@ -2651,15 +2667,55 @@ public class AccountManagerService public void onResult(Bundle result) { mNumResults++; Intent intent = null; - if (result != null && mAuthDetailsRequired) { - long lastAuthenticatedTime = DatabaseUtils.longForQuery( - mAccounts.openHelper.getReadableDatabase(), - "select " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " from " + - TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND " - + ACCOUNTS_TYPE + "=?", - new String[]{mAccountName, mAccountType}); - result.putLong(AccountManager.KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH, - lastAuthenticatedTime); + if (result != null) { + boolean isSuccessfulConfirmCreds = result.getBoolean( + AccountManager.KEY_BOOLEAN_RESULT, false); + boolean isSuccessfulUpdateCreds = + result.containsKey(AccountManager.KEY_ACCOUNT_NAME) + && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE); + // We should only update lastAuthenticated time, if + // mUpdateLastAuthenticatedTime is true and the confirmRequest + // or updateRequest was successful + boolean needUpdate = mUpdateLastAuthenticatedTime + && (isSuccessfulConfirmCreds || isSuccessfulUpdateCreds); + if (needUpdate || mAuthDetailsRequired) { + boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType); + if (needUpdate && accountPresent) { + updateLastAuthenticatedTime(new Account(mAccountName, mAccountType)); + } + if (mAuthDetailsRequired) { + long lastAuthenticatedTime = -1; + if (accountPresent) { + lastAuthenticatedTime = DatabaseUtils.longForQuery( + mAccounts.openHelper.getReadableDatabase(), + "select " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + + " from " + + TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND " + + ACCOUNTS_TYPE + "=?", + new String[] { + mAccountName, mAccountType + }); + } + result.putLong(AccountManager.KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH, + lastAuthenticatedTime); + } + } + if (mAuthDetailsRequired) { + long lastAuthenticatedTime = -1; + if (isAccountPresentForCaller(mAccountName, mAccountType)) { + lastAuthenticatedTime = DatabaseUtils.longForQuery( + mAccounts.openHelper.getReadableDatabase(), + "select " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " from " + + + TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND " + + ACCOUNTS_TYPE + "=?", + new String[] { + mAccountName, mAccountType + }); + } + result.putLong(AccountManager.KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH, + lastAuthenticatedTime); + } } if (result != null && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) { @@ -3202,6 +3258,17 @@ public class AccountManagerService return false; } + private boolean isAccountPresentForCaller(String accountName, String accountType) { + if (getUserAccountsForCaller().accountCache.containsKey(accountType)) { + for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) { + if (account.name.equals(accountName)) { + return true; + } + } + } + return false; + } + private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType, int callerUid) { if (callerUid == Process.SYSTEM_UID) { diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index 28597c1..6b5908d 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -37,7 +37,6 @@ import android.hardware.fingerprint.IFingerprintServiceReceiver; import static android.Manifest.permission.MANAGE_FINGERPRINT; import static android.Manifest.permission.USE_FINGERPRINT; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -364,12 +363,12 @@ public class FingerprintService extends SystemService { private class ClientMonitor implements IBinder.DeathRecipient { IBinder token; - WeakReference<IFingerprintServiceReceiver> receiver; + IFingerprintServiceReceiver receiver; int userId; public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId) { this.token = token; - this.receiver = new WeakReference<IFingerprintServiceReceiver>(receiver); + this.receiver = receiver; this.userId = userId; try { token.linkToDeath(this, 0); @@ -389,6 +388,7 @@ public class FingerprintService extends SystemService { public void binderDied() { token = null; removeClient(this); + receiver = null; } protected void finalize() throws Throwable { @@ -406,10 +406,9 @@ public class FingerprintService extends SystemService { * @return true if we're done. */ private boolean sendRemoved(int fingerId, int groupId) { - IFingerprintServiceReceiver rx = receiver.get(); - if (rx == null) return true; // client not listening + if (receiver == null) return true; // client not listening try { - rx.onRemoved(mHalDeviceId, fingerId, groupId); + receiver.onRemoved(mHalDeviceId, fingerId, groupId); return fingerId == 0; } catch (RemoteException e) { Slog.w(TAG, "Failed to notify Removed:", e); @@ -421,11 +420,10 @@ public class FingerprintService extends SystemService { * @return true if we're done. */ private boolean sendEnrollResult(int fpId, int groupId, int remaining) { - IFingerprintServiceReceiver rx = receiver.get(); - if (rx == null) return true; // client not listening + if (receiver == null) return true; // client not listening FingerprintUtils.vibrateFingerprintSuccess(getContext()); try { - rx.onEnrollResult(mHalDeviceId, fpId, groupId, remaining); + receiver.onEnrollResult(mHalDeviceId, fpId, groupId, remaining); return remaining == 0; } catch (RemoteException e) { Slog.w(TAG, "Failed to notify EnrollResult:", e); @@ -437,11 +435,10 @@ public class FingerprintService extends SystemService { * @return true if we're done. */ private boolean sendAuthenticated(int fpId, int groupId) { - IFingerprintServiceReceiver rx = receiver.get(); boolean result = false; - if (rx != null) { + if (receiver != null) { try { - rx.onAuthenticated(mHalDeviceId, fpId, groupId); + receiver.onAuthenticated(mHalDeviceId, fpId, groupId); } catch (RemoteException e) { Slog.w(TAG, "Failed to notify Authenticated:", e); result = true; // client failed @@ -464,10 +461,9 @@ public class FingerprintService extends SystemService { * @return true if we're done. */ private boolean sendAcquired(int acquiredInfo) { - IFingerprintServiceReceiver rx = receiver.get(); - if (rx == null) return true; // client not listening + if (receiver == null) return true; // client not listening try { - rx.onAcquired(mHalDeviceId, acquiredInfo); + receiver.onAcquired(mHalDeviceId, acquiredInfo); return false; // acquisition continues... } catch (RemoteException e) { Slog.w(TAG, "Failed to invoke sendAcquired:", e); @@ -479,10 +475,9 @@ public class FingerprintService extends SystemService { * @return true if we're done. */ private boolean sendError(int error) { - IFingerprintServiceReceiver rx = receiver.get(); - if (rx != null) { + if (receiver != null) { try { - rx.onError(mHalDeviceId, error); + receiver.onError(mHalDeviceId, error); } catch (RemoteException e) { Slog.w(TAG, "Failed to invoke sendError:", e); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 1008653..25998da 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -36,6 +36,9 @@ import android.app.NotificationManager; import android.app.NotificationManager.Policy; import android.app.PendingIntent; import android.app.StatusBarManager; +import android.app.usage.UsageEvents; +import android.app.usage.UsageStats; +import android.app.usage.UsageStatsManagerInternal; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; @@ -97,6 +100,7 @@ import android.widget.Toast; import com.android.internal.R; import com.android.internal.util.FastXmlSerializer; import com.android.server.EventLogTags; +import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.lights.Light; import com.android.server.lights.LightsManager; @@ -236,6 +240,7 @@ public class NotificationManagerService extends SystemService { ArrayList<String> mLights = new ArrayList<>(); private AppOpsManager mAppOps; + private UsageStatsManagerInternal mAppUsageStats; private Archive mArchive; @@ -871,6 +876,7 @@ public class NotificationManagerService extends SystemService { mAm = ActivityManagerNative.getDefault(); mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); + mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class); mHandler = new WorkerHandler(); mRankingThread.start(); @@ -1405,6 +1411,41 @@ public class NotificationManagerService extends SystemService { } } + @Override + public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + long identity = Binder.clearCallingIdentity(); + try { + synchronized (mNotificationList) { + final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); + if (keys != null) { + final int N = keys.length; + for (int i = 0; i < N; i++) { + NotificationRecord r = mNotificationsByKey.get(keys[i]); + if (r == null) continue; + final int userId = r.sbn.getUserId(); + if (userId != info.userid && userId != UserHandle.USER_ALL && + !mUserProfiles.isCurrentProfile(userId)) { + throw new SecurityException("Disallowed call from listener: " + + info.service); + } + if (!r.isSeen()) { + if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]); + mAppUsageStats.reportEvent(r.sbn.getPackageName(), + userId == UserHandle.USER_ALL ? UserHandle.USER_OWNER + : userId, + UsageEvents.Event.INTERACTION); + r.setSeen(); + } + } + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + private void cancelNotificationFromListenerLocked(ManagedServiceInfo info, int callingUid, int callingPid, String pkg, String tag, int id, int userId) { cancelNotification(callingUid, callingPid, pkg, tag, id, 0, diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 5569a09..e106a4a 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -50,6 +50,8 @@ public final class NotificationRecord { NotificationUsageStats.SingleNotificationStats stats; boolean isCanceled; int score; + /** Whether the notification was seen by the user via one of the notification listeners. */ + boolean mIsSeen; // These members are used by NotificationSignalExtractors // to communicate with the ranking module. @@ -301,6 +303,16 @@ public final class NotificationRecord { return mGlobalSortKey; } + /** Check if any of the listeners have marked this notification as seen by the user. */ + public boolean isSeen() { + return mIsSeen; + } + + /** Mark the notification as seen by the user. */ + public void setSeen() { + mIsSeen = true; + } + public void setAuthoritativeRank(int authoritativeRank) { mAuthoritativeRank = authoritativeRank; } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 25857c5..5536d4d 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -2151,6 +2151,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { win.setType( WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); + + synchronized (mWindowManagerFuncs.getWindowManagerLock()) { + // Assumes it's safe to show starting windows of launched apps while + // the keyguard is being hidden. This is okay because starting windows never show + // secret information. + if (mKeyguardHidden) { + windowFlags |= FLAG_SHOW_WHEN_LOCKED; + } + } + // Force the window flags: this is a fake window, so it is not really // touchable or focusable by the user. We also add in the ALT_FOCUSABLE_IM // flag because we do know that the next window will take input @@ -4131,6 +4141,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (attrs.type == TYPE_STATUS_BAR && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { mForceStatusBarFromKeyguard = true; } + + boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW + && attrs.type < FIRST_SYSTEM_WINDOW; + final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0; + final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0; + if (mTopFullscreenOpaqueWindowState == null && win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) { if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) { @@ -4143,8 +4159,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { mShowingLockscreen = true; } - boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW - && attrs.type < FIRST_SYSTEM_WINDOW; if (attrs.type == TYPE_DREAM) { // If the lockscreen was showing when the dream started then wait // for the dream to draw before hiding the lockscreen. @@ -4155,8 +4169,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0; - final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0; if (appWindow) { final IApplicationToken appToken = win.getAppToken(); if (showWhenLocked) { @@ -4210,10 +4222,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (mWinShowWhenLocked != null && - mWinShowWhenLocked.getAppToken() != win.getAppToken()) { + mWinShowWhenLocked.getAppToken() != win.getAppToken() && + (attrs.flags & FLAG_SHOW_WHEN_LOCKED) == 0) { win.hideLw(false); } } + } else if (mTopFullscreenOpaqueWindowState == null && mWinShowWhenLocked == null) { + // No TopFullscreenOpaqueWindow is showing, but we found a SHOW_WHEN_LOCKED window + // that is being hidden in an animation - keep the + // keyguard hidden until the new window shows up and + // we know whether to show the keyguard or not. + if (win.isAnimatingLw() && appWindow && showWhenLocked) { + mHideLockScreen = true; + mWinShowWhenLocked = win; + } } if (mTopFullscreenOpaqueOrDimmingWindowState == null && win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw() diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 897b865..52071cc 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -201,9 +201,11 @@ public class WindowAnimator { null : winShowWhenLocked.mAppToken; final boolean hideWhenLocked = !(((win.mIsImWindow || imeTarget == win) && showImeOverKeyguard) - || (appShowWhenLocked != null && (appShowWhenLocked == win.mAppToken || + || (appShowWhenLocked != null && (appShowWhenLocked == win.mAppToken + // Show all SHOW_WHEN_LOCKED windows while they're animating + || (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && win.isAnimatingLw() // Show error dialogs over apps that dismiss keyguard. - (win.mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0))); + || (win.mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0))); return ((mForceHiding == KEYGUARD_ANIMATING_IN) && (!win.mWinAnimator.isAnimating() || hideWhenLocked)) || ((mForceHiding == KEYGUARD_SHOWN) && hideWhenLocked); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 3d54dfb..04984d3 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -17,7 +17,10 @@ package com.android.server.usage; import android.Manifest; +import android.app.ActivityManagerNative; +import android.app.AppGlobals; import android.app.AppOpsManager; +import android.app.admin.DevicePolicyManager; import android.app.usage.ConfigurationStats; import android.app.usage.IUsageStatsManager; import android.app.usage.UsageEvents; @@ -25,11 +28,13 @@ import android.app.usage.UsageEvents.Event; import android.app.usage.UsageStats; import android.app.usage.UsageStatsManagerInternal; import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener; +import android.appwidget.AppWidgetManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.UserInfo; @@ -82,6 +87,7 @@ public class UsageStatsService extends SystemService implements static final int MSG_FLUSH_TO_DISK = 1; static final int MSG_REMOVE_USER = 2; static final int MSG_INFORM_LISTENERS = 3; + static final int MSG_RESET_LAST_TIMESTAMP = 4; private final Object mLock = new Object(); Handler mHandler; @@ -279,6 +285,29 @@ public class UsageStatsService extends SystemService implements } /** + * Forces the app's timestamp to reflect idle or active. If idle, then it rolls back the + * last used timestamp to a point in time thats behind the threshold for idle. + */ + void resetLastTimestamp(String packageName, int userId, boolean idle) { + synchronized (mLock) { + final long timeNow = checkAndGetTimeLocked(); + final long lastTimestamp = timeNow - (idle ? mAppIdleDurationMillis : 0); + + final UserUsageStatsService service = + getUserDataAndInitializeIfNeededLocked(userId, timeNow); + final long lastUsed = service.getLastPackageAccessTime(packageName); + final boolean previouslyIdle = hasPassedIdleDuration(lastUsed); + service.setLastTimestamp(packageName, lastTimestamp); + // Inform listeners if necessary + if (previouslyIdle != idle) { + // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage); + mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId, + /* idle = */ idle ? 1 : 0, packageName)); + } + } + } + + /** * Called by the Binder stub. */ void flushToDisk() { @@ -384,13 +413,39 @@ public class UsageStatsService extends SystemService implements } boolean isAppIdle(String packageName, int userId) { + if (packageName == null) return false; if (SystemConfig.getInstance().getAllowInPowerSave().contains(packageName)) { return false; } + if (isActiveDeviceAdmin(packageName, userId)) { + return false; + } + final long lastUsed = getLastPackageAccessTime(packageName, userId); return hasPassedIdleDuration(lastUsed); } + void setAppIdle(String packageName, boolean idle, int userId) { + if (packageName == null) return; + + mHandler.obtainMessage(MSG_RESET_LAST_TIMESTAMP, userId, idle ? 1 : 0, packageName) + .sendToTarget(); + } + + private boolean isActiveDeviceAdmin(String packageName, int userId) { + DevicePolicyManager dpm = getContext().getSystemService(DevicePolicyManager.class); + if (dpm == null) return false; + List<ComponentName> components = dpm.getActiveAdminsAsUser(userId); + if (components == null) return false; + final int size = components.size(); + for (int i = 0; i < size; i++) { + if (components.get(i).getPackageName().equals(packageName)) { + return true; + } + } + return false; + } + void informListeners(String packageName, int userId, boolean isIdle) { for (AppIdleStateChangeListener listener : mPackageAccessListeners) { listener.onAppIdleStateChanged(packageName, userId, isIdle); @@ -459,6 +514,10 @@ public class UsageStatsService extends SystemService implements informListeners((String) msg.obj, msg.arg1, msg.arg2 == 1); break; + case MSG_RESET_LAST_TIMESTAMP: + resetLastTimestamp((String) msg.obj, msg.arg1, msg.arg2 == 1); + break; + default: super.handleMessage(msg); break; @@ -566,6 +625,46 @@ public class UsageStatsService extends SystemService implements } @Override + public boolean isAppIdle(String packageName, int userId) { + try { + userId = ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, false, true, "isAppIdle", null); + } catch (RemoteException re) { + return false; + } + final long token = Binder.clearCallingIdentity(); + try { + return UsageStatsService.this.isAppIdle(packageName, userId); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void setAppIdle(String packageName, boolean idle, int userId) { + final int callingUid = Binder.getCallingUid(); + try { + userId = ActivityManagerNative.getDefault().handleIncomingUser( + Binder.getCallingPid(), callingUid, userId, false, true, + "setAppIdle", null); + } catch (RemoteException re) { + return; + } + getContext().enforceCallingPermission(Manifest.permission.CHANGE_APP_IDLE_STATE, + "No permission to change app idle state"); + final long token = Binder.clearCallingIdentity(); + try { + PackageInfo pi = AppGlobals.getPackageManager() + .getPackageInfo(packageName, 0, userId); + if (pi == null) return; + UsageStatsService.this.setAppIdle(packageName, idle, userId); + } catch (RemoteException re) { + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index 0a9481a..d94759d 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -211,6 +211,17 @@ class UserUsageStatsService { notifyStatsChanged(); } + /** + * Sets the last timestamp for each of the intervals. + * @param lastTimestamp + */ + void setLastTimestamp(String packageName, long lastTimestamp) { + for (IntervalStats stats : mCurrentStats) { + stats.update(packageName, lastTimestamp, UsageEvents.Event.NONE); + } + notifyStatsChanged(); + } + private static final StatCombiner<UsageStats> sUsageStatsCombiner = new StatCombiner<UsageStats>() { @Override diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java index 8f0c6c8..daccf95 100644 --- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java +++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java @@ -142,8 +142,10 @@ public final class UsbAlsaManager { // add existing alsa devices File[] files = new File(ALSA_DIRECTORY).listFiles(); - for (int i = 0; i < files.length; i++) { - alsaFileAdded(files[i].getName()); + if (files != null) { + for (int i = 0; i < files.length; i++) { + alsaFileAdded(files[i].getName()); + } } } diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java index eef72fb..bf8fac6 100644 --- a/telecomm/java/android/telecom/DefaultDialerManager.java +++ b/telecomm/java/android/telecom/DefaultDialerManager.java @@ -87,15 +87,15 @@ public class DefaultDialerManager { } // No user-set dialer found, fallback to system dialer - ComponentName systemDialer = getTelecomManager(context).getDefaultPhoneApp(); + String systemDialer = getTelecomManager(context).getSystemDialerPackage(); - if (systemDialer == null) { + if (TextUtils.isEmpty(systemDialer)) { // No system dialer configured at build time return null; } // Verify that the system dialer has not been disabled. - return getComponentName(componentNames, systemDialer.getPackageName()); + return getComponentName(componentNames, systemDialer); } /** diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index fd95327..8d6bda8 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -110,6 +110,28 @@ public class TelecomManager { "android.telecom.action.PHONE_ACCOUNT_REGISTERED"; /** + * Activity action: Shows a dialog asking the user whether or not they want to replace the + * current default Dialer with the one specified in + * {@link #EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME}. + * + * Usage example: + * <pre> + * Intent intent = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER); + * intent.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, + * getActivity().getPackageName()); + * startActivity(intent); + * </pre> + */ + public static final String ACTION_CHANGE_DEFAULT_DIALER = + "android.telecom.action.CHANGE_DEFAULT_DIALER"; + + /** + * Extra value used to provide the package name for {@link #ACTION_CHANGE_DEFAULT_DIALER}. + */ + public static final String EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME = + "android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME"; + + /** * Optional extra for {@link android.content.Intent#ACTION_CALL} containing a boolean that * determines whether the speakerphone should be automatically turned on for an outgoing call. */ @@ -689,7 +711,10 @@ public class TelecomManager { } } + /** + * @deprecated - Use {@link TelecomManager#getDefaultDialerPackage} to directly access + * the default dialer's package name instead. * @hide */ @SystemApi @@ -705,6 +730,40 @@ public class TelecomManager { } /** + * Used to determine the currently selected default dialer package. + * + * @return package name for the default dialer package or null if no package has been + * selected as the default dialer. + */ + public String getDefaultDialerPackage() { + try { + if (isServiceConnected()) { + return getTelecomService().getDefaultDialerPackage(); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException attempting to get the default dialer package name.", e); + } + return null; + } + + /** + * Used to determine the dialer package that is preloaded on the system partition. + * + * @return package name for the system dialer package or null if no system dialer is preloaded. + * @hide + */ + public String getSystemDialerPackage() { + try { + if (isServiceConnected()) { + return getTelecomService().getSystemDialerPackage(); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException attempting to get the system dialer package name.", e); + } + return null; + } + + /** * Return whether a given phone number is the configured voicemail number for a * particular phone account. * diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl index 45b2482..49f2aad 100644 --- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl +++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl @@ -137,6 +137,16 @@ interface ITelecomService { */ ComponentName getDefaultPhoneApp(); + /** + * @see TelecomServiceImpl#getDefaultDialerPackage + */ + String getDefaultDialerPackage(); + + /** + * @see TelecomServiceImpl#getSystemDialerPackage + */ + String getSystemDialerPackage(); + // // Internal system apis relating to call management. // diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 7d1a2fa..831a194 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -208,13 +208,13 @@ public class CarrierConfigManager { } /** - * Returns a bundle with the default value for every supported configuration variable. + * Returns a new bundle with the default value for every supported configuration variable. * * @hide */ @SystemApi public static Bundle getDefaultConfig() { - return sDefaults; + return new Bundle(sDefaults); } /** @hide */ diff --git a/tools/obbtool/pbkdf2gen.cpp b/tools/obbtool/pbkdf2gen.cpp index 98d67c0..f1d8d04 100644 --- a/tools/obbtool/pbkdf2gen.cpp +++ b/tools/obbtool/pbkdf2gen.cpp @@ -20,6 +20,7 @@ #include <errno.h> #include <fcntl.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <unistd.h> |
