summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt64
-rw-r--r--api/system-current.txt69
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java51
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java41
-rw-r--r--core/java/android/animation/Animator.java118
-rw-r--r--core/java/android/animation/AnimatorInflater.java13
-rw-r--r--core/java/android/animation/AnimatorSet.java1
-rw-r--r--core/java/android/animation/ValueAnimator.java5
-rw-r--r--core/java/android/app/ActivityThread.java116
-rw-r--r--core/java/android/app/ApplicationPackageManager.java2
-rw-r--r--core/java/android/app/INotificationManager.aidl2
-rw-r--r--core/java/android/app/usage/IUsageStatsManager.aidl2
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java17
-rw-r--r--core/java/android/hardware/Sensor.java18
-rw-r--r--core/java/android/hardware/SensorManager.java100
-rw-r--r--core/java/android/hardware/SystemSensorManager.java112
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestThreadManager.java3
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java10
-rw-r--r--core/java/android/os/Parcel.java47
-rw-r--r--core/java/android/os/storage/IMountService.java12
-rw-r--r--core/java/android/os/storage/StorageManager.java20
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java14
-rw-r--r--core/java/android/view/animation/AnimationUtils.java85
-rw-r--r--core/java/android/widget/GridView.java27
-rw-r--r--core/java/android/widget/RemoteViewsAdapter.java4
-rw-r--r--core/java/android/widget/ZoomButtonsController.java4
-rw-r--r--core/jni/android_hardware_SensorManager.cpp33
-rw-r--r--core/jni/android_media_AudioTrack.cpp38
-rw-r--r--core/res/AndroidManifest.xml5
-rw-r--r--core/res/res/drawable/list_choice_background_material.xml (renamed from core/res/res/drawable/list_highlight_material.xml)0
-rw-r--r--core/res/res/values/attrs.xml16
-rw-r--r--core/res/res/values/public.xml4
-rw-r--r--core/res/res/values/styles_material.xml2
-rw-r--r--core/res/res/values/themes_material.xml6
-rw-r--r--docs/html/google/play-services/index.jd24
-rw-r--r--keystore/java/android/security/AndroidKeyPairGenerator.java14
-rw-r--r--keystore/java/android/security/CryptoOperationException.java59
-rw-r--r--keystore/java/android/security/KeyExpiredException.java4
-rw-r--r--keystore/java/android/security/KeyNotYetValidException.java4
-rw-r--r--keystore/java/android/security/KeyStore.java29
-rw-r--r--keystore/java/android/security/KeyStoreCipherSpi.java60
-rw-r--r--keystore/java/android/security/KeyStoreConnectException.java2
-rw-r--r--keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java12
-rw-r--r--keystore/java/android/security/KeyStoreHmacSpi.java24
-rw-r--r--keystore/java/android/security/KeyStoreKeyGeneratorSpi.java3
-rw-r--r--keystore/java/android/security/NewFingerprintEnrolledException.java4
-rw-r--r--keystore/java/android/security/UserNotAuthenticatedException.java4
-rw-r--r--keystore/tests/src/android/security/AndroidKeyStoreTest.java18
-rw-r--r--keystore/tests/src/android/security/KeyStoreTest.java30
-rw-r--r--media/java/android/media/AudioFormat.java15
-rw-r--r--media/java/android/media/AudioManager.java14
-rw-r--r--media/java/android/media/AudioTrack.java56
-rw-r--r--media/java/android/media/Image.java29
-rw-r--r--media/java/android/media/ImageReader.java16
-rw-r--r--media/java/android/media/ImageWriter.java74
-rw-r--r--media/java/android/media/MediaCodec.java35
-rw-r--r--media/java/android/media/MediaSync.java78
-rw-r--r--media/java/android/media/PlaybackSettings.java12
-rw-r--r--media/java/android/media/tv/TvContentRating.java15
-rw-r--r--media/java/android/media/tv/TvInputManager.java110
-rw-r--r--media/java/android/media/tv/TvInputService.java11
-rw-r--r--media/java/android/media/tv/TvTrackInfo.java9
-rw-r--r--media/jni/android_media_ImageWriter.cpp2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java10
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rwxr-xr-xpackages/SystemUI/src/com/android/systemui/BatteryMeterView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java2
-rw-r--r--preloaded-classes1
-rw-r--r--services/core/java/com/android/server/MountService.java152
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java93
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintService.java31
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java41
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java12
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java18
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java32
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java6
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java7
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java99
-rw-r--r--services/usage/java/com/android/server/usage/UserUsageStatsService.java11
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaManager.java6
-rw-r--r--telecomm/java/android/telecom/DefaultDialerManager.java6
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java59
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl10
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java4
-rw-r--r--tools/aapt2/BinaryResourceParser.cpp7
-rw-r--r--tools/aapt2/Main.cpp342
-rw-r--r--tools/aapt2/TableFlattener.cpp72
-rw-r--r--tools/aapt2/TableFlattener.h5
-rw-r--r--tools/aapt2/ZipEntry.cpp8
-rw-r--r--tools/aapt2/ZipEntry.h5
-rw-r--r--tools/aapt2/ZipFile.cpp7
-rw-r--r--tools/aapt2/ZipFile.h6
-rw-r--r--tools/aapt2/data/Makefile4
-rw-r--r--tools/aapt2/data/lib/Makefile2
-rw-r--r--tools/aapt2/data/lib/res/layout/main.xml4
-rw-r--r--tools/aapt2/data/lib/res/raw/hello.txt1
-rw-r--r--tools/obbtool/pbkdf2gen.cpp1
99 files changed, 1801 insertions, 1116 deletions
diff --git a/api/current.txt b/api/current.txt
index 2f63509..4ff18d7 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,30 +16435,26 @@ 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();
method public int getAudioFallbackMode();
- method public int getAudioStretchMode();
method public float getPitch();
method public float getSpeed();
method public android.media.PlaybackSettings setAudioFallbackMode(int);
- method public android.media.PlaybackSettings setAudioStretchMode(int);
method public android.media.PlaybackSettings setPitch(float);
method public android.media.PlaybackSettings setSpeed(float);
field public static final int AUDIO_FALLBACK_MODE_DEFAULT = 0; // 0x0
field public static final int AUDIO_FALLBACK_MODE_FAIL = 2; // 0x2
field public static final int AUDIO_FALLBACK_MODE_MUTE = 1; // 0x1
- field public static final int AUDIO_STRETCH_MODE_DEFAULT = 0; // 0x0
- 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 {
@@ -17819,6 +17821,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 +23407,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 +23452,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 +28449,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 +28505,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 +28547,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 +28695,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 +28913,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 +30606,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 +30621,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 +30632,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..87e130c 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);
@@ -13260,6 +13256,7 @@ package android.hardware {
method public int getType();
method public java.lang.String getVendor();
method public int getVersion();
+ method public boolean isDataInjectionSupported();
method public boolean isWakeUpSensor();
field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
@@ -13335,6 +13332,7 @@ package android.hardware {
public abstract class SensorManager {
method public boolean cancelTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
+ method public boolean enableDataInjectionMode(boolean);
method public boolean flush(android.hardware.SensorEventListener);
method public static float getAltitude(float, float);
method public static void getAngleChange(float[], float[], float[]);
@@ -13347,6 +13345,7 @@ package android.hardware {
method public static void getRotationMatrixFromVector(float[], float[]);
method public java.util.List<android.hardware.Sensor> getSensorList(int);
method public deprecated int getSensors();
+ method public boolean injectSensorData(android.hardware.Sensor, float[], int, long);
method public deprecated boolean registerListener(android.hardware.SensorListener, int);
method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -15947,7 +15946,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 +16102,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 +17610,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 +17624,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,30 +17654,26 @@ 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();
method public int getAudioFallbackMode();
- method public int getAudioStretchMode();
method public float getPitch();
method public float getSpeed();
method public android.media.PlaybackSettings setAudioFallbackMode(int);
- method public android.media.PlaybackSettings setAudioStretchMode(int);
method public android.media.PlaybackSettings setPitch(float);
method public android.media.PlaybackSettings setSpeed(float);
field public static final int AUDIO_FALLBACK_MODE_DEFAULT = 0; // 0x0
field public static final int AUDIO_FALLBACK_MODE_FAIL = 2; // 0x2
field public static final int AUDIO_FALLBACK_MODE_MUTE = 1; // 0x1
- field public static final int AUDIO_STRETCH_MODE_DEFAULT = 0; // 0x0
- 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 {
@@ -19104,6 +19109,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 +25299,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 +25344,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 +30456,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 +30512,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 +30554,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 +30702,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 +30961,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 +32753,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 +32774,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 +32787,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/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index b84b1e2..39de1dc7 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -30,7 +30,6 @@ import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageManager;
-import android.content.pm.IPackageMoveObserver;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
@@ -237,8 +236,12 @@ public final class Pm {
return runForceDexOpt();
}
- if ("move".equals(op)) {
- return runMove();
+ if ("move-package".equals(op)) {
+ return runMovePackage();
+ }
+
+ if ("move-primary-storage".equals(op)) {
+ return runMovePrimaryStorage();
}
try {
@@ -1285,7 +1288,7 @@ public final class Pm {
}
}
- public int runMove() {
+ public int runMovePackage() {
final String packageName = nextArg();
String volumeUuid = nextArg();
if ("internal".equals(volumeUuid)) {
@@ -1313,6 +1316,33 @@ public final class Pm {
}
}
+ public int runMovePrimaryStorage() {
+ String volumeUuid = nextArg();
+ if ("internal".equals(volumeUuid)) {
+ volumeUuid = null;
+ }
+
+ try {
+ final int moveId = mPm.movePrimaryStorage(volumeUuid);
+
+ int status = mPm.getMoveStatus(moveId);
+ while (!PackageManager.isMoveStatusFinished(status)) {
+ SystemClock.sleep(DateUtils.SECOND_IN_MILLIS);
+ status = mPm.getMoveStatus(moveId);
+ }
+
+ if (status == PackageManager.MOVE_SUCCEEDED) {
+ System.out.println("Success");
+ return 0;
+ } else {
+ System.err.println("Failure [" + status + "]");
+ return 1;
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
private int runUninstall() throws RemoteException {
int flags = 0;
int userId = UserHandle.USER_ALL;
@@ -1860,7 +1890,8 @@ public final class Pm {
System.err.println(" pm install-abandon SESSION_ID");
System.err.println(" pm uninstall [-k] [--user USER_ID] PACKAGE");
System.err.println(" pm set-installer PACKAGE INSTALLER");
- System.err.println(" pm move PACKAGE [internal|UUID]");
+ System.err.println(" pm move-package PACKAGE [internal|UUID]");
+ System.err.println(" pm move-primary-storage [internal|UUID]");
System.err.println(" pm clear [--user USER_ID] PACKAGE");
System.err.println(" pm enable [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm disable [--user USER_ID] PACKAGE_OR_COMPONENT");
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/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 10f5960..16a2430 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1556,6 +1556,7 @@ final class ApplicationPackageManager extends PackageManager {
}
}
+ @Override
public @Nullable VolumeInfo getPrimaryStorageCurrentVolume() {
final StorageManager storage = mContext.getSystemService(StorageManager.class);
final String volumeUuid = storage.getPrimaryStorageUuid();
@@ -1568,6 +1569,7 @@ final class ApplicationPackageManager extends PackageManager {
}
}
+ @Override
public @NonNull List<VolumeInfo> getPrimaryStorageCandidateVolumes() {
final StorageManager storage = mContext.getSystemService(StorageManager.class);
final VolumeInfo currentVol = getPrimaryStorageCurrentVolume();
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/Sensor.java b/core/java/android/hardware/Sensor.java
index 39f4cca..e875864 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -580,6 +580,10 @@ public final class Sensor {
private static final int REPORTING_MODE_MASK = 0xE;
private static final int REPORTING_MODE_SHIFT = 1;
+ // MASK for LSB fifth bit. Used to know whether the sensor supports data injection or not.
+ private static final int DATA_INJECTION_MASK = 0x10;
+ private static final int DATA_INJECTION_SHIFT = 4;
+
// TODO(): The following arrays are fragile and error-prone. This needs to be refactored.
// Note: This needs to be updated, whenever a new sensor is added.
@@ -822,6 +826,20 @@ public final class Sensor {
return (mFlags & SENSOR_FLAG_WAKE_UP_SENSOR) != 0;
}
+ /**
+ * Returns true if the sensor supports data injection when the
+ * HAL is set to data injection mode.
+ *
+ * @return <code>true</code> if the sensor supports data
+ * injection when the HAL is set in injection mode,
+ * false otherwise.
+ * @hide
+ */
+ @SystemApi
+ public boolean isDataInjectionSupported() {
+ return (((mFlags & DATA_INJECTION_MASK) >> DATA_INJECTION_SHIFT)) != 0;
+ }
+
void setRange(float max, float res) {
mMaxRange = max;
mResolution = res;
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 34b895b..861969e 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -16,7 +16,10 @@
package android.hardware;
+import android.annotation.SystemApi;
+import android.os.Build;
import android.os.Handler;
+import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
@@ -1555,6 +1558,103 @@ public abstract class SensorManager {
Sensor sensor, boolean disable);
+ /**
+ * For testing purposes only. Not for third party applications.
+ *
+ * Enable data injection mode in sensor service. This mode is
+ * expected to be used only for testing purposes. If the HAL is
+ * set to data injection mode, it will ignore the input from
+ * physical sensors and read sensor data that is injected from
+ * the test application. This mode is used for testing vendor
+ * implementations for various algorithms like Rotation Vector,
+ * Significant Motion, Step Counter etc.
+ *
+ * The tests which call this API need to have {@code
+ * android.permission.HARDWARE_TEST} permission which isn't
+ * available for third party applications.
+ *
+ * @param enable True to set the HAL in DATA_INJECTION mode.
+ * False to reset the HAL back to NORMAL mode.
+ *
+ * @return true if the HAL supports data injection and false
+ * otherwise.
+ * @hide
+ */
+ @SystemApi
+ public boolean enableDataInjectionMode(boolean enable) {
+ return enableDataInjectionImpl(enable);
+ }
+
+ /**
+ * @hide
+ */
+ protected abstract boolean enableDataInjectionImpl(boolean enable);
+
+ /**
+ * For testing purposes only. Not for third party applications.
+ *
+ * This method is used to inject raw sensor data into the HAL.
+ * Call enableDataInjection before this method to set the HAL in
+ * data injection mode. This method should be called only if a
+ * previous call to enableDataInjection has been successful and
+ * the HAL is already in data injection mode.
+ *
+ * The tests which call this API need to have {@code
+ * android.permission.HARDWARE_TEST} permission which isn't
+ * available for third party applications.
+ *
+ * @param sensor The sensor to inject.
+ * @param values Sensor values to inject. The length of this
+ * array must be exactly equal to the number of
+ * values reported by the sensor type.
+ * @param accuracy Accuracy of the sensor.
+ * @param timestamp Sensor timestamp associated with the event.
+ *
+ * @return boolean True if the data injection succeeds, false
+ * otherwise.
+ * @throws IllegalArgumentException when the sensor is null,
+ * data injection is not supported by the sensor, values
+ * are null, incorrect number of values for the sensor,
+ * sensor accuracy is incorrect or timestamps are
+ * invalid.
+ * @hide
+ */
+ @SystemApi
+ public boolean injectSensorData(Sensor sensor, float[] values, int accuracy,
+ long timestamp) {
+ if (sensor == null) {
+ throw new IllegalArgumentException("sensor cannot be null");
+ }
+ if (!sensor.isDataInjectionSupported()) {
+ throw new IllegalArgumentException("sensor does not support data injection");
+ }
+ if (values == null) {
+ throw new IllegalArgumentException("sensor data cannot be null");
+ }
+ int expectedNumValues = Sensor.getMaxLengthValuesArray(sensor, Build.VERSION_CODES.MNC);
+ if (values.length != expectedNumValues) {
+ throw new IllegalArgumentException ("Wrong number of values for sensor " +
+ sensor.getName() + " actual=" + values.length + " expected=" +
+ expectedNumValues);
+ }
+ if (accuracy < SENSOR_STATUS_NO_CONTACT || accuracy > SENSOR_STATUS_ACCURACY_HIGH) {
+ throw new IllegalArgumentException("Invalid sensor accuracy");
+ }
+ if (timestamp <= 0) {
+ throw new IllegalArgumentException("Negative or zero sensor timestamp");
+ }
+ if (timestamp > SystemClock.elapsedRealtimeNanos()) {
+ throw new IllegalArgumentException("Sensor timestamp into the future");
+ }
+ return injectSensorDataImpl(sensor, values, accuracy, timestamp);
+ }
+
+ /**
+ * @hide
+ */
+ protected abstract boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
+ long timestamp);
+
private LegacySensorManager getLegacySensorManager() {
synchronized (mSensorListByType) {
if (mLegacySensorManager == null) {
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 7ad3a68..11037fd 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -16,7 +16,9 @@
package android.hardware;
+import android.Manifest;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
@@ -40,11 +42,14 @@ import java.util.List;
public class SystemSensorManager extends SensorManager {
private static native void nativeClassInit();
private static native int nativeGetNextSensor(Sensor sensor, int next);
+ private static native int nativeEnableDataInjection(boolean enable);
private static boolean sSensorModuleInitialized = false;
private static final Object sSensorModuleLock = new Object();
private static final ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>();
private static final SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>();
+ private static InjectEventQueue mInjectEventQueue = null;
+ private static boolean mDataInjectionMode = false;
// Listener list
private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners =
@@ -56,6 +61,7 @@ public class SystemSensorManager extends SensorManager {
private final Looper mMainLooper;
private final int mTargetSdkLevel;
private final String mPackageName;
+ private final boolean mHasDataInjectionPermissions;
/** {@hide} */
public SystemSensorManager(Context context, Looper mainLooper) {
@@ -82,6 +88,8 @@ public class SystemSensorManager extends SensorManager {
}
} while (i>0);
}
+ mHasDataInjectionPermissions = context.checkSelfPermission(
+ Manifest.permission.HARDWARE_TEST) == PackageManager.PERMISSION_GRANTED;
}
}
@@ -219,19 +227,72 @@ public class SystemSensorManager extends SensorManager {
}
}
+ protected boolean enableDataInjectionImpl(boolean enable) {
+ if (!mHasDataInjectionPermissions) {
+ throw new SecurityException("Permission denial. Calling enableDataInjection without "
+ + Manifest.permission.HARDWARE_TEST);
+ }
+ synchronized (sSensorModuleLock) {
+ int ret = nativeEnableDataInjection(enable);
+ // The HAL does not support injection. Ignore.
+ if (ret != 0) {
+ Log.e(TAG, "HAL does not support data injection");
+ return false;
+ }
+ mDataInjectionMode = enable;
+ // If data injection is being disabled clean up the native resources.
+ if (!enable && mInjectEventQueue != null) {
+ mInjectEventQueue.dispose();
+ mInjectEventQueue = null;
+ }
+ return true;
+ }
+ }
+
+ protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
+ long timestamp) {
+ if (!mHasDataInjectionPermissions) {
+ throw new SecurityException("Permission denial. Calling injectSensorData without "
+ + Manifest.permission.HARDWARE_TEST);
+ }
+ synchronized (sSensorModuleLock) {
+ if (!mDataInjectionMode) {
+ Log.e(TAG, "Data injection mode not activated before calling injectSensorData");
+ return false;
+ }
+ if (mInjectEventQueue == null) {
+ mInjectEventQueue = new InjectEventQueue(mMainLooper, this);
+ }
+ int ret = mInjectEventQueue.injectSensorData(sensor.getHandle(), values, accuracy,
+ timestamp);
+ // If there are any errors in data injection clean up the native resources.
+ if (ret != 0) {
+ mInjectEventQueue.dispose();
+ mInjectEventQueue = null;
+ mDataInjectionMode = false;
+ }
+ return ret == 0;
+ }
+ }
+
/*
* BaseEventQueue is the communication channel with the sensor service,
* SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
- * the queues and the listeners.
+ * the queues and the listeners. InjectEventQueue is also a sub-class which is a special case
+ * where data is being injected into the sensor HAL through the sensor service. It is not
+ * associated with any listener and there is one InjectEventQueue associated with a
+ * SensorManager instance.
*/
private static abstract class BaseEventQueue {
private native long nativeInitBaseEventQueue(WeakReference<BaseEventQueue> eventQWeak,
- MessageQueue msgQ, float[] scratch, String packageName);
+ MessageQueue msgQ, float[] scratch, String packageName, int mode);
private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
int maxBatchReportLatencyUs);
private static native int nativeDisableSensor(long eventQ, int handle);
private static native void nativeDestroySensorEventQueue(long eventQ);
private static native int nativeFlushSensor(long eventQ);
+ private static native int nativeInjectSensorData(long eventQ, int handle,
+ float[] values,int accuracy, long timestamp);
private long nSensorEventQueue;
private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
@@ -240,10 +301,12 @@ public class SystemSensorManager extends SensorManager {
private final float[] mScratch = new float[16];
protected final SystemSensorManager mManager;
- BaseEventQueue(Looper looper, SystemSensorManager manager) {
+ protected static final int OPERATING_MODE_NORMAL = 0;
+ protected static final int OPERATING_MODE_DATA_INJECTION = 1;
+
+ BaseEventQueue(Looper looper, SystemSensorManager manager, int mode) {
nSensorEventQueue = nativeInitBaseEventQueue(new WeakReference<BaseEventQueue>(this),
- looper.getQueue(), mScratch,
- manager.mPackageName);
+ looper.getQueue(), mScratch, manager.mPackageName, mode);
mCloseGuard.open("dispose");
mManager = manager;
}
@@ -340,6 +403,11 @@ public class SystemSensorManager extends SensorManager {
maxBatchReportLatencyUs);
}
+ protected int injectSensorDataBase(int handle, float[] values, int accuracy,
+ long timestamp) {
+ return nativeInjectSensorData(nSensorEventQueue, handle, values, accuracy, timestamp);
+ }
+
private int disableSensor(Sensor sensor) {
if (nSensorEventQueue == 0) throw new NullPointerException();
if (sensor == null) throw new NullPointerException();
@@ -359,7 +427,7 @@ public class SystemSensorManager extends SensorManager {
public SensorEventQueue(SensorEventListener listener, Looper looper,
SystemSensorManager manager) {
- super(looper, manager);
+ super(looper, manager, OPERATING_MODE_NORMAL);
mListener = listener;
}
@@ -426,7 +494,7 @@ public class SystemSensorManager extends SensorManager {
public TriggerEventQueue(TriggerEventListener listener, Looper looper,
SystemSensorManager manager) {
- super(looper, manager);
+ super(looper, manager, OPERATING_MODE_NORMAL);
mListener = listener;
}
@@ -477,4 +545,34 @@ public class SystemSensorManager extends SensorManager {
protected void dispatchFlushCompleteEvent(int handle) {
}
}
+
+ static final class InjectEventQueue extends BaseEventQueue {
+ public InjectEventQueue(Looper looper, SystemSensorManager manager) {
+ super(looper, manager, OPERATING_MODE_DATA_INJECTION);
+ }
+
+ int injectSensorData(int handle, float[] values,int accuracy, long timestamp) {
+ return injectSensorDataBase(handle, values, accuracy, timestamp);
+ }
+
+ @SuppressWarnings("unused")
+ protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
+ long timestamp) {
+ }
+
+ @SuppressWarnings("unused")
+ protected void dispatchFlushCompleteEvent(int handle) {
+
+ }
+
+ @SuppressWarnings("unused")
+ protected void addSensorEvent(Sensor sensor) {
+
+ }
+
+ @SuppressWarnings("unused")
+ protected void removeSensorEvent(Sensor sensor) {
+
+ }
+ }
}
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/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 0b1031c..16e0bf7 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -16,6 +16,7 @@
package android.os.storage;
+import android.content.pm.IPackageMoveObserver;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
@@ -1082,12 +1083,14 @@ public interface IMountService extends IInterface {
}
@Override
- public void setPrimaryStorageUuid(String volumeUuid) throws RemoteException {
+ public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
+ throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(volumeUuid);
+ _data.writeStrongBinder((callback != null ? callback.asBinder() : null));
mRemote.transact(Stub.TRANSACTION_setPrimaryStorageUuid, _data, _reply, 0);
_reply.readException();
} finally {
@@ -1714,7 +1717,9 @@ public interface IMountService extends IInterface {
case TRANSACTION_setPrimaryStorageUuid: {
data.enforceInterface(DESCRIPTOR);
String volumeUuid = data.readString();
- setPrimaryStorageUuid(volumeUuid);
+ IPackageMoveObserver listener = IPackageMoveObserver.Stub.asInterface(
+ data.readStrongBinder());
+ setPrimaryStorageUuid(volumeUuid, listener);
reply.writeNoException();
return true;
}
@@ -2020,5 +2025,6 @@ public interface IMountService extends IInterface {
public void setVolumeUserFlags(String volId, int flags, int mask) throws RemoteException;
public String getPrimaryStorageUuid() throws RemoteException;
- public void setPrimaryStorageUuid(String volumeUuid) throws RemoteException;
+ public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
+ throws RemoteException;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 747fb40..6116aef 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -22,6 +22,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.IPackageMoveObserver;
+import android.content.pm.PackageManager;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
@@ -642,7 +644,12 @@ public class StorageManager {
}
}
- /** {@hide} */
+ /**
+ * This is not the API you're looking for.
+ *
+ * @see PackageManager#getPrimaryStorageCurrentVolume()
+ * @hide
+ */
public String getPrimaryStorageUuid() {
try {
return mMountService.getPrimaryStorageUuid();
@@ -651,10 +658,15 @@ public class StorageManager {
}
}
- /** {@hide} */
- public void setPrimaryStorageUuid(String volumeUuid) {
+ /**
+ * This is not the API you're looking for.
+ *
+ * @see PackageManager#movePrimaryStorage(VolumeInfo)
+ * @hide
+ */
+ public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
try {
- mMountService.setPrimaryStorageUuid(volumeUuid);
+ mMountService.setPrimaryStorageUuid(volumeUuid, callback);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
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_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 16e5b3c..0cf596c 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -174,6 +174,11 @@ nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next)
return size_t(next) < count ? next : 0;
}
+static int nativeEnableDataInjection(JNIEnv *_env, jclass _this, jboolean enable) {
+ SensorManager& mgr(SensorManager::getInstance());
+ return mgr.enableDataInjection(enable);
+}
+
//----------------------------------------------------------------------------
class Receiver : public LooperCallback {
@@ -277,11 +282,11 @@ private:
};
static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQWeak, jobject msgQ,
- jfloatArray scratch, jstring packageName) {
+ jfloatArray scratch, jstring packageName, jint mode) {
SensorManager& mgr(SensorManager::getInstance());
ScopedUtfChars packageUtf(env, packageName);
String8 clientName(packageUtf.c_str());
- sp<SensorEventQueue> queue(mgr.createEventQueue(clientName));
+ sp<SensorEventQueue> queue(mgr.createEventQueue(clientName, mode));
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
if (messageQueue == NULL) {
@@ -297,7 +302,6 @@ static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject event
static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
jint maxBatchReportLatency) {
sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
-
return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
0);
}
@@ -307,7 +311,7 @@ static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint ha
return receiver->getSensorEventQueue()->disableSensor(handle);
}
-static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
+static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ) {
sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
receiver->destroy();
receiver->decStrong((void*)nativeInitSensorEventQueue);
@@ -318,6 +322,17 @@ static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) {
return receiver->getSensorEventQueue()->flush();
}
+static jint nativeInjectSensorData(JNIEnv *env, jclass clazz, jlong eventQ, jint handle,
+ jfloatArray values, jint accuracy, jlong timestamp) {
+ sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
+ // Create a sensor_event from the above data which can be injected into the HAL.
+ ASensorEvent sensor_event;
+ memset(&sensor_event, 0, sizeof(sensor_event));
+ sensor_event.sensor = handle;
+ sensor_event.timestamp = timestamp;
+ env->GetFloatArrayRegion(values, 0, env->GetArrayLength(values), sensor_event.data);
+ return receiver->getSensorEventQueue()->injectSensorEvent(sensor_event);
+}
//----------------------------------------------------------------------------
static JNINativeMethod gSystemSensorManagerMethods[] = {
@@ -328,11 +343,15 @@ static JNINativeMethod gSystemSensorManagerMethods[] = {
{"nativeGetNextSensor",
"(Landroid/hardware/Sensor;I)I",
(void*)nativeGetNextSensor },
+
+ {"nativeEnableDataInjection",
+ "(Z)I",
+ (void*)nativeEnableDataInjection },
};
static JNINativeMethod gBaseEventQueueMethods[] = {
{"nativeInitBaseEventQueue",
- "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;)J",
+ "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;I)J",
(void*)nativeInitSensorEventQueue },
{"nativeEnableSensor",
@@ -350,6 +369,10 @@ static JNINativeMethod gBaseEventQueueMethods[] = {
{"nativeFlushSensor",
"(J)I",
(void*)nativeFlushSensor },
+
+ {"nativeInjectSensorData",
+ "(JI[FIJ)I",
+ (void*)nativeInjectSensorData },
};
}; // namespace android
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..6f1fd24 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);
}
//--------------
@@ -973,8 +926,7 @@ public class AudioTrack
return new PlaybackSettings()
.setSpeed(floatArray[0])
.setPitch(floatArray[1])
- .setAudioFallbackMode(intArray[0])
- .setAudioStretchMode(intArray[1]);
+ .setAudioFallbackMode(intArray[0]);
}
/**
@@ -1397,7 +1349,7 @@ public class AudioTrack
};
intArray = new int[] {
settings.getAudioFallbackMode(),
- settings.getAudioStretchMode(),
+ PlaybackSettings.AUDIO_STRETCH_MODE_DEFAULT,
};
} catch (IllegalStateException e) {
throw new IllegalArgumentException(e);
@@ -2362,7 +2314,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/PlaybackSettings.java b/media/java/android/media/PlaybackSettings.java
index ceb6bb1..b2e1033 100644
--- a/media/java/android/media/PlaybackSettings.java
+++ b/media/java/android/media/PlaybackSettings.java
@@ -38,14 +38,6 @@ import android.annotation.IntDef;
* Return {@link java.lang.IllegalArgumentException} from
* <code>AudioTrack.setPlaybackSettings(PlaybackSettings)</code>.</li>
* </ul>
- * <p> <strong>audio stretch mode:</strong> select
- * timestretch handling.
- * <ul>
- * <li> {@link PlaybackSettings#AUDIO_STRETCH_MODE_DEFAULT}:
- * System will determine best selection. </li>
- * <li> {@link PlaybackSettings#AUDIO_STRETCH_MODE_VOICE}:
- * Content is primarily voice.</li>
- * </ul>
* <p> <strong>pitch:</strong> increases or decreases the tonal frequency of the audio content.
* It is expressed as a multiplicative factor, where normal pitch is 1.0f.
* <p> <strong>speed:</strong> increases or decreases the time to
@@ -84,7 +76,9 @@ public final class PlaybackSettings {
)
@Retention(RetentionPolicy.SOURCE)
public @interface AudioStretchMode {}
+ /** @hide */
public static final int AUDIO_STRETCH_MODE_DEFAULT = 0;
+ /** @hide */
public static final int AUDIO_STRETCH_MODE_VOICE = 1;
// flags to indicate which settings are actually set
@@ -136,6 +130,7 @@ public final class PlaybackSettings {
}
/**
+ * @hide
* Sets the audio stretch mode.
* @param audioStretchMode
* @return this <code>PlaybackSettings</code> instance.
@@ -147,6 +142,7 @@ public final class PlaybackSettings {
}
/**
+ * @hide
* Retrieves the audio stretch mode.
* @return audio stretch mode
* @throws IllegalStateException if the audio stretch mode is not set.
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..7172ab7 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -30,6 +30,8 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.IPackageMoveObserver;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.ObbInfo;
import android.mtp.MtpStorage;
@@ -178,6 +180,9 @@ class MountService extends IMountService.Stub
/** Maximum number of ASEC containers allowed to be mounted. */
private static final int MAX_CONTAINERS = 250;
+ /** Magic value sent by MoveTask.cpp */
+ private static final int MOVE_STATUS_COPY_FINISHED = 82;
+
/*
* Internal vold response code constants
*/
@@ -226,6 +231,8 @@ class MountService extends IMountService.Stub
public static final int VOLUME_PATH_CHANGED = 655;
public static final int VOLUME_DESTROYED = 659;
+ public static final int MOVE_STATUS = 660;
+
/*
* 700 series - fstrim
*/
@@ -314,6 +321,11 @@ class MountService extends IMountService.Stub
@GuardedBy("mLock")
private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
+ @GuardedBy("mLock")
+ private IPackageMoveObserver mMoveCallback;
+ @GuardedBy("mLock")
+ private String mMoveTargetUuid;
+
private DiskInfo findDiskById(String id) {
synchronized (mLock) {
final DiskInfo disk = mDisks.get(id);
@@ -347,6 +359,17 @@ class MountService extends IMountService.Stub
throw new IllegalArgumentException("No volume found for path " + path);
}
+ private VolumeInfo findStorageForUuid(String volumeUuid) {
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
+ return findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
+ } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
+ return storage.getPrimaryPhysicalVolume();
+ } else {
+ return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
+ }
+ }
+
private VolumeMetadata findOrCreateMetadataLocked(VolumeInfo vol) {
VolumeMetadata meta = mMetadata.get(vol.fsUuid);
if (meta == null) {
@@ -937,6 +960,12 @@ class MountService extends IMountService.Stub
break;
}
+ case VoldResponseCode.MOVE_STATUS: {
+ final int status = Integer.parseInt(cooked[1]);
+ onMoveStatusLocked(status);
+ break;
+ }
+
case VoldResponseCode.FstrimCompleted: {
EventLogTags.writeFstrimFinish(SystemClock.elapsedRealtime());
break;
@@ -972,24 +1001,36 @@ class MountService extends IMountService.Stub
}
private void onVolumeCreatedLocked(VolumeInfo vol) {
- final boolean primaryPhysical = SystemProperties.getBoolean(
- StorageManager.PROP_PRIMARY_PHYSICAL, false);
- // TODO: enable switching to another emulated primary
- if (VolumeInfo.ID_EMULATED_INTERNAL.equals(vol.id) && !primaryPhysical) {
- vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
- vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
- mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
+ if (vol.type == VolumeInfo.TYPE_EMULATED) {
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
+
+ if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
+ && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
+ Slog.v(TAG, "Found primary storage at " + vol);
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
+
+ } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
+ Slog.v(TAG, "Found primary storage at " + vol);
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
+ }
} else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
- if (primaryPhysical) {
+ // TODO: only look at first public partition
+ if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
+ && vol.disk.isDefaultPrimary()) {
+ Slog.v(TAG, "Found primary storage at " + vol);
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
}
// Adoptable public disks are visible to apps, since they meet
// public API requirement of being in a stable location.
- final DiskInfo disk = mDisks.get(vol.getDiskId());
- if (disk != null && disk.isAdoptable()) {
+ if (vol.disk.isAdoptable()) {
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
}
@@ -1066,6 +1107,35 @@ class MountService extends IMountService.Stub
}
}
+ private void onMoveStatusLocked(int status) {
+ if (mMoveCallback == null) {
+ Slog.w(TAG, "Odd, status but no move requested");
+ return;
+ }
+
+ // TODO: estimate remaining time
+ try {
+ mMoveCallback.onStatusChanged(-1, status, -1);
+ } catch (RemoteException ignored) {
+ }
+
+ // We've finished copying and we're about to clean up old data, so
+ // remember that move was successful if we get rebooted
+ if (status == MOVE_STATUS_COPY_FINISHED) {
+ Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
+
+ mPrimaryStorageUuid = mMoveTargetUuid;
+ writeMetadataLocked();
+ }
+
+ if (PackageManager.isMoveStatusFinished(status)) {
+ Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
+
+ mMoveCallback = null;
+ mMoveTargetUuid = null;
+ }
+ }
+
/**
* Refresh latest metadata into any currently active {@link VolumeInfo}.
*/
@@ -1322,12 +1392,17 @@ class MountService extends IMountService.Stub
final VolumeInfo vol = findVolumeById(volId);
// TODO: expand PMS to know about multiple volumes
- if (vol.isPrimary()) {
- synchronized (mUnmountLock) {
- mUnmountSignal = new CountDownLatch(1);
- mPms.updateExternalMediaStatus(false, true);
- waitForLatch(mUnmountSignal, "mUnmountSignal");
- mUnmountSignal = null;
+ if (vol.isPrimaryPhysical()) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mUnmountLock) {
+ mUnmountSignal = new CountDownLatch(1);
+ mPms.updateExternalMediaStatus(false, true);
+ waitForLatch(mUnmountSignal, "mUnmountSignal");
+ mUnmountSignal = null;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -1424,20 +1499,41 @@ class MountService extends IMountService.Stub
}
@Override
- public String getPrimaryStorageUuid() throws RemoteException {
+ public String getPrimaryStorageUuid() {
+ enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+ waitForReady();
+
synchronized (mLock) {
return mPrimaryStorageUuid;
}
}
@Override
- public void setPrimaryStorageUuid(String volumeUuid) throws RemoteException {
+ public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
+ enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+ waitForReady();
+
synchronized (mLock) {
- Slog.d(TAG, "Changing primary storage UUID to " + volumeUuid);
- mPrimaryStorageUuid = volumeUuid;
- writeMetadataLocked();
+ final VolumeInfo from = Preconditions.checkNotNull(
+ findStorageForUuid(mPrimaryStorageUuid));
+ final VolumeInfo to = Preconditions.checkNotNull(
+ findStorageForUuid(volumeUuid));
+
+ if (Objects.equals(from, to)) {
+ throw new IllegalArgumentException("Primary storage already at " + from);
+ }
- // TODO: reevaluate all volumes we know about!
+ if (mMoveCallback != null) {
+ throw new IllegalStateException("Move already in progress");
+ }
+ mMoveCallback = callback;
+ mMoveTargetUuid = volumeUuid;
+
+ try {
+ mConnector.execute("volume", "move_storage", from.id, to.id);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
}
}
@@ -1758,6 +1854,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 +1890,7 @@ class MountService extends IMountService.Stub
warnOnNotMounted();
final ObbState state;
- synchronized (mObbPathToStateMap) {
+ synchronized (mObbMounts) {
state = mObbPathToStateMap.get(rawPath);
}
if (state == null) {
@@ -1843,7 +1942,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 +2192,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();
}
@@ -2870,6 +2971,9 @@ class MountService extends IMountService.Stub
meta.dump(pw);
}
pw.decreaseIndent();
+
+ pw.println();
+ pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
}
synchronized (mObbMounts) {
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/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bd22524..f087c33 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -14307,12 +14307,22 @@ public class PackageManagerService extends IPackageManager.Stub {
public int movePrimaryStorage(String volumeUuid) throws RemoteException {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
- final int moveId = mNextMoveId.getAndIncrement();
+ final int realMoveId = mNextMoveId.getAndIncrement();
+ final IPackageMoveObserver callback = new IPackageMoveObserver.Stub() {
+ @Override
+ public void onStarted(int moveId, String title) {
+ // Ignored
+ }
- // TODO: ask mountservice to take down both, connect over to DCS to
- // migrate, and then bring up new storage
+ @Override
+ public void onStatusChanged(int moveId, int status, long estMillis) {
+ mMoveCallbacks.notifyStatusChanged(realMoveId, status, estMillis);
+ }
+ };
- return moveId;
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ storage.setPrimaryStorageUuid(volumeUuid, callback);
+ return realMoveId;
}
@Override
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/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6fc3103..2b88158 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -771,8 +771,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
permittedInputMethods = readPackageList(parser, tag);
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
+ XmlUtils.skipCurrentTag(parser);
}
- XmlUtils.skipCurrentTag(parser);
}
}
@@ -1565,11 +1565,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} else if ("failed-password-attempts".equals(tag)) {
policy.mFailedPasswordAttempts = Integer.parseInt(
parser.getAttributeValue(null, "value"));
- XmlUtils.skipCurrentTag(parser);
} else if ("password-owner".equals(tag)) {
policy.mPasswordOwner = Integer.parseInt(
parser.getAttributeValue(null, "value"));
- XmlUtils.skipCurrentTag(parser);
} else if ("active-password".equals(tag)) {
policy.mActivePasswordQuality = Integer.parseInt(
parser.getAttributeValue(null, "quality"));
@@ -1587,14 +1585,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
parser.getAttributeValue(null, "symbols"));
policy.mActivePasswordNonLetter = Integer.parseInt(
parser.getAttributeValue(null, "nonletter"));
- XmlUtils.skipCurrentTag(parser);
} else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) {
policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name"));
- XmlUtils.skipCurrentTag(parser);
} else if (TAG_STATUS_BAR.equals(tag)) {
policy.mStatusBarEnabledState = Boolean.parseBoolean(
parser.getAttributeValue(null, ATTR_ENABLED));
- XmlUtils.skipCurrentTag(parser);
} else if (DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML.equals(tag)) {
policy.doNotAskCredentialsOnBoot = true;
} else {
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/aapt2/BinaryResourceParser.cpp b/tools/aapt2/BinaryResourceParser.cpp
index 71016c1..326a2ac 100644
--- a/tools/aapt2/BinaryResourceParser.cpp
+++ b/tools/aapt2/BinaryResourceParser.cpp
@@ -603,6 +603,13 @@ std::unique_ptr<Item> BinaryResourceParser::parseValue(const ResourceNameRef& na
mTable->getValueStringPool().makeRef(
styleStr, StringPool::Context{1, config}));
} else {
+ if (name.type != ResourceType::kString &&
+ util::stringStartsWith<char16_t>(str, u"res/")) {
+ // This must be a FileReference.
+ return util::make_unique<FileReference>(mTable->getValueStringPool().makeRef(
+ str, StringPool::Context{ 0, config }));
+ }
+
// There are no styles associated with this string, so treat it as
// a simple string.
return util::make_unique<String>(
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 03b9ba4..be806c9 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -25,6 +25,7 @@
#include "Linker.h"
#include "ManifestParser.h"
#include "ManifestValidator.h"
+#include "NameMangler.h"
#include "Png.h"
#include "ResourceParser.h"
#include "ResourceTable.h"
@@ -266,22 +267,50 @@ struct CompileItem {
struct LinkItem {
Source source;
- std::string apkPath;
+ ResourceName name;
+ ConfigDescription config;
+ std::string originalPath;
+ ZipFile* apk;
};
-std::string buildFileReference(const CompileItem& item) {
+template <typename TChar>
+static BasicStringPiece<TChar> getExtension(const BasicStringPiece<TChar>& str) {
+ auto iter = std::find(str.begin(), str.end(), static_cast<TChar>('.'));
+ if (iter == str.end()) {
+ return BasicStringPiece<TChar>();
+ }
+ size_t offset = (iter - str.begin()) + 1;
+ return str.substr(offset, str.size() - offset);
+}
+
+
+
+std::string buildFileReference(const ResourceNameRef& name, const ConfigDescription& config,
+ const StringPiece& extension) {
std::stringstream path;
- path << "res/" << item.name.type;
- if (item.config != ConfigDescription{}) {
- path << "-" << item.config;
+ path << "res/" << name.type;
+ if (config != ConfigDescription{}) {
+ path << "-" << config;
+ }
+ path << "/" << util::utf16ToUtf8(name.entry);
+ if (!extension.empty()) {
+ path << "." << extension;
}
- path << "/" << util::utf16ToUtf8(item.name.entry) + "." + item.extension;
return path.str();
}
+std::string buildFileReference(const CompileItem& item) {
+ return buildFileReference(item.name, item.config, item.extension);
+}
+
+std::string buildFileReference(const LinkItem& item) {
+ return buildFileReference(item.name, item.config, getExtension<char>(item.originalPath));
+}
+
bool addFileReference(const std::shared_ptr<ResourceTable>& table, const CompileItem& item) {
StringPool& pool = table->getValueStringPool();
- StringPool::Ref ref = pool.makeRef(util::utf8ToUtf16(buildFileReference(item)));
+ StringPool::Ref ref = pool.makeRef(util::utf8ToUtf16(buildFileReference(item)),
+ StringPool::Context{ 0, item.config });
return table->addResource(item.name, item.config, item.source.line(0),
util::make_unique<FileReference>(ref));
}
@@ -418,8 +447,8 @@ bool linkXml(const AaptOptions& options, const std::shared_ptr<Resolver>& resolv
return false;
}
- if (outApk->add(outBuffer, item.apkPath.data(), ZipEntry::kCompressDeflated, nullptr) !=
- android::NO_ERROR) {
+ if (outApk->add(outBuffer, buildFileReference(item).data(), ZipEntry::kCompressDeflated,
+ nullptr) != android::NO_ERROR) {
Logger::error(options.output) << "failed to write linked file '" << item.source
<< "' to apk." << std::endl;
return false;
@@ -502,109 +531,6 @@ bool compileManifest(const AaptOptions& options, const std::shared_ptr<Resolver>
return true;
}
-bool loadAppInfo(const Source& source, AppInfo* outInfo) {
- std::ifstream ifs(source.path, std::ifstream::in | std::ifstream::binary);
- if (!ifs) {
- Logger::error(source) << strerror(errno) << std::endl;
- return false;
- }
-
- ManifestParser parser;
- std::shared_ptr<XmlPullParser> pullParser = std::make_shared<SourceXmlPullParser>(ifs);
- return parser.parse(source, pullParser, outInfo);
-}
-
-static void printCommandsAndDie() {
- std::cerr << "The following commands are supported:" << std::endl << std::endl;
- std::cerr << "compile compiles a subset of resources" << std::endl;
- std::cerr << "link links together compiled resources and libraries" << std::endl;
- std::cerr << std::endl;
- std::cerr << "run aapt2 with one of the commands and the -h flag for extra details."
- << std::endl;
- exit(1);
-}
-
-static AaptOptions prepareArgs(int argc, char** argv) {
- if (argc < 2) {
- std::cerr << "no command specified." << std::endl << std::endl;
- printCommandsAndDie();
- }
-
- const StringPiece command(argv[1]);
- argc -= 2;
- argv += 2;
-
- AaptOptions options;
-
- if (command == "--version" || command == "version") {
- std::cout << kAaptVersionStr << std::endl;
- exit(0);
- } else if (command == "link") {
- options.phase = AaptOptions::Phase::Link;
- } else if (command == "compile") {
- options.phase = AaptOptions::Phase::Compile;
- } else {
- std::cerr << "invalid command '" << command << "'." << std::endl << std::endl;
- printCommandsAndDie();
- }
-
- if (options.phase == AaptOptions::Phase::Compile) {
- flag::requiredFlag("--package", "Android package name",
- [&options](const StringPiece& arg) {
- options.appInfo.package = util::utf8ToUtf16(arg);
- });
- flag::optionalFlag("--binding", "Output directory for binding XML files",
- [&options](const StringPiece& arg) {
- options.bindingOutput = Source{ arg.toString() };
- });
- flag::optionalSwitch("--no-version", "Disables automatic style and layout versioning",
- false, &options.versionStylesAndLayouts);
-
- } else if (options.phase == AaptOptions::Phase::Link) {
- flag::requiredFlag("--manifest", "AndroidManifest.xml of your app",
- [&options](const StringPiece& arg) {
- options.manifest = Source{ arg.toString() };
- });
-
- flag::optionalFlag("-I", "add an Android APK to link against",
- [&options](const StringPiece& arg) {
- options.libraries.push_back(Source{ arg.toString() });
- });
-
- flag::optionalFlag("--java", "directory in which to generate R.java",
- [&options](const StringPiece& arg) {
- options.generateJavaClass = Source{ arg.toString() };
- });
- }
-
- // Common flags for all steps.
- flag::requiredFlag("-o", "Output path", [&options](const StringPiece& arg) {
- options.output = Source{ arg.toString() };
- });
-
- bool help = false;
- flag::optionalSwitch("-v", "enables verbose logging", true, &options.verbose);
- flag::optionalSwitch("-h", "displays this help menu", true, &help);
-
- // Build the command string for output (eg. "aapt2 compile").
- std::string fullCommand = "aapt2";
- fullCommand += " ";
- fullCommand += command.toString();
-
- // Actually read the command line flags.
- flag::parse(argc, argv, fullCommand);
-
- if (help) {
- flag::usageAndDie(fullCommand);
- }
-
- // Copy all the remaining arguments.
- for (const std::string& arg : flag::getArgs()) {
- options.input.push_back(Source{ arg });
- }
- return options;
-}
-
static bool compileValues(const std::shared_ptr<ResourceTable>& table, const Source& source,
const ConfigDescription& config) {
std::ifstream in(source.path, std::ifstream::binary);
@@ -630,6 +556,7 @@ struct ResourcePathData {
* [--/res/]type[-config]/name
*/
static Maybe<ResourcePathData> extractResourcePathData(const Source& source) {
+ // TODO(adamlesinski): Use Windows path separator on windows.
std::vector<std::string> parts = util::splitAndLowercase(source.path, '/');
if (parts.size() < 2) {
Logger::error(source) << "bad resource path." << std::endl;
@@ -695,6 +622,38 @@ bool writeResourceTable(const AaptOptions& options, const std::shared_ptr<Resour
return true;
}
+/**
+ * For each FileReference in the table, adds a LinkItem to the link queue for processing.
+ */
+static void addApkFilesToLinkQueue(const std::u16string& package, const Source& source,
+ const std::shared_ptr<ResourceTable>& table,
+ const std::unique_ptr<ZipFile>& apk,
+ std::queue<LinkItem>* outLinkQueue) {
+ bool mangle = package != table->getPackage();
+ for (auto& type : *table) {
+ for (auto& entry : type->entries) {
+ ResourceName name = { package, type->type, entry->name };
+ if (mangle) {
+ NameMangler::mangle(table->getPackage(), &name.entry);
+ }
+
+ for (auto& value : entry->values) {
+ visitFunc<FileReference>(*value.value, [&](FileReference& ref) {
+ std::string pathUtf8 = util::utf16ToUtf8(*ref.path);
+ outLinkQueue->push(LinkItem{
+ source, name, value.config, pathUtf8, apk.get() });
+ // Now rewrite the file path.
+ if (mangle) {
+ ref.path = table->getValueStringPool().makeRef(util::utf8ToUtf16(
+ buildFileReference(name, value.config,
+ getExtension<char>(pathUtf8))));
+ }
+ });
+ }
+ }
+ }
+}
+
static constexpr int kOpenFlags = ZipFile::kOpenCreate | ZipFile::kOpenTruncate |
ZipFile::kOpenReadWrite;
@@ -740,9 +699,14 @@ bool link(const AaptOptions& options, const std::shared_ptr<ResourceTable>& outT
linkedPackages.insert(table->getPackage());
}
+ std::queue<LinkItem> linkQueue;
for (auto& p : apkFiles) {
const std::shared_ptr<ResourceTable>& inTable = p.first;
+ // Collect all FileReferences and add them to the queue for processing.
+ addApkFilesToLinkQueue(options.appInfo.package, Source{}, inTable, p.second, &linkQueue);
+
+ // Merge the tables.
if (!outTable->merge(std::move(*inTable))) {
return false;
}
@@ -779,39 +743,32 @@ bool link(const AaptOptions& options, const std::shared_ptr<ResourceTable>& outT
return false;
}
- for (auto& p : apkFiles) {
- std::unique_ptr<ZipFile>& zipFile = p.second;
+ for (; !linkQueue.empty(); linkQueue.pop()) {
+ const LinkItem& item = linkQueue.front();
- // TODO(adamlesinski): Get list of files to read when processing config filter.
+ ZipEntry* entry = item.apk->getEntryByName(item.originalPath.data());
+ if (!entry) {
+ Logger::error(item.source) << "failed to find '" << item.originalPath << "'."
+ << std::endl;
+ return false;
+ }
- const int numEntries = zipFile->getNumEntries();
- for (int i = 0; i < numEntries; i++) {
- ZipEntry* entry = zipFile->getEntryByIndex(i);
- assert(entry);
+ if (util::stringEndsWith<char>(item.originalPath, ".xml")) {
+ void* uncompressedData = item.apk->uncompress(entry);
+ assert(uncompressedData);
- StringPiece filename = entry->getFileName();
- if (!util::stringStartsWith<char>(filename, "res/")) {
- continue;
+ if (!linkXml(options, resolver, item, uncompressedData, entry->getUncompressedLen(),
+ &outApk)) {
+ Logger::error(options.output) << "failed to link '" << item.originalPath << "'."
+ << std::endl;
+ return false;
}
-
- if (util::stringEndsWith<char>(filename, ".xml")) {
- void* uncompressedData = zipFile->uncompress(entry);
- assert(uncompressedData);
-
- LinkItem item = { Source{ filename.toString() }, filename.toString() };
-
- if (!linkXml(options, resolver, item, uncompressedData,
- entry->getUncompressedLen(), &outApk)) {
- Logger::error(options.output) << "failed to link '" << filename << "'."
- << std::endl;
- return false;
- }
- } else {
- if (outApk.add(zipFile.get(), entry, 0, nullptr) != android::NO_ERROR) {
- Logger::error(options.output) << "failed to copy '" << filename << "'."
- << std::endl;
- return false;
- }
+ } else {
+ if (outApk.add(item.apk, entry, buildFileReference(item).data(), 0, nullptr) !=
+ android::NO_ERROR) {
+ Logger::error(options.output) << "failed to copy '" << item.originalPath << "'."
+ << std::endl;
+ return false;
}
}
}
@@ -957,6 +914,109 @@ bool compile(const AaptOptions& options, const std::shared_ptr<ResourceTable>& t
return true;
}
+bool loadAppInfo(const Source& source, AppInfo* outInfo) {
+ std::ifstream ifs(source.path, std::ifstream::in | std::ifstream::binary);
+ if (!ifs) {
+ Logger::error(source) << strerror(errno) << std::endl;
+ return false;
+ }
+
+ ManifestParser parser;
+ std::shared_ptr<XmlPullParser> pullParser = std::make_shared<SourceXmlPullParser>(ifs);
+ return parser.parse(source, pullParser, outInfo);
+}
+
+static void printCommandsAndDie() {
+ std::cerr << "The following commands are supported:" << std::endl << std::endl;
+ std::cerr << "compile compiles a subset of resources" << std::endl;
+ std::cerr << "link links together compiled resources and libraries" << std::endl;
+ std::cerr << std::endl;
+ std::cerr << "run aapt2 with one of the commands and the -h flag for extra details."
+ << std::endl;
+ exit(1);
+}
+
+static AaptOptions prepareArgs(int argc, char** argv) {
+ if (argc < 2) {
+ std::cerr << "no command specified." << std::endl << std::endl;
+ printCommandsAndDie();
+ }
+
+ const StringPiece command(argv[1]);
+ argc -= 2;
+ argv += 2;
+
+ AaptOptions options;
+
+ if (command == "--version" || command == "version") {
+ std::cout << kAaptVersionStr << std::endl;
+ exit(0);
+ } else if (command == "link") {
+ options.phase = AaptOptions::Phase::Link;
+ } else if (command == "compile") {
+ options.phase = AaptOptions::Phase::Compile;
+ } else {
+ std::cerr << "invalid command '" << command << "'." << std::endl << std::endl;
+ printCommandsAndDie();
+ }
+
+ if (options.phase == AaptOptions::Phase::Compile) {
+ flag::requiredFlag("--package", "Android package name",
+ [&options](const StringPiece& arg) {
+ options.appInfo.package = util::utf8ToUtf16(arg);
+ });
+ flag::optionalFlag("--binding", "Output directory for binding XML files",
+ [&options](const StringPiece& arg) {
+ options.bindingOutput = Source{ arg.toString() };
+ });
+ flag::optionalSwitch("--no-version", "Disables automatic style and layout versioning",
+ false, &options.versionStylesAndLayouts);
+
+ } else if (options.phase == AaptOptions::Phase::Link) {
+ flag::requiredFlag("--manifest", "AndroidManifest.xml of your app",
+ [&options](const StringPiece& arg) {
+ options.manifest = Source{ arg.toString() };
+ });
+
+ flag::optionalFlag("-I", "add an Android APK to link against",
+ [&options](const StringPiece& arg) {
+ options.libraries.push_back(Source{ arg.toString() });
+ });
+
+ flag::optionalFlag("--java", "directory in which to generate R.java",
+ [&options](const StringPiece& arg) {
+ options.generateJavaClass = Source{ arg.toString() };
+ });
+ }
+
+ // Common flags for all steps.
+ flag::requiredFlag("-o", "Output path", [&options](const StringPiece& arg) {
+ options.output = Source{ arg.toString() };
+ });
+
+ bool help = false;
+ flag::optionalSwitch("-v", "enables verbose logging", true, &options.verbose);
+ flag::optionalSwitch("-h", "displays this help menu", true, &help);
+
+ // Build the command string for output (eg. "aapt2 compile").
+ std::string fullCommand = "aapt2";
+ fullCommand += " ";
+ fullCommand += command.toString();
+
+ // Actually read the command line flags.
+ flag::parse(argc, argv, fullCommand);
+
+ if (help) {
+ flag::usageAndDie(fullCommand);
+ }
+
+ // Copy all the remaining arguments.
+ for (const std::string& arg : flag::getArgs()) {
+ options.input.push_back(Source{ arg });
+ }
+ return options;
+}
+
int main(int argc, char** argv) {
Logger::setLog(std::make_shared<Log>(std::cerr, std::cerr));
AaptOptions options = prepareArgs(argc, argv);
diff --git a/tools/aapt2/TableFlattener.cpp b/tools/aapt2/TableFlattener.cpp
index 67c56e7..4aadadc 100644
--- a/tools/aapt2/TableFlattener.cpp
+++ b/tools/aapt2/TableFlattener.cpp
@@ -43,8 +43,7 @@ struct FlatEntry {
*/
class MapFlattener : public ConstValueVisitor {
public:
- MapFlattener(BigBuffer* out, const FlatEntry& flatEntry,
- std::vector<std::pair<ResourceNameRef, uint32_t>>& symbols) :
+ MapFlattener(BigBuffer* out, const FlatEntry& flatEntry, SymbolEntryVector* symbols) :
mOut(out), mSymbols(symbols) {
mMap = mOut->nextBlock<android::ResTable_map_entry>();
mMap->key.index = flatEntry.entryKey;
@@ -65,7 +64,7 @@ public:
void flattenParent(const Reference& ref) {
if (!ref.id.isValid()) {
- mSymbols.push_back({
+ mSymbols->push_back({
ResourceNameRef(ref.name),
(mOut->size() - mMap->size) + sizeof(*mMap) - sizeof(android::ResTable_entry)
});
@@ -80,7 +79,7 @@ public:
// Write the key.
if (!Res_INTERNALID(key.id.id) && !key.id.isValid()) {
- mSymbols.push_back(std::make_pair(ResourceNameRef(key.name),
+ mSymbols->push_back(std::make_pair(ResourceNameRef(key.name),
mOut->size() - sizeof(*outMapEntry)));
}
outMapEntry->name.ident = key.id.id;
@@ -90,7 +89,7 @@ public:
if (outMapEntry->value.data == 0x0) {
visitFunc<Reference>(value, [&](const Reference& reference) {
- mSymbols.push_back(std::make_pair(ResourceNameRef(reference.name),
+ mSymbols->push_back(std::make_pair(ResourceNameRef(reference.name),
mOut->size() - sizeof(outMapEntry->value.data)));
});
}
@@ -188,16 +187,47 @@ public:
private:
BigBuffer* mOut;
- std::vector<std::pair<ResourceNameRef, uint32_t>>& mSymbols;
+ SymbolEntryVector* mSymbols;
android::ResTable_map_entry* mMap;
};
+/**
+ * Flattens a value, with special handling for References.
+ */
+struct ValueFlattener : ConstValueVisitor {
+ ValueFlattener(BigBuffer* out, SymbolEntryVector* symbols) :
+ result(false), mOut(out), mOutValue(nullptr), mSymbols(symbols) {
+ mOutValue = mOut->nextBlock<android::Res_value>();
+ }
+
+ virtual void visit(const Reference& ref, ValueVisitorArgs& a) override {
+ visitItem(ref, a);
+ if (mOutValue->data == 0x0) {
+ mSymbols->push_back({
+ ResourceNameRef(ref.name),
+ mOut->size() - sizeof(mOutValue->data)});
+ }
+ }
+
+ virtual void visitItem(const Item& item, ValueVisitorArgs&) override {
+ result = item.flatten(*mOutValue);
+ mOutValue->size = sizeof(*mOutValue);
+ }
+
+ bool result;
+
+private:
+ BigBuffer* mOut;
+ android::Res_value* mOutValue;
+ SymbolEntryVector* mSymbols;
+};
+
TableFlattener::TableFlattener(Options options)
: mOptions(options) {
}
bool TableFlattener::flattenValue(BigBuffer* out, const FlatEntry& flatEntry,
- std::vector<std::pair<ResourceNameRef, uint32_t>>& symbolEntries) {
+ SymbolEntryVector* symbols) {
if (flatEntry.value.isItem()) {
android::ResTable_entry* entry = out->nextBlock<android::ResTable_entry>();
@@ -218,30 +248,16 @@ bool TableFlattener::flattenValue(BigBuffer* out, const FlatEntry& flatEntry,
ResTable_entry_source* sourceBlock = out->nextBlock<ResTable_entry_source>();
sourceBlock->pathIndex = flatEntry.sourcePathKey;
sourceBlock->line = flatEntry.sourceLine;
-
entry->size += sizeof(*sourceBlock);
}
- android::Res_value* outValue = out->nextBlock<android::Res_value>();
-
- const Item& item = static_cast<const Item&>(flatEntry.value);
- if (!item.flatten(*outValue)) {
- return false;
- }
-
- if (outValue->data == 0x0) {
- visitFunc<Reference>(item, [&](const Reference& reference) {
- symbolEntries.push_back({
- ResourceNameRef(reference.name),
- out->size() - sizeof(outValue->data)
- });
- });
- }
- outValue->size = sizeof(*outValue);
- return true;
+ const Item* item = static_cast<const Item*>(&flatEntry.value);
+ ValueFlattener flattener(out, symbols);
+ item->accept(flattener, {});
+ return flattener.result;
}
- MapFlattener flattener(out, flatEntry, symbolEntries);
+ MapFlattener flattener(out, flatEntry, symbols);
flatEntry.value.accept(flattener, {});
return true;
}
@@ -263,7 +279,7 @@ bool TableFlattener::flatten(BigBuffer* out, const ResourceTable& table) {
return false;
}
- std::vector<std::pair<ResourceNameRef, uint32_t>> symbolEntries;
+ SymbolEntryVector symbolEntries;
StringPool typePool;
StringPool keyPool;
@@ -401,7 +417,7 @@ bool TableFlattener::flatten(BigBuffer* out, const ResourceTable& table) {
for (const FlatEntry& flatEntry : entry.second) {
assert(flatEntry.entry.entryId < type->entries.size());
indices[flatEntry.entry.entryId] = typeBlock.size() - entryStart;
- if (!flattenValue(&typeBlock, flatEntry, symbolEntries)) {
+ if (!flattenValue(&typeBlock, flatEntry, &symbolEntries)) {
Logger::error()
<< "failed to flatten resource '"
<< ResourceNameRef {
diff --git a/tools/aapt2/TableFlattener.h b/tools/aapt2/TableFlattener.h
index 0ae798c..ccbb737 100644
--- a/tools/aapt2/TableFlattener.h
+++ b/tools/aapt2/TableFlattener.h
@@ -22,6 +22,8 @@
namespace aapt {
+using SymbolEntryVector = std::vector<std::pair<ResourceNameRef, uint32_t>>;
+
struct FlatEntry;
/**
@@ -49,8 +51,7 @@ struct TableFlattener {
bool flatten(BigBuffer* out, const ResourceTable& table);
private:
- bool flattenValue(BigBuffer* out, const FlatEntry& flatEntry,
- std::vector<std::pair<ResourceNameRef, uint32_t>>& symbolEntries);
+ bool flattenValue(BigBuffer* out, const FlatEntry& flatEntry, SymbolEntryVector* symbols);
Options mOptions;
};
diff --git a/tools/aapt2/ZipEntry.cpp b/tools/aapt2/ZipEntry.cpp
index ad5d84a..891b4e1 100644
--- a/tools/aapt2/ZipEntry.cpp
+++ b/tools/aapt2/ZipEntry.cpp
@@ -144,9 +144,15 @@ void ZipEntry::initNew(const char* fileName, const char* comment)
* Initializes the CDE and the LFH.
*/
status_t ZipEntry::initFromExternal(const ZipFile* /* pZipFile */,
- const ZipEntry* pEntry)
+ const ZipEntry* pEntry, const char* storageName)
{
mCDE = pEntry->mCDE;
+ if (storageName && *storageName != 0) {
+ mCDE.mFileNameLength = strlen(storageName);
+ mCDE.mFileName = new unsigned char[mCDE.mFileNameLength + 1];
+ strcpy((char*) mCDE.mFileName, storageName);
+ }
+
// Check whether we got all the memory needed.
if ((mCDE.mFileNameLength > 0 && mCDE.mFileName == NULL) ||
(mCDE.mFileCommentLength > 0 && mCDE.mFileComment == NULL) ||
diff --git a/tools/aapt2/ZipEntry.h b/tools/aapt2/ZipEntry.h
index d048a3e..2745a43 100644
--- a/tools/aapt2/ZipEntry.h
+++ b/tools/aapt2/ZipEntry.h
@@ -171,9 +171,10 @@ protected:
/*
* Initialize the structure with the contents of a ZipEntry from
- * another file.
+ * another file. If fileName is non-NULL, override the name with fileName.
*/
- status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
+ status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry,
+ const char* fileName);
/*
* Add some pad bytes to the LFH. We do this by adding or resizing
diff --git a/tools/aapt2/ZipFile.cpp b/tools/aapt2/ZipFile.cpp
index 41e59cf..268c15e 100644
--- a/tools/aapt2/ZipFile.cpp
+++ b/tools/aapt2/ZipFile.cpp
@@ -546,7 +546,7 @@ bail:
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
*/
status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
- int padding, ZipEntry** ppEntry)
+ const char* storageName, int padding, ZipEntry** ppEntry)
{
ZipEntry* pEntry = NULL;
status_t result;
@@ -570,9 +570,10 @@ status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
goto bail;
}
- result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
- if (result != NO_ERROR)
+ result = pEntry->initFromExternal(pSourceZip, pSourceEntry, storageName);
+ if (result != NO_ERROR) {
goto bail;
+ }
if (padding != 0) {
result = pEntry->addPadding(padding);
if (result != NO_ERROR)
diff --git a/tools/aapt2/ZipFile.h b/tools/aapt2/ZipFile.h
index 9cbd1fa..9de92dd 100644
--- a/tools/aapt2/ZipFile.h
+++ b/tools/aapt2/ZipFile.h
@@ -123,14 +123,16 @@ public:
int compressionMethod, ZipEntry** ppEntry);
/*
- * Add an entry by copying it from another zip file. If "padding" is
+ * Add an entry by copying it from another zip file. If storageName is
+ * non-NULL, the entry will be inserted with the name storageName, otherwise
+ * it will have the same name as the source entry. If "padding" is
* nonzero, the specified number of bytes will be added to the "extra"
* field in the header.
*
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
*/
status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
- int padding, ZipEntry** ppEntry);
+ const char* storageName, int padding, ZipEntry** ppEntry);
/*
* Mark an entry as having been removed. It is not actually deleted
diff --git a/tools/aapt2/data/Makefile b/tools/aapt2/data/Makefile
index 5a2a1d1..6b5fafa 100644
--- a/tools/aapt2/data/Makefile
+++ b/tools/aapt2/data/Makefile
@@ -2,10 +2,8 @@
# Environment dependent variables
##
-SHELL := /bin/bash
AAPT := aapt2
-ZIP := zip -n .arsc:.png:AndroidManifest.xml
-ZIPALIGN := zipalign 4
+ZIPALIGN := zipalign -f 4
FRAMEWORK := ../../../../../out/target/common/obj/APPS/framework-res_intermediates/package-export.apk
##
diff --git a/tools/aapt2/data/lib/Makefile b/tools/aapt2/data/lib/Makefile
index 2897ff1..8f56c54 100644
--- a/tools/aapt2/data/lib/Makefile
+++ b/tools/aapt2/data/lib/Makefile
@@ -3,7 +3,7 @@
##
AAPT := aapt2
-ZIPALIGN := zipalign 4
+ZIPALIGN := zipalign -f 4
FRAMEWORK := ../../../../../../out/target/common/obj/APPS/framework-res_intermediates/package-export.apk
##
diff --git a/tools/aapt2/data/lib/res/layout/main.xml b/tools/aapt2/data/lib/res/layout/main.xml
new file mode 100644
index 0000000..187ed2d
--- /dev/null
+++ b/tools/aapt2/data/lib/res/layout/main.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
diff --git a/tools/aapt2/data/lib/res/raw/hello.txt b/tools/aapt2/data/lib/res/raw/hello.txt
new file mode 100644
index 0000000..44fc22b
--- /dev/null
+++ b/tools/aapt2/data/lib/res/raw/hello.txt
@@ -0,0 +1 @@
+Oh howdy there
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>