Merge "Call webview updating logic with the system UID when setup done." into nyc-dev
diff --git a/Android.mk b/Android.mk
index 97dfc1d..683cdf8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -194,6 +194,8 @@
core/java/android/hardware/usb/IUsbManager.aidl \
core/java/android/net/ICaptivePortal.aidl \
core/java/android/net/IConnectivityManager.aidl \
+ core/java/android/net/IConnectivityMetricsLogger.aidl \
+ core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl \
core/java/android/net/IEthernetManager.aidl \
core/java/android/net/IEthernetServiceListener.aidl \
core/java/android/net/INetworkManagementEventObserver.aidl \
diff --git a/api/current.txt b/api/current.txt
index cc0ca64..1eb35b6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5830,9 +5830,7 @@
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public void clearProfileOwner(android.content.ComponentName);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
- method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
- method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public void enableSystemApp(android.content.ComponentName, java.lang.String);
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
@@ -9786,6 +9784,8 @@
field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
+ field public static final java.lang.String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
+ field public static final java.lang.String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
@@ -11947,6 +11947,8 @@
ctor public Outline(android.graphics.Outline);
method public boolean canClip();
method public float getAlpha();
+ method public float getRadius();
+ method public boolean getRect(android.graphics.Rect);
method public boolean isEmpty();
method public void offset(int, int);
method public void set(android.graphics.Outline);
@@ -12974,12 +12976,10 @@
ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
method public void draw(android.graphics.Canvas);
- method public android.graphics.NinePatch getNinePatch();
method public int getOpacity();
method public android.graphics.Paint getPaint();
method public void setAlpha(int);
method public void setColorFilter(android.graphics.ColorFilter);
- method public void setNinePatch(android.graphics.NinePatch);
method public void setTargetDensity(android.graphics.Canvas);
method public void setTargetDensity(android.util.DisplayMetrics);
method public void setTargetDensity(int);
@@ -19693,6 +19693,7 @@
field public static final int TYPE_BUILTIN_EARPIECE = 1; // 0x1
field public static final int TYPE_BUILTIN_MIC = 15; // 0xf
field public static final int TYPE_BUILTIN_SPEAKER = 2; // 0x2
+ field public static final int TYPE_BUS = 21; // 0x15
field public static final int TYPE_DOCK = 13; // 0xd
field public static final int TYPE_FM = 14; // 0xe
field public static final int TYPE_FM_TUNER = 16; // 0x10
@@ -19710,12 +19711,14 @@
field public static final int TYPE_WIRED_HEADSET = 3; // 0x3
}
- public class AudioFormat {
+ public class AudioFormat implements android.os.Parcelable {
+ method public int describeContents();
method public int getChannelCount();
method public int getChannelIndexMask();
method public int getChannelMask();
method public int getEncoding();
method public int getSampleRate();
+ method public void writeToParcel(android.os.Parcel, int);
field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
field public static final deprecated int CHANNEL_CONFIGURATION_INVALID = 0; // 0x0
field public static final deprecated int CHANNEL_CONFIGURATION_MONO = 2; // 0x2
@@ -19757,6 +19760,7 @@
field public static final int CHANNEL_OUT_SIDE_RIGHT = 4096; // 0x1000
field public static final int CHANNEL_OUT_STEREO = 12; // 0xc
field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c
+ field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
field public static final int ENCODING_AC3 = 5; // 0x5
field public static final int ENCODING_DEFAULT = 1; // 0x1
field public static final int ENCODING_DTS = 7; // 0x7
@@ -21188,6 +21192,7 @@
method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
+ method public void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -22752,8 +22757,11 @@
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final boolean isChannelUri(android.net.Uri);
+ method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
+ method public static final boolean isChannelUriForTunerInput(android.net.Uri);
+ method public static final boolean isProgramUri(android.net.Uri);
field public static final java.lang.String AUTHORITY = "android.media.tv";
- field public static final java.lang.String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS";
}
public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
@@ -22844,7 +22852,8 @@
field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+ field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+ field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
@@ -22854,7 +22863,9 @@
field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
- field public static final java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+ field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+ field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
@@ -22897,7 +22908,7 @@
field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+ field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
@@ -22912,7 +22923,8 @@
field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
- field public static final java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+ field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
@@ -23502,6 +23514,17 @@
method public abstract void onNetworkActive();
}
+ public class ConnectivityMetricsEvent implements android.os.Parcelable {
+ ctor public ConnectivityMetricsEvent(long, int, int, android.os.Parcelable);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent> CREATOR;
+ field public final int componentTag;
+ field public final android.os.Parcelable data;
+ field public final int eventTag;
+ field public final long timestamp;
+ }
+
public class Credentials {
ctor public Credentials(int, int, int);
method public int getGid();
@@ -34112,6 +34135,7 @@
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isDigestsSpecified();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
@@ -34129,6 +34153,7 @@
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
@@ -34155,6 +34180,7 @@
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isInsideSecureHardware();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
method public boolean isUserAuthenticationValidWhileOnBody();
@@ -34218,6 +34244,7 @@
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isDigestsSpecified();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
@@ -34229,6 +34256,7 @@
method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
+ method public android.security.keystore.KeyProtection.Builder setInvalidatedByBiometricEnrollment(boolean);
method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
diff --git a/api/removed.txt b/api/removed.txt
index 0bf6594..50a24f6 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -9,6 +9,8 @@
package android.app.admin {
public class DevicePolicyManager {
+ method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
+ method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public deprecated java.lang.String getDeviceInitializerApp();
method public deprecated android.content.ComponentName getDeviceInitializerComponent();
}
@@ -35,7 +37,7 @@
package android.media {
- public class AudioFormat {
+ public class AudioFormat implements android.os.Parcelable {
ctor public AudioFormat();
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 058fc78..cfd3dd8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5967,9 +5967,7 @@
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public void clearProfileOwner(android.content.ComponentName);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
- method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
- method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public void enableSystemApp(android.content.ComponentName, java.lang.String);
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
@@ -6026,6 +6024,7 @@
method public int getStorageEncryptionStatus();
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
+ method public int getUserProvisioningState();
method public android.os.Bundle getUserRestrictions(android.content.ComponentName);
method public java.lang.String getWifiMacAddress();
method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
@@ -6112,6 +6111,7 @@
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
+ field public static final java.lang.String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION";
field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE";
field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE = "android.app.action.PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE";
field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
@@ -6181,6 +6181,11 @@
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
+ field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4
+ field public static final int STATE_USER_SETUP_COMPLETE = 2; // 0x2
+ field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3
+ field public static final int STATE_USER_SETUP_INCOMPLETE = 1; // 0x1
+ field public static final int STATE_USER_UNMANAGED = 0; // 0x0
field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
}
@@ -10144,6 +10149,8 @@
field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
+ field public static final java.lang.String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
+ field public static final java.lang.String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
@@ -12350,6 +12357,8 @@
ctor public Outline(android.graphics.Outline);
method public boolean canClip();
method public float getAlpha();
+ method public float getRadius();
+ method public boolean getRect(android.graphics.Rect);
method public boolean isEmpty();
method public void offset(int, int);
method public void set(android.graphics.Outline);
@@ -13377,12 +13386,10 @@
ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
method public void draw(android.graphics.Canvas);
- method public android.graphics.NinePatch getNinePatch();
method public int getOpacity();
method public android.graphics.Paint getPaint();
method public void setAlpha(int);
method public void setColorFilter(android.graphics.ColorFilter);
- method public void setNinePatch(android.graphics.NinePatch);
method public void setTargetDensity(android.graphics.Canvas);
method public void setTargetDensity(android.util.DisplayMetrics);
method public void setTargetDensity(int);
@@ -21170,6 +21177,7 @@
field public static final int TYPE_BUILTIN_EARPIECE = 1; // 0x1
field public static final int TYPE_BUILTIN_MIC = 15; // 0xf
field public static final int TYPE_BUILTIN_SPEAKER = 2; // 0x2
+ field public static final int TYPE_BUS = 21; // 0x15
field public static final int TYPE_DOCK = 13; // 0xd
field public static final int TYPE_FM = 14; // 0xe
field public static final int TYPE_FM_TUNER = 16; // 0x10
@@ -21199,12 +21207,14 @@
field public static final android.os.Parcelable.Creator<android.media.AudioFocusInfo> CREATOR;
}
- public class AudioFormat {
+ public class AudioFormat implements android.os.Parcelable {
+ method public int describeContents();
method public int getChannelCount();
method public int getChannelIndexMask();
method public int getChannelMask();
method public int getEncoding();
method public int getSampleRate();
+ method public void writeToParcel(android.os.Parcel, int);
field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
field public static final deprecated int CHANNEL_CONFIGURATION_INVALID = 0; // 0x0
field public static final deprecated int CHANNEL_CONFIGURATION_MONO = 2; // 0x2
@@ -21246,6 +21256,7 @@
field public static final int CHANNEL_OUT_SIDE_RIGHT = 4096; // 0x1000
field public static final int CHANNEL_OUT_STEREO = 12; // 0xc
field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c
+ field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
field public static final int ENCODING_AC3 = 5; // 0x5
field public static final int ENCODING_DEFAULT = 1; // 0x1
field public static final int ENCODING_DTS = 7; // 0x7
@@ -22689,6 +22700,7 @@
method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
+ method public void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -24375,9 +24387,11 @@
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final boolean isChannelUri(android.net.Uri);
method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
+ method public static final boolean isChannelUriForTunerInput(android.net.Uri);
+ method public static final boolean isProgramUri(android.net.Uri);
field public static final java.lang.String AUTHORITY = "android.media.tv";
- field public static final java.lang.String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS";
}
public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
@@ -24470,7 +24484,8 @@
field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+ field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+ field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
@@ -24480,7 +24495,9 @@
field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
- field public static final java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+ field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+ field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
@@ -24523,7 +24540,7 @@
field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+ field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
@@ -24538,7 +24555,8 @@
field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
- field public static final java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+ field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
@@ -25315,6 +25333,17 @@
method public void onTetheringStarted();
}
+ public class ConnectivityMetricsEvent implements android.os.Parcelable {
+ ctor public ConnectivityMetricsEvent(long, int, int, android.os.Parcelable);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent> CREATOR;
+ field public final int componentTag;
+ field public final android.os.Parcelable data;
+ field public final int eventTag;
+ field public final long timestamp;
+ }
+
public class Credentials {
ctor public Credentials(int, int, int);
method public int getGid();
@@ -36611,6 +36640,7 @@
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isDigestsSpecified();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
@@ -36628,6 +36658,7 @@
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
@@ -36654,6 +36685,7 @@
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isInsideSecureHardware();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
method public boolean isUserAuthenticationValidWhileOnBody();
@@ -36717,6 +36749,7 @@
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isDigestsSpecified();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
@@ -36728,6 +36761,7 @@
method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
+ method public android.security.keystore.KeyProtection.Builder setInvalidatedByBiometricEnrollment(boolean);
method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 27de913..7347aa3 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -6,6 +6,15 @@
}
+package android.app.admin {
+
+ public class DevicePolicyManager {
+ method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
+ method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
+ }
+
+}
+
package android.content.pm {
public class PackageInfo implements android.os.Parcelable {
@@ -26,7 +35,7 @@
package android.media {
- public class AudioFormat {
+ public class AudioFormat implements android.os.Parcelable {
ctor public AudioFormat();
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 7a78806..64854a8 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5832,9 +5832,7 @@
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public void clearProfileOwner(android.content.ComponentName);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
- method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
- method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public void enableSystemApp(android.content.ComponentName, java.lang.String);
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
@@ -9794,6 +9792,8 @@
field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
+ field public static final java.lang.String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
+ field public static final java.lang.String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
@@ -11955,6 +11955,8 @@
ctor public Outline(android.graphics.Outline);
method public boolean canClip();
method public float getAlpha();
+ method public float getRadius();
+ method public boolean getRect(android.graphics.Rect);
method public boolean isEmpty();
method public void offset(int, int);
method public void set(android.graphics.Outline);
@@ -12982,12 +12984,10 @@
ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
method public void draw(android.graphics.Canvas);
- method public android.graphics.NinePatch getNinePatch();
method public int getOpacity();
method public android.graphics.Paint getPaint();
method public void setAlpha(int);
method public void setColorFilter(android.graphics.ColorFilter);
- method public void setNinePatch(android.graphics.NinePatch);
method public void setTargetDensity(android.graphics.Canvas);
method public void setTargetDensity(android.util.DisplayMetrics);
method public void setTargetDensity(int);
@@ -19702,6 +19702,7 @@
field public static final int TYPE_BUILTIN_EARPIECE = 1; // 0x1
field public static final int TYPE_BUILTIN_MIC = 15; // 0xf
field public static final int TYPE_BUILTIN_SPEAKER = 2; // 0x2
+ field public static final int TYPE_BUS = 21; // 0x15
field public static final int TYPE_DOCK = 13; // 0xd
field public static final int TYPE_FM = 14; // 0xe
field public static final int TYPE_FM_TUNER = 16; // 0x10
@@ -19719,12 +19720,14 @@
field public static final int TYPE_WIRED_HEADSET = 3; // 0x3
}
- public class AudioFormat {
+ public class AudioFormat implements android.os.Parcelable {
+ method public int describeContents();
method public int getChannelCount();
method public int getChannelIndexMask();
method public int getChannelMask();
method public int getEncoding();
method public int getSampleRate();
+ method public void writeToParcel(android.os.Parcel, int);
field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
field public static final deprecated int CHANNEL_CONFIGURATION_INVALID = 0; // 0x0
field public static final deprecated int CHANNEL_CONFIGURATION_MONO = 2; // 0x2
@@ -19766,6 +19769,7 @@
field public static final int CHANNEL_OUT_SIDE_RIGHT = 4096; // 0x1000
field public static final int CHANNEL_OUT_STEREO = 12; // 0xc
field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c
+ field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
field public static final int ENCODING_AC3 = 5; // 0x5
field public static final int ENCODING_DEFAULT = 1; // 0x1
field public static final int ENCODING_DTS = 7; // 0x7
@@ -21197,6 +21201,7 @@
method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
+ method public void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -22761,8 +22766,11 @@
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final boolean isChannelUri(android.net.Uri);
+ method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
+ method public static final boolean isChannelUriForTunerInput(android.net.Uri);
+ method public static final boolean isProgramUri(android.net.Uri);
field public static final java.lang.String AUTHORITY = "android.media.tv";
- field public static final java.lang.String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS";
}
public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
@@ -22853,7 +22861,8 @@
field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+ field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+ field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
@@ -22863,7 +22872,9 @@
field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
- field public static final java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+ field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+ field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
@@ -22906,7 +22917,7 @@
field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+ field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
@@ -22921,7 +22932,8 @@
field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
- field public static final java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+ field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
@@ -23511,6 +23523,17 @@
method public abstract void onNetworkActive();
}
+ public class ConnectivityMetricsEvent implements android.os.Parcelable {
+ ctor public ConnectivityMetricsEvent(long, int, int, android.os.Parcelable);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent> CREATOR;
+ field public final int componentTag;
+ field public final android.os.Parcelable data;
+ field public final int eventTag;
+ field public final long timestamp;
+ }
+
public class Credentials {
ctor public Credentials(int, int, int);
method public int getGid();
@@ -34127,6 +34150,7 @@
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isDigestsSpecified();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
@@ -34144,6 +34168,7 @@
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
@@ -34170,6 +34195,7 @@
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isInsideSecureHardware();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
method public boolean isUserAuthenticationValidWhileOnBody();
@@ -34233,6 +34259,7 @@
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isDigestsSpecified();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
@@ -34244,6 +34271,7 @@
method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
+ method public android.security.keystore.KeyProtection.Builder setInvalidatedByBiometricEnrollment(boolean);
method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 0bf6594..50a24f6 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -9,6 +9,8 @@
package android.app.admin {
public class DevicePolicyManager {
+ method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
+ method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public deprecated java.lang.String getDeviceInitializerApp();
method public deprecated android.content.ComponentName getDeviceInitializerComponent();
}
@@ -35,7 +37,7 @@
package android.media {
- public class AudioFormat {
+ public class AudioFormat implements android.os.Parcelable {
ctor public AudioFormat();
}
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 079bdfc..75680e6 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -686,6 +686,11 @@
return null;
}
+ /** {@hide} */
+ public boolean isEncryptionAware() {
+ return mResolveInfo.serviceInfo.encryptionAware;
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index d5ca0e9..a34e8551e 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -383,8 +383,8 @@
*
* <p> If the admin is activated by a device owner, then the intent
* may contain private extras that are relevant to user setup.
- * {@see DevicePolicyManager#createAndInitializeUser(ComponentName, String, String,
- * ComponentName, Intent)}
+ * {@see DevicePolicyManager#createAndManageUser(ComponentName, String, ComponentName,
+ * PersistableBundle, int)}
*
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 820e0e8..ba8f1f4 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -341,6 +341,7 @@
*
* @hide
*/
+ @SystemApi
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_PROVISION_FINALIZATION
= "android.app.action.PROVISION_FINALIZATION";
@@ -932,30 +933,35 @@
* No management for current user in-effect. This is the default.
* @hide
*/
+ @SystemApi
public static final int STATE_USER_UNMANAGED = 0;
/**
* Management partially setup, user setup needs to be completed.
* @hide
*/
+ @SystemApi
public static final int STATE_USER_SETUP_INCOMPLETE = 1;
/**
* Management partially setup, user setup completed.
* @hide
*/
+ @SystemApi
public static final int STATE_USER_SETUP_COMPLETE = 2;
/**
* Management setup and active on current user.
* @hide
*/
+ @SystemApi
public static final int STATE_USER_SETUP_FINALIZED = 3;
/**
* Management partially setup on a managed profile.
* @hide
*/
+ @SystemApi
public static final int STATE_USER_PROFILE_COMPLETE = 4;
/**
@@ -4539,14 +4545,10 @@
* user could not be created.
*
* @deprecated From {@link android.os.Build.VERSION_CODES#M}
+ * @removed From {@link android.os.Build.VERSION_CODES#N}
*/
@Deprecated
public UserHandle createUser(@NonNull ComponentName admin, String name) {
- try {
- return mService.createUser(admin, name);
- } catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- }
return null;
}
@@ -4576,16 +4578,11 @@
* user could not be created.
*
* @deprecated From {@link android.os.Build.VERSION_CODES#M}
+ * @removed From {@link android.os.Build.VERSION_CODES#N}
*/
@Deprecated
public UserHandle createAndInitializeUser(@NonNull ComponentName admin, String name,
String ownerName, @NonNull ComponentName profileOwnerComponent, Bundle adminExtras) {
- try {
- return mService.createAndInitializeUser(admin, name, ownerName, profileOwnerComponent,
- adminExtras);
- } catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- }
return null;
}
@@ -5900,6 +5897,7 @@
* return {@link #STATE_USER_UNMANAGED}
* @hide
*/
+ @SystemApi
@UserProvisioningState
public int getUserProvisioningState() {
if (mService != null) {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index e9af872..e78c0ac 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -185,8 +185,6 @@
boolean setApplicationHidden(in ComponentName admin, in String packageName, boolean hidden);
boolean isApplicationHidden(in ComponentName admin, in String packageName);
- UserHandle createUser(in ComponentName who, in String name);
- UserHandle createAndInitializeUser(in ComponentName who, in String name, in String profileOwnerName, in ComponentName profileOwnerComponent, in Bundle adminExtras);
UserHandle createAndManageUser(in ComponentName who, in String name, in ComponentName profileOwner, in PersistableBundle adminExtras, in int flags);
boolean removeUser(in ComponentName who, in UserHandle userHandle);
boolean switchUser(in ComponentName who, in UserHandle userHandle);
diff --git a/core/java/android/auditing/SecurityLog.java b/core/java/android/auditing/SecurityLog.java
index f1703d6..829685b 100644
--- a/core/java/android/auditing/SecurityLog.java
+++ b/core/java/android/auditing/SecurityLog.java
@@ -64,7 +64,8 @@
public static final int TAG_SYNC_SEND_FILE = SecurityLogTags.SECURITY_ADB_SYNC_SEND;
/**
* Indicate that an app process was started. The log entry contains the following
- * information about the process in order, accessible via {@link SecurityEvent#getData()}}:
+ * information about the process encapsulated in an {@link Object} array, accessible via
+ * {@link SecurityEvent#getData()}:
* process name (String), exact start time (long), app Uid (integer), app Pid (integer),
* seinfo tag (String), SHA-256 hash of the APK in hexadecimal (String)
*/
@@ -77,10 +78,10 @@
SecurityLogTags.SECURITY_KEYGUARD_DISMISSED;
/**
* Indicate that there has been an authentication attempt to dismiss the keyguard. The log entry
- * contains the following information about the attempt in order, accessible via
- * {@link SecurityEvent#getData()}}: attempt result (integer, 1 for successful, 0 for
- * unsuccessful), strength of auth method (integer, 1 if strong auth method was used,
- * 0 otherwise)
+ * contains the following information about the attempt encapsulated in an {@link Object} array,
+ * accessible via {@link SecurityEvent#getData()}:
+ * attempt result (integer, 1 for successful, 0 for unsuccessful), strength of auth method
+ * (integer, 1 if strong auth method was used, 0 otherwise)
*/
public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT =
SecurityLogTags.SECURITY_KEYGUARD_DISMISS_AUTH_ATTEMPT;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 188e1d7..b7f968c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1573,6 +1573,48 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: If this feature is supported, the Vulkan native API will enumerate
+ * at least one {@code VkPhysicalDevice}, and the feature version will indicate what
+ * level of optional hardware features limits it supports.
+ * <p>
+ * Level 0 includes the base Vulkan requirements as well as:
+ * <ul><li>{@code VkPhysicalDeviceFeatures::textureCompressionETC2}</li></ul>
+ * <p>
+ * Level 1 additionally includes:
+ * <ul>
+ * <li>{@code VkPhysicalDeviceFeatures::fullDrawIndexUint32}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::imageCubeArray}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::independentBlend}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::geometryShader}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::tessellationShader}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::sampleRateShading}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::textureCompressionASTC_LDR}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::fragmentStoresAndAtomics}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::shaderImageGatherExtended}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::shaderUniformBufferArrayDynamicIndexing}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::shaderSampledImageArrayDynamicIndexing}</li>
+ * </ul>
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The version of this feature indicates the highest
+ * {@code VkPhysicalDeviceProperties::apiVersion} supported by the physical devices that support
+ * the hardware level indicated by {@link #FEATURE_VULKAN_HARDWARE_LEVEL}. The feature version
+ * uses the same encoding as Vulkan version numbers:
+ * <ul>
+ * <li>Major version number in bits 31-22</li>
+ * <li>Minor version number in bits 21-12</li>
+ * <li>Patch version number in bits 11-0</li>
+ * </ul>
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device includes an accelerometer.
*/
@SdkConstant(SdkConstantType.FEATURE)
@@ -4059,7 +4101,7 @@
*
* @return A list of {@link InstrumentationInfo} objects containing one
* entry for each matching instrumentation. If there are no
- * instrumentation available, returns and empty list.
+ * instrumentation available, returns an empty list.
*
* @see #GET_META_DATA
*/
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 9cf4675..3139151 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -73,6 +73,9 @@
/**
* Indicates that this user is disabled.
+ *
+ * <p>Note: If an ephemeral user is disabled, it shouldn't be later re-enabled. Ephemeral users
+ * are disabled as their removal is in progress to indicate that they shouldn't be re-entered.
*/
public static final int FLAG_DISABLED = 0x00000040;
@@ -171,6 +174,10 @@
* @return true if this user can be switched to.
**/
public boolean supportsSwitchTo() {
+ if (isEphemeral() && !isEnabled()) {
+ // Don't support switching to an ephemeral user with removal in progress.
+ return false;
+ }
// TODO remove fw.show_hidden_users when we have finished developing managed profiles.
return !isManagedProfile() || SystemProperties.getBoolean("fw.show_hidden_users", false);
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 915fae0..a9150e8 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -769,7 +769,6 @@
* @deprecated Use {@link #getDrawable(int, Theme)} instead.
*/
@Deprecated
- @Nullable
public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
final Drawable d = getDrawable(id, null);
if (d != null && d.canApplyTheme()) {
@@ -794,7 +793,6 @@
* @throws NotFoundException Throws NotFoundException if the given ID does
* not exist.
*/
- @Nullable
public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme)
throws NotFoundException {
final TypedValue value = obtainTempTypedValue(id);
@@ -832,7 +830,6 @@
* @deprecated Use {@link #getDrawableForDensity(int, int, Theme)} instead.
*/
@Deprecated
- @Nullable
public Drawable getDrawableForDensity(@DrawableRes int id, int density)
throws NotFoundException {
return getDrawableForDensity(id, density, null);
@@ -852,7 +849,6 @@
* @throws NotFoundException Throws NotFoundException if the given ID does
* not exist.
*/
- @Nullable
public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
final TypedValue value = obtainTempTypedValue(id);
try {
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 8be49e8..6cc7fec 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -1269,6 +1269,11 @@
private Size[] getInternalFormatSizes(int format, int dataspace,
boolean output, boolean highRes) {
+ // All depth formats are non-high-res.
+ if (dataspace == HAL_DATASPACE_DEPTH && highRes) {
+ return new Size[0];
+ }
+
SparseIntArray formatsMap =
!output ? mInputFormats :
dataspace == HAL_DATASPACE_DEPTH ? mDepthOutputFormats :
@@ -1287,6 +1292,8 @@
StreamConfiguration[] configurations =
(dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations : mConfigurations;
+ StreamConfigurationDuration[] minFrameDurations =
+ (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations : mMinFrameDurations;
for (StreamConfiguration config : configurations) {
int fmt = config.getFormat();
@@ -1295,8 +1302,8 @@
// Filter slow high-res output formats; include for
// highRes, remove for !highRes
long duration = 0;
- for (int i = 0; i < mMinFrameDurations.length; i++) {
- StreamConfigurationDuration d = mMinFrameDurations[i];
+ for (int i = 0; i < minFrameDurations.length; i++) {
+ StreamConfigurationDuration d = minFrameDurations[i];
if (d.getFormat() == fmt &&
d.getWidth() == config.getSize().getWidth() &&
d.getHeight() == config.getSize().getHeight()) {
@@ -1304,7 +1311,8 @@
break;
}
}
- if (highRes != (duration > DURATION_20FPS_NS)) {
+ if (dataspace != HAL_DATASPACE_DEPTH &&
+ highRes != (duration > DURATION_20FPS_NS)) {
continue;
}
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 9f8c28e..abd02f0 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -40,6 +40,7 @@
import javax.crypto.Cipher;
import javax.crypto.Mac;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.USE_FINGERPRINT;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
@@ -655,8 +656,23 @@
@RequiresPermission(USE_FINGERPRINT)
public boolean hasEnrolledFingerprints() {
if (mService != null) try {
- return mService.hasEnrolledFingerprints(UserHandle.myUserId(),
- mContext.getOpPackageName());
+ return mService.hasEnrolledFingerprints(
+ UserHandle.myUserId(), mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @RequiresPermission(allOf = {
+ USE_FINGERPRINT,
+ INTERACT_ACROSS_USERS})
+ public boolean hasEnrolledFingerprints(int userId) {
+ if (mService != null) try {
+ return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
}
diff --git a/core/java/android/net/ConnectivityMetricsEvent.aidl b/core/java/android/net/ConnectivityMetricsEvent.aidl
new file mode 100644
index 0000000..da17561
--- /dev/null
+++ b/core/java/android/net/ConnectivityMetricsEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 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.net;
+
+parcelable ConnectivityMetricsEvent;
diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java
new file mode 100644
index 0000000..d040a85
--- /dev/null
+++ b/core/java/android/net/ConnectivityMetricsEvent.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 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.net;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+@SystemApi
+public class ConnectivityMetricsEvent implements Parcelable {
+
+ /** The time when this event was collected, as returned by System.currentTimeMillis(). */
+ final public long timestamp;
+
+ /** The subsystem that generated the event. One of the COMPONENT_TAG_xxx constants. */
+ final public int componentTag;
+
+ /** The subsystem-specific event ID. */
+ final public int eventTag;
+
+ /** Opaque event-specific data. */
+ final public Parcelable data;
+
+ public ConnectivityMetricsEvent(long timestamp, int componentTag,
+ int eventTag, Parcelable data) {
+ this.timestamp = timestamp;
+ this.componentTag = componentTag;
+ this.eventTag = eventTag;
+ this.data = data;
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Parcelable.Creator<ConnectivityMetricsEvent> CREATOR
+ = new Parcelable.Creator<ConnectivityMetricsEvent> (){
+ public ConnectivityMetricsEvent createFromParcel(Parcel source) {
+ final long timestamp = source.readLong();
+ final int componentTag = source.readInt();
+ final int eventTag = source.readInt();
+ final Parcelable data = source.readParcelable(null);
+ return new ConnectivityMetricsEvent(timestamp, componentTag,
+ eventTag, data);
+ }
+
+ public ConnectivityMetricsEvent[] newArray(int size) {
+ return new ConnectivityMetricsEvent[size];
+ }
+ };
+
+ /** Implement the Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(timestamp);
+ dest.writeInt(componentTag);
+ dest.writeInt(eventTag);
+ dest.writeParcelable(data, 0);
+ }
+
+ public String toString() {
+ return String.format("ConnectivityMetricsEvent(%d, %d, %d)", timestamp,
+ componentTag, eventTag);
+ }
+}
diff --git a/core/java/android/net/ConnectivityMetricsLogger.java b/core/java/android/net/ConnectivityMetricsLogger.java
new file mode 100644
index 0000000..3ef8050
--- /dev/null
+++ b/core/java/android/net/ConnectivityMetricsLogger.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 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.net;
+
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/** {@hide} */
+public class ConnectivityMetricsLogger {
+ private static String TAG = "ConnectivityMetricsLogger";
+ private static final boolean DBG = true;
+
+ public static final String CONNECTIVITY_METRICS_LOGGER_SERVICE = "connectivity_metrics_logger";
+
+ // Component Tags
+ public static final int COMPONENT_TAG_CONNECTIVITY = 1;
+ public static final int COMPONENT_TAG_BLUETOOTH = 2;
+ public static final int COMPONENT_TAG_WIFI = 3;
+ public static final int COMPONENT_TAG_TELECOM = 4;
+ public static final int COMPONENT_TAG_TELEPHONY = 5;
+
+ private IConnectivityMetricsLogger mService;
+
+ public ConnectivityMetricsLogger() {
+ mService = IConnectivityMetricsLogger.Stub.asInterface(ServiceManager.getService(
+ CONNECTIVITY_METRICS_LOGGER_SERVICE));
+ }
+
+ public void logEvent(long timestamp, int componentTag, int eventTag, Parcelable data) {
+ if (mService == null) {
+ if (DBG) {
+ Log.d(TAG, "logEvent(" + componentTag + "," + eventTag + ") Service not ready");
+ }
+ } else {
+ try {
+ mService.logEvent(new ConnectivityMetricsEvent(timestamp, componentTag, eventTag, data));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error logging event " + e.getMessage());
+ }
+ }
+ }
+}
diff --git a/core/java/android/net/IConnectivityMetricsLogger.aidl b/core/java/android/net/IConnectivityMetricsLogger.aidl
new file mode 100644
index 0000000..2778671
--- /dev/null
+++ b/core/java/android/net/IConnectivityMetricsLogger.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 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.net;
+
+import android.net.ConnectivityMetricsEvent;
+import android.net.IConnectivityMetricsLoggerSubscriber;
+
+/** {@hide} */
+interface IConnectivityMetricsLogger {
+
+ void logEvent(in ConnectivityMetricsEvent event);
+ void logEvents(in ConnectivityMetricsEvent[] events);
+
+ boolean subscribe(in IConnectivityMetricsLoggerSubscriber subscriber);
+ void unsubscribe(in IConnectivityMetricsLoggerSubscriber subscriber);
+}
diff --git a/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl b/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl
new file mode 100644
index 0000000..a2c62cd
--- /dev/null
+++ b/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 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.net;
+
+import android.net.ConnectivityMetricsEvent;
+
+/** {@hide} */
+oneway interface IConnectivityMetricsLoggerSubscriber {
+
+ void onEvents(in ConnectivityMetricsEvent[] events);
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index a738b2e..8281279 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -623,7 +623,7 @@
/**
* The statistics associated with a particular service.
*/
- public abstract class Serv {
+ public static abstract class Serv {
/**
* Returns the amount of time spent started.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1a093d8..da7f85f 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1371,8 +1371,12 @@
/**
* Sets the user as enabled, if such an user exists.
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
- * Note that the default is true, it's only that managed profiles might not be enabled.
+ *
+ * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+ *
+ * <p>Note that the default is true, it's only that managed profiles might not be enabled.
+ * Also ephemeral users can be disabled to indicate that their removal is in progress and they
+ * shouldn't be re-entered. Therefore ephemeral users should not be re-enabled once disabled.
*
* @param userHandle the id of the profile to enable
* @hide
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index d2ece8b..f399719 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -109,6 +109,17 @@
public abstract void removeAllUsers();
/**
+ * Called by the activity manager when the ephemeral user goes to background and its removal
+ * starts as a result.
+ *
+ * <p>It marks the ephemeral user as disabled in order to prevent it from being re-entered
+ * before its removal finishes.
+ *
+ * @param userId the ID of the ephemeral user.
+ */
+ public abstract void onEphemeralUserStop(int userId);
+
+ /**
* Same as UserManager.createUser(), but bypasses the check for DISALLOW_ADD_USER.
*
* <p>Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0074788..921e18f 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2780,6 +2780,11 @@
*/
public static final Uri DEFAULT_RINGTONE_URI = getUriFor(RINGTONE);
+ /** {@hide} */
+ public static final String RINGTONE_CACHE = "ringtone_cache";
+ /** {@hide} */
+ public static final Uri RINGTONE_CACHE_URI = getUriFor(RINGTONE_CACHE);
+
/**
* Persistent store for the system-wide default notification sound.
*
@@ -2798,6 +2803,11 @@
*/
public static final Uri DEFAULT_NOTIFICATION_URI = getUriFor(NOTIFICATION_SOUND);
+ /** {@hide} */
+ public static final String NOTIFICATION_SOUND_CACHE = "notification_sound_cache";
+ /** {@hide} */
+ public static final Uri NOTIFICATION_SOUND_CACHE_URI = getUriFor(NOTIFICATION_SOUND_CACHE);
+
/**
* Persistent store for the system-wide default alarm alert.
*
@@ -2816,6 +2826,11 @@
*/
public static final Uri DEFAULT_ALARM_ALERT_URI = getUriFor(ALARM_ALERT);
+ /** {@hide} */
+ public static final String ALARM_ALERT_CACHE = "alarm_alert_cache";
+ /** {@hide} */
+ public static final Uri ALARM_ALERT_CACHE_URI = getUriFor(ALARM_ALERT_CACHE);
+
/**
* Persistent store for the system default media button event receiver.
*
@@ -8141,6 +8156,15 @@
"uninstalled_ephemeral_app_cache_duration_millis";
/**
+ * Allows switching users when system user is locked.
+ * <p>
+ * Type: int
+ * @hide
+ */
+ public static final String ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED =
+ "allow_user_switching_when_system_user_locked";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index a4cb703..a45c18d 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -779,7 +779,7 @@
return mOwningView != null && mOwningView.mAttachInfo != null;
}
- public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimator animatorSet) {
+ public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) {
if (mOwningView == null || mOwningView.mAttachInfo == null) {
throw new IllegalStateException("Cannot start this animator on a detached view!");
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 673c609..2e10bec 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1072,6 +1072,8 @@
mStopped = stopped;
if (!mStopped) {
scheduleTraversals();
+ } else {
+ destroyHardwareResources();
}
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 18dfdfd..6e02516 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -30,7 +30,7 @@
import android.util.Log;
import java.util.List;
-
+import java.util.Objects;
/**
* The interface that apps use to talk to the window manager.
@@ -1950,7 +1950,7 @@
// already have one.
packageName = o.packageName;
}
- if (o.mTitle != null) {
+ if (!Objects.equals(mTitle, o.mTitle) && o.mTitle != null) {
// NOTE: mTitle only copied if the originator set one.
mTitle = o.mTitle;
changes |= TITLE_CHANGED;
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 23af384..94dc03c 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -156,7 +156,7 @@
* Adds the WebView asset path to {@link android.content.res.AssetManager}.
*/
public void addWebViewAssetPath(Context context) {
- context.getAssets().addAssetPath(
+ context.getAssets().addAssetPathAsSharedLibrary(
WebViewFactory.getLoadedPackageInfo().applicationInfo.sourceDir);
}
}
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index c7459d7..aca93ab 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -16,8 +16,8 @@
package com.android.internal.app;
-import android.icu.util.ULocale;
import android.icu.text.ListFormatter;
+import android.icu.util.ULocale;
import android.util.LocaleList;
import java.text.Collator;
@@ -99,7 +99,7 @@
* @return the localized name of the locale.
*/
public static String getDisplayName(Locale locale, Locale displayLocale, boolean sentenceCase) {
- String result = ULocale.getDisplayName(locale.toLanguageTag(),
+ String result = ULocale.getDisplayNameWithDialect(locale.toLanguageTag(),
ULocale.forLocale(displayLocale));
return sentenceCase ? toSentenceCase(result, displayLocale) : result;
}
@@ -112,7 +112,8 @@
* @return the localized name of the locale.
*/
public static String getDisplayName(Locale locale, boolean sentenceCase) {
- String result = ULocale.getDisplayName(locale.toLanguageTag(), ULocale.getDefault());
+ String result = ULocale.getDisplayNameWithDialect(locale.toLanguageTag(),
+ ULocale.getDefault());
return sentenceCase ? toSentenceCase(result, Locale.getDefault()) : result;
}
@@ -155,7 +156,7 @@
}
ListFormatter lfn = ListFormatter.getInstance(dispLocale);
- return lfn.format(localeNames);
+ return lfn.format((Object[]) localeNames);
}
/**
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index 478a56d..0d4a5aa 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -23,7 +23,6 @@
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
-import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.R;
@@ -156,16 +155,9 @@
}
TextView text = (TextView) convertView.findViewById(R.id.locale);
- ImageView localized = (ImageView) convertView.findViewById(R.id.l10nWarn);
LocaleStore.LocaleInfo item = (LocaleStore.LocaleInfo) getItem(position);
text.setText(item.getLabel());
- if (item.isTranslated() || mCountryMode) {
- localized.setVisibility(View.GONE);
- text.setTextLocale(item.getLocale());
- } else {
- localized.setVisibility(View.VISIBLE);
- text.setTextLocale(Locale.getDefault());
- }
+ text.setTextLocale(item.getLocale());
if (mCountryMode) {
int layoutDir = TextUtils.getLayoutDirectionFromLocale(item.getParent());
//noinspection ResourceType
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 648b1a5..d917cdb 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -93,7 +93,7 @@
* battery life. All times are represented in microseconds except where indicated
* otherwise.
*/
-public final class BatteryStatsImpl extends BatteryStats {
+public class BatteryStatsImpl extends BatteryStats {
private static final String TAG = "BatteryStatsImpl";
private static final boolean DEBUG = false;
public static final boolean DEBUG_ENERGY = false;
@@ -126,6 +126,8 @@
// Number of transmit power states the Bluetooth controller can be in.
private static final int NUM_BT_TX_LEVELS = 1;
+ protected Clocks mClocks;
+
private final JournaledFile mFile;
public final AtomicFile mCheckinFile;
public final AtomicFile mDailyFile;
@@ -185,6 +187,21 @@
}
}
+ public interface Clocks {
+ public long elapsedRealtime();
+ public long uptimeMillis();
+ }
+
+ public static class SystemClocks implements Clocks {
+ public long elapsedRealtime() {
+ return SystemClock.elapsedRealtime();
+ }
+
+ public long uptimeMillis() {
+ return SystemClock.uptimeMillis();
+ }
+ }
+
public interface ExternalStatsSync {
public static final int UPDATE_CPU = 0x01;
public static final int UPDATE_WIFI = 0x02;
@@ -236,7 +253,7 @@
// These are the objects that will want to do something when the device
// is unplugged from power.
- final TimeBase mOnBatteryTimeBase = new TimeBase();
+ protected final TimeBase mOnBatteryTimeBase = new TimeBase();
// These are the objects that will want to do something when the device
// is unplugged from power *and* the screen is off.
@@ -541,6 +558,11 @@
}
public BatteryStatsImpl() {
+ this(new SystemClocks());
+ }
+
+ public BatteryStatsImpl(Clocks clocks) {
+ init(clocks);
mFile = null;
mCheckinFile = null;
mDailyFile = null;
@@ -549,25 +571,40 @@
clearHistoryLocked();
}
+ private void init(Clocks clocks) {
+ mClocks = clocks;
+ mMobileNetworkStats = new NetworkStats[] {
+ new NetworkStats(mClocks.elapsedRealtime(), 50),
+ new NetworkStats(mClocks.elapsedRealtime(), 50),
+ new NetworkStats(mClocks.elapsedRealtime(), 50)
+ };
+ mWifiNetworkStats = new NetworkStats[] {
+ new NetworkStats(mClocks.elapsedRealtime(), 50),
+ new NetworkStats(mClocks.elapsedRealtime(), 50),
+ new NetworkStats(mClocks.elapsedRealtime(), 50)
+ };
+ }
+
public static interface TimeBaseObs {
void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime);
void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime);
}
- static class TimeBase {
- private final ArrayList<TimeBaseObs> mObservers = new ArrayList<>();
+ // methods are protected not private to be VisibleForTesting
+ public static class TimeBase {
+ protected final ArrayList<TimeBaseObs> mObservers = new ArrayList<>();
- private long mUptime;
- private long mRealtime;
+ protected long mUptime;
+ protected long mRealtime;
- private boolean mRunning;
+ protected boolean mRunning;
- private long mPastUptime;
- private long mUptimeStart;
- private long mPastRealtime;
- private long mRealtimeStart;
- private long mUnpluggedUptime;
- private long mUnpluggedRealtime;
+ protected long mPastUptime;
+ protected long mUptimeStart;
+ protected long mPastRealtime;
+ protected long mRealtimeStart;
+ protected long mUnpluggedUptime;
+ protected long mUnpluggedRealtime;
public void dump(PrintWriter pw, String prefix) {
StringBuilder sb = new StringBuilder(128);
@@ -608,6 +645,10 @@
}
}
+ public boolean hasObserver(TimeBaseObs observer) {
+ return mObservers.contains(observer);
+ }
+
public void init(long uptime, long realtime) {
mRealtime = 0;
mUptime = 0;
@@ -626,7 +667,10 @@
} else {
mUptimeStart = uptime;
mRealtimeStart = realtime;
+ // TODO: Since mUptimeStart was just reset and we are running, getUptime will
+ // just return mPastUptime. Also, are we sure we don't want to reset that?
mUnpluggedUptime = getUptime(uptime);
+ // TODO: likewise.
mUnpluggedRealtime = getRealtime(realtime);
}
}
@@ -949,13 +993,14 @@
* State for keeping track of timing information.
*/
public static abstract class Timer extends BatteryStats.Timer implements TimeBaseObs {
- final int mType;
- final TimeBase mTimeBase;
+ protected final Clocks mClocks;
+ protected final int mType;
+ protected final TimeBase mTimeBase;
- int mCount;
- int mLoadedCount;
- int mLastCount;
- int mUnpluggedCount;
+ protected int mCount;
+ protected int mLoadedCount;
+ protected int mLastCount;
+ protected int mUnpluggedCount;
// Times are in microseconds for better accuracy when dividing by the
// lock count, and are in "battery realtime" units.
@@ -965,32 +1010,32 @@
* boot, to the last time something interesting happened in the
* current run.
*/
- long mTotalTime;
+ protected long mTotalTime;
/**
* The total time we loaded for the previous runs. Subtract this from
* mTotalTime to find the time for the current run of the system.
*/
- long mLoadedTime;
+ protected long mLoadedTime;
/**
* The run time of the last run of the system, as loaded from the
* saved data.
*/
- long mLastTime;
+ protected long mLastTime;
/**
* The value of mTotalTime when unplug() was last called. Subtract
* this from mTotalTime to find the time since the last unplug from
* power.
*/
- long mUnpluggedTime;
+ protected long mUnpluggedTime;
/**
* The total time this timer has been running until the latest mark has been set.
* Subtract this from mTotalTime to get the time spent running since the mark was set.
*/
- long mTimeBeforeMark;
+ protected long mTimeBeforeMark;
/**
* Constructs from a parcel.
@@ -998,7 +1043,8 @@
* @param timeBase
* @param in
*/
- Timer(int type, TimeBase timeBase, Parcel in) {
+ public Timer(Clocks clocks, int type, TimeBase timeBase, Parcel in) {
+ mClocks = clocks;
mType = type;
mTimeBase = timeBase;
@@ -1015,7 +1061,8 @@
if (DEBUG) Log.i(TAG, "**** READ TIMER #" + mType + ": mTotalTime=" + mTotalTime);
}
- Timer(int type, TimeBase timeBase) {
+ public Timer(Clocks clocks, int type, TimeBase timeBase) {
+ mClocks = clocks;
mType = type;
mTimeBase = timeBase;
timeBase.add(this);
@@ -1029,7 +1076,7 @@
* Clear state of this timer. Returns true if the timer is inactive
* so can be completely dropped.
*/
- boolean reset(boolean detachIfReset) {
+ public boolean reset(boolean detachIfReset) {
mTotalTime = mLoadedTime = mLastTime = mTimeBeforeMark = 0;
mCount = mLoadedCount = mLastCount = 0;
if (detachIfReset) {
@@ -1038,7 +1085,7 @@
return true;
}
- void detach() {
+ public void detach() {
mTimeBase.remove(this);
}
@@ -1142,13 +1189,13 @@
}
- void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) {
+ public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) {
long runTime = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
out.writeLong(runTime);
out.writeInt(mCount);
}
- void readSummaryFromParcelLocked(Parcel in) {
+ public void readSummaryFromParcelLocked(Parcel in) {
// Multiply by 1000 for backwards compatibility
mTotalTime = mLoadedTime = in.readLong();
mLastTime = 0;
@@ -1162,7 +1209,7 @@
}
}
- public static final class SamplingTimer extends Timer {
+ public static class SamplingTimer extends Timer {
/**
* The most recent reported count from /proc/wakelocks.
@@ -1202,8 +1249,8 @@
*/
int mUpdateVersion;
- SamplingTimer(TimeBase timeBase, Parcel in) {
- super(0, timeBase, in);
+ SamplingTimer(Clocks clocks, TimeBase timeBase, Parcel in) {
+ super(clocks, 0, timeBase, in);
mCurrentReportedCount = in.readInt();
mUnpluggedReportedCount = in.readInt();
mCurrentReportedTotalTime = in.readLong();
@@ -1212,8 +1259,8 @@
mTimeBaseRunning = timeBase.isRunning();
}
- SamplingTimer(TimeBase timeBase, boolean trackReportedValues) {
- super(0, timeBase);
+ SamplingTimer(Clocks clocks, TimeBase timeBase, boolean trackReportedValues) {
+ super(clocks, 0, timeBase);
mTrackingReportedValues = trackReportedValues;
mTimeBaseRunning = timeBase.isRunning();
}
@@ -1301,20 +1348,20 @@
out.writeInt(mTrackingReportedValues ? 1 : 0);
}
- boolean reset(boolean detachIfReset) {
+ public boolean reset(boolean detachIfReset) {
super.reset(detachIfReset);
setStale();
return true;
}
- void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
+ public void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
super.writeSummaryFromParcelLocked(out, batteryRealtime);
out.writeLong(mCurrentReportedTotalTime);
out.writeInt(mCurrentReportedCount);
out.writeInt(mTrackingReportedValues ? 1 : 0);
}
- void readSummaryFromParcelLocked(Parcel in) {
+ public void readSummaryFromParcelLocked(Parcel in) {
super.readSummaryFromParcelLocked(in);
mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = in.readLong();
mUnpluggedReportedCount = mCurrentReportedCount = in.readInt();
@@ -1326,7 +1373,7 @@
* A timer that increments in batches. It does not run for durations, but just jumps
* for a pre-determined amount.
*/
- public static final class BatchTimer extends Timer {
+ public static class BatchTimer extends Timer {
final Uid mUid;
/**
@@ -1344,16 +1391,16 @@
*/
boolean mInDischarge;
- BatchTimer(Uid uid, int type, TimeBase timeBase, Parcel in) {
- super(type, timeBase, in);
+ BatchTimer(Clocks clocks, Uid uid, int type, TimeBase timeBase, Parcel in) {
+ super(clocks, type, timeBase, in);
mUid = uid;
mLastAddedTime = in.readLong();
mLastAddedDuration = in.readLong();
mInDischarge = timeBase.isRunning();
}
- BatchTimer(Uid uid, int type, TimeBase timeBase) {
- super(type, timeBase);
+ BatchTimer(Clocks clocks, Uid uid, int type, TimeBase timeBase) {
+ super(clocks, type, timeBase);
mUid = uid;
mInDischarge = timeBase.isRunning();
}
@@ -1367,7 +1414,7 @@
@Override
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
- recomputeLastDuration(SystemClock.elapsedRealtime() * 1000, false);
+ recomputeLastDuration(mClocks.elapsedRealtime() * 1000, false);
mInDischarge = false;
super.onTimeStopped(elapsedRealtime, baseUptime, baseRealtime);
}
@@ -1416,7 +1463,7 @@
}
public void addDuration(BatteryStatsImpl stats, long durationMillis) {
- final long now = SystemClock.elapsedRealtime() * 1000;
+ final long now = mClocks.elapsedRealtime() * 1000;
recomputeLastDuration(now, true);
mLastAddedTime = now;
mLastAddedDuration = durationMillis * 1000;
@@ -1427,7 +1474,7 @@
}
public void abortLastDuration(BatteryStatsImpl stats) {
- final long now = SystemClock.elapsedRealtime() * 1000;
+ final long now = mClocks.elapsedRealtime() * 1000;
recomputeLastDuration(now, true);
}
@@ -1438,7 +1485,7 @@
@Override
protected long computeRunTimeLocked(long curBatteryRealtime) {
- final long overage = computeOverage(SystemClock.elapsedRealtime() * 1000);
+ final long overage = computeOverage(mClocks.elapsedRealtime() * 1000);
if (overage > 0) {
return mTotalTime = overage;
}
@@ -1446,8 +1493,8 @@
}
@Override
- boolean reset(boolean detachIfReset) {
- final long now = SystemClock.elapsedRealtime() * 1000;
+ public boolean reset(boolean detachIfReset) {
+ final long now = mClocks.elapsedRealtime() * 1000;
recomputeLastDuration(now, true);
boolean stillActive = mLastAddedTime == now;
super.reset(!stillActive && detachIfReset);
@@ -1458,7 +1505,7 @@
/**
* State for keeping track of timing information.
*/
- public static final class StopwatchTimer extends Timer {
+ public static class StopwatchTimer extends Timer {
final Uid mUid;
final ArrayList<StopwatchTimer> mTimerPool;
@@ -1485,22 +1532,22 @@
*/
boolean mInList;
- StopwatchTimer(Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+ public StopwatchTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
TimeBase timeBase, Parcel in) {
- super(type, timeBase, in);
+ super(clocks, type, timeBase, in);
mUid = uid;
mTimerPool = timerPool;
mUpdateTime = in.readLong();
}
- StopwatchTimer(Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+ public StopwatchTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
TimeBase timeBase) {
- super(type, timeBase);
+ super(clocks, type, timeBase);
mUid = uid;
mTimerPool = timerPool;
}
- void setTimeout(long timeout) {
+ public void setTimeout(long timeout) {
mTimeout = timeout;
}
@@ -1528,7 +1575,7 @@
+ " mAcquireTime=" + mAcquireTime);
}
- void startRunningLocked(long elapsedRealtimeMs) {
+ public void startRunningLocked(long elapsedRealtimeMs) {
if (mNesting++ == 0) {
final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
mUpdateTime = batteryRealtime;
@@ -1550,11 +1597,11 @@
}
}
- boolean isRunningLocked() {
+ public boolean isRunningLocked() {
return mNesting > 0;
}
- void stopRunningLocked(long elapsedRealtimeMs) {
+ public void stopRunningLocked(long elapsedRealtimeMs) {
// Ignore attempt to stop a timer that isn't running
if (mNesting == 0) {
return;
@@ -1587,7 +1634,7 @@
}
}
- void stopAllRunningLocked(long elapsedRealtimeMs) {
+ public void stopAllRunningLocked(long elapsedRealtimeMs) {
if (mNesting > 0) {
mNesting = 1;
stopRunningLocked(elapsedRealtimeMs);
@@ -1632,18 +1679,18 @@
}
@Override
- boolean reset(boolean detachIfReset) {
+ public boolean reset(boolean detachIfReset) {
boolean canDetach = mNesting <= 0;
super.reset(canDetach && detachIfReset);
if (mNesting > 0) {
- mUpdateTime = mTimeBase.getRealtime(SystemClock.elapsedRealtime() * 1000);
+ mUpdateTime = mTimeBase.getRealtime(mClocks.elapsedRealtime() * 1000);
}
mAcquireTime = mTotalTime;
return canDetach;
}
@Override
- void detach() {
+ public void detach() {
super.detach();
if (mTimerPool != null) {
mTimerPool.remove(this);
@@ -1651,7 +1698,7 @@
}
@Override
- void readSummaryFromParcelLocked(Parcel in) {
+ public void readSummaryFromParcelLocked(Parcel in) {
super.readSummaryFromParcelLocked(in);
mNesting = 0;
}
@@ -1943,7 +1990,7 @@
public SamplingTimer getWakeupReasonTimerLocked(String name) {
SamplingTimer timer = mWakeupReasonStats.get(name);
if (timer == null) {
- timer = new SamplingTimer(mOnBatteryTimeBase, true);
+ timer = new SamplingTimer(mClocks, mOnBatteryTimeBase, true);
mWakeupReasonStats.put(name, timer);
}
return timer;
@@ -1956,7 +2003,8 @@
public SamplingTimer getKernelWakelockTimerLocked(String name) {
SamplingTimer kwlt = mKernelWakelockStats.get(name);
if (kwlt == null) {
- kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase, true /* track reported values */);
+ kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase,
+ true /* track reported values */);
mKernelWakelockStats.put(name, kwlt);
}
return kwlt;
@@ -2729,8 +2777,8 @@
if (!mActiveEvents.updateState(code, name, uid, 0)) {
return;
}
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, code, name, uid);
}
@@ -2740,7 +2788,7 @@
// If the start clock time has changed by more than a year, then presumably
// the previous time was completely bogus. So we are going to figure out a
// new time based on how much time has elapsed since we started counting.
- mStartClockTime = currentTime - (SystemClock.elapsedRealtime()-(mRealtimeStart/1000));
+ mStartClockTime = currentTime - (mClocks.elapsedRealtime()-(mRealtimeStart/1000));
return true;
}
return false;
@@ -2748,8 +2796,8 @@
public void noteCurrentTimeChangedLocked() {
final long currentTime = System.currentTimeMillis();
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
recordCurrentTimeChangeLocked(currentTime, elapsedRealtime, uptime);
ensureStartClockTime(currentTime);
}
@@ -2766,8 +2814,8 @@
if (!mRecordAllHistory) {
return;
}
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_START, name, uid);
}
@@ -2800,15 +2848,15 @@
if (!mRecordAllHistory) {
return;
}
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_FINISH, name, uid);
}
public void noteSyncStartLocked(String name, int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
getUidStatsLocked(uid).noteStartSyncLocked(name, elapsedRealtime);
if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_START, name, uid, 0)) {
return;
@@ -2818,8 +2866,8 @@
public void noteSyncFinishLocked(String name, int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
getUidStatsLocked(uid).noteStopSyncLocked(name, elapsedRealtime);
if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_FINISH, name, uid, 0)) {
return;
@@ -2829,8 +2877,8 @@
public void noteJobStartLocked(String name, int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
getUidStatsLocked(uid).noteStartJobLocked(name, elapsedRealtime);
if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_START, name, uid, 0)) {
return;
@@ -2840,8 +2888,8 @@
public void noteJobFinishLocked(String name, int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
getUidStatsLocked(uid).noteStopJobLocked(name, elapsedRealtime);
if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_FINISH, name, uid, 0)) {
return;
@@ -2854,8 +2902,8 @@
return;
}
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (!mActiveEvents.updateState(HistoryItem.EVENT_ALARM_START, name, uid, 0)) {
return;
}
@@ -2867,8 +2915,8 @@
return;
}
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (!mActiveEvents.updateState(HistoryItem.EVENT_ALARM_FINISH, name, uid, 0)) {
return;
}
@@ -2898,8 +2946,8 @@
HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
HistoryItem.EVENT_PROC);
if (active != null) {
- long mSecRealtime = SystemClock.elapsedRealtime();
- final long mSecUptime = SystemClock.uptimeMillis();
+ long mSecRealtime = mClocks.elapsedRealtime();
+ final long mSecUptime = mClocks.uptimeMillis();
for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
SparseIntArray uids = ent.getValue();
for (int j=0; j<uids.size(); j++) {
@@ -2913,8 +2961,8 @@
HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
HistoryItem.EVENT_PROC);
if (active != null) {
- long mSecRealtime = SystemClock.elapsedRealtime();
- final long mSecUptime = SystemClock.uptimeMillis();
+ long mSecRealtime = mClocks.elapsedRealtime();
+ final long mSecUptime = mClocks.uptimeMillis();
for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
SparseIntArray uids = ent.getValue();
for (int j=0; j<uids.size(); j++) {
@@ -3023,8 +3071,8 @@
public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name,
String historyName, int type, boolean unimportantForLogging) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
final int N = ws.size();
for (int i=0; i<N; i++) {
noteStartWakeLocked(ws.get(i), pid, name, historyName, type, unimportantForLogging,
@@ -3035,8 +3083,8 @@
public void noteChangeWakelockFromSourceLocked(WorkSource ws, int pid, String name,
String historyName, int type, WorkSource newWs, int newPid, String newName,
String newHistoryName, int newType, boolean newUnimportantForLogging) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
// For correct semantics, we start the need worksources first, so that we won't
// make inappropriate history items as if all wake locks went away and new ones
// appeared. This is okay because tracking of wake locks allows nesting.
@@ -3053,8 +3101,8 @@
public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name,
String historyName, int type) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
final int N = ws.size();
for (int i=0; i<N; i++) {
noteStopWakeLocked(ws.get(i), pid, name, historyName, type, elapsedRealtime, uptime);
@@ -3072,8 +3120,8 @@
}
public void noteWakeupReasonLocked(String reason) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (DEBUG_HISTORY) Slog.v(TAG, "Wakeup reason \"" + reason +"\": "
+ Integer.toHexString(mHistoryCur.states));
aggregateLastWakeupUptimeLocked(uptime);
@@ -3147,8 +3195,8 @@
public void noteStartSensorLocked(int uid, int sensor) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mSensorNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: "
@@ -3161,8 +3209,8 @@
public void noteStopSensorLocked(int uid, int sensor) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mSensorNesting--;
if (mSensorNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG;
@@ -3177,8 +3225,8 @@
public void noteStartGpsLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mGpsNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
@@ -3191,8 +3239,8 @@
public void noteStopGpsLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mGpsNesting--;
if (mGpsNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
@@ -3223,8 +3271,8 @@
if (state == Display.STATE_ON) {
// Screen turning on.
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -3235,7 +3283,7 @@
}
updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), false,
- SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
+ mClocks.uptimeMillis() * 1000, elapsedRealtime * 1000);
// Fake a wake lock, so we consider the device waked as long
// as the screen is on.
@@ -3248,8 +3296,8 @@
}
} else if (oldState == Display.STATE_ON) {
// Screen turning off or dozing.
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -3263,7 +3311,7 @@
elapsedRealtime, uptime);
updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), true,
- SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
+ mClocks.uptimeMillis() * 1000, elapsedRealtime * 1000);
// Update discharge amounts.
if (mOnBatteryInternal) {
@@ -3279,8 +3327,8 @@
if (bin < 0) bin = 0;
else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
if (mScreenBrightnessBin != bin) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_BRIGHTNESS_MASK)
| (bin << HistoryItem.STATE_BRIGHTNESS_SHIFT);
if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
@@ -3304,15 +3352,15 @@
}
public void noteWakeUpLocked(String reason, int reasonUid) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_SCREEN_WAKE_UP,
reason, reasonUid);
}
public void noteInteractiveLocked(boolean interactive) {
if (mInteractive != interactive) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
mInteractive = interactive;
if (DEBUG) Slog.v(TAG, "Interactive: " + interactive);
if (interactive) {
@@ -3324,16 +3372,16 @@
}
public void noteConnectivityChangedLocked(int type, String extra) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_CONNECTIVITY_CHANGED,
extra, type);
mNumConnectivityChange++;
}
public void noteMobileRadioPowerState(int powerState, long timestampNs) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mMobileRadioPowerState != powerState) {
long realElapsedRealtimeMs;
final boolean active =
@@ -3375,8 +3423,8 @@
int stepState = enabled ? STEP_LEVEL_MODE_POWER_SAVE : 0;
mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_POWER_SAVE) ^ stepState;
mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_POWER_SAVE) | stepState;
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mPowerSaveModeEnabled = enabled;
if (enabled) {
mHistoryCur.states2 |= HistoryItem.STATE2_POWER_SAVE_FLAG;
@@ -3394,8 +3442,8 @@
}
public void noteDeviceIdleModeLocked(int mode, String activeReason, int activeUid) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
boolean nowIdling = mode == DEVICE_IDLE_MODE_FULL;
if (mDeviceIdling && !nowIdling && activeReason == null) {
// We don't go out of general idling mode until explicitly taken out of
@@ -3460,8 +3508,8 @@
}
public void notePackageInstalledLocked(String pkgName, int versionCode) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_INSTALLED,
pkgName, versionCode);
PackageChange pc = new PackageChange();
@@ -3472,8 +3520,8 @@
}
public void notePackageUninstalledLocked(String pkgName) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_UNINSTALLED,
pkgName, 0);
PackageChange pc = new PackageChange();
@@ -3491,8 +3539,8 @@
public void notePhoneOnLocked() {
if (!mPhoneOn) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states2 |= HistoryItem.STATE2_PHONE_IN_CALL_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -3504,8 +3552,8 @@
public void notePhoneOffLocked() {
if (mPhoneOn) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states2 &= ~HistoryItem.STATE2_PHONE_IN_CALL_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -3516,7 +3564,7 @@
}
void stopAllPhoneSignalStrengthTimersLocked(int except) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
for (int i = 0; i < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
if (i == except) {
continue;
@@ -3548,8 +3596,8 @@
mPhoneSimStateRaw = simState;
mPhoneSignalStrengthBinRaw = strengthBin;
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (simState == TelephonyManager.SIM_STATE_ABSENT) {
// In this case we will always be STATE_OUT_OF_SERVICE, so need
@@ -3697,8 +3745,8 @@
}
if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
if (mPhoneDataConnectionType != bin) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK)
| (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT);
if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
@@ -3715,8 +3763,8 @@
public void noteWifiOnLocked() {
if (!mWifiOn) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -3728,8 +3776,8 @@
}
public void noteWifiOffLocked() {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mWifiOn) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
@@ -3743,8 +3791,8 @@
public void noteAudioOnLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mAudioOnNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
@@ -3761,8 +3809,8 @@
return;
}
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (--mAudioOnNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
@@ -3775,8 +3823,8 @@
public void noteVideoOnLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mVideoOnNesting == 0) {
mHistoryCur.states2 |= HistoryItem.STATE2_VIDEO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
@@ -3793,8 +3841,8 @@
return;
}
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (--mVideoOnNesting == 0) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
@@ -3807,8 +3855,8 @@
public void noteResetAudioLocked() {
if (mAudioOnNesting > 0) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mAudioOnNesting = 0;
mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
@@ -3824,8 +3872,8 @@
public void noteResetVideoLocked() {
if (mVideoOnNesting > 0) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mAudioOnNesting = 0;
mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
@@ -3841,12 +3889,12 @@
public void noteActivityResumedLocked(int uid) {
uid = mapUid(uid);
- getUidStatsLocked(uid).noteActivityResumedLocked(SystemClock.elapsedRealtime());
+ getUidStatsLocked(uid).noteActivityResumedLocked(mClocks.elapsedRealtime());
}
public void noteActivityPausedLocked(int uid) {
uid = mapUid(uid);
- getUidStatsLocked(uid).noteActivityPausedLocked(SystemClock.elapsedRealtime());
+ getUidStatsLocked(uid).noteActivityPausedLocked(mClocks.elapsedRealtime());
}
public void noteVibratorOnLocked(int uid, long durationMillis) {
@@ -3861,8 +3909,8 @@
public void noteFlashlightOnLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mFlashlightOnNesting++ == 0) {
mHistoryCur.states2 |= HistoryItem.STATE2_FLASHLIGHT_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight on to: "
@@ -3878,8 +3926,8 @@
return;
}
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (--mFlashlightOnNesting == 0) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: "
@@ -3892,8 +3940,8 @@
public void noteCameraOnLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mCameraOnNesting++ == 0) {
mHistoryCur.states2 |= HistoryItem.STATE2_CAMERA_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Camera on to: "
@@ -3909,8 +3957,8 @@
return;
}
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (--mCameraOnNesting == 0) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: "
@@ -3923,8 +3971,8 @@
public void noteResetCameraLocked() {
if (mCameraOnNesting > 0) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mCameraOnNesting = 0;
mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: "
@@ -3940,8 +3988,8 @@
public void noteResetFlashlightLocked() {
if (mFlashlightOnNesting > 0) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mFlashlightOnNesting = 0;
mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: "
@@ -4015,8 +4063,8 @@
}
public void noteWifiRadioPowerState(int powerState, long timestampNs) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mWifiRadioPowerState != powerState) {
final boolean active =
powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
@@ -4035,8 +4083,8 @@
public void noteWifiRunningLocked(WorkSource ws) {
if (!mGlobalWifiRunning) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_RUNNING_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -4056,7 +4104,7 @@
public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
if (mGlobalWifiRunning) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
int N = oldWs.size();
for (int i=0; i<N; i++) {
int uid = mapUid(oldWs.get(i));
@@ -4074,8 +4122,8 @@
public void noteWifiStoppedLocked(WorkSource ws) {
if (mGlobalWifiRunning) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_RUNNING_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -4096,7 +4144,7 @@
public void noteWifiStateLocked(int wifiState, String accessPoint) {
if (DEBUG) Log.i(TAG, "WiFi state -> " + wifiState);
if (mWifiState != wifiState) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
if (mWifiState >= 0) {
mWifiStateTimer[mWifiState].stopRunningLocked(elapsedRealtime);
}
@@ -4109,8 +4157,8 @@
public void noteWifiSupplicantStateChangedLocked(int supplState, boolean failedAuth) {
if (DEBUG) Log.i(TAG, "WiFi suppl state -> " + supplState);
if (mWifiSupplState != supplState) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mWifiSupplState >= 0) {
mWifiSupplStateTimer[mWifiSupplState].stopRunningLocked(elapsedRealtime);
}
@@ -4126,7 +4174,7 @@
}
void stopAllWifiSignalStrengthTimersLocked(int except) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
for (int i = 0; i < NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
if (i == except) {
continue;
@@ -4141,8 +4189,8 @@
int strengthBin = WifiManager.calculateSignalLevel(newRssi, NUM_WIFI_SIGNAL_STRENGTH_BINS);
if (DEBUG) Log.i(TAG, "WiFi rssi -> " + newRssi + " bin=" + strengthBin);
if (mWifiSignalStrengthBin != strengthBin) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mWifiSignalStrengthBin >= 0) {
mWifiSignalStrengthsTimer[mWifiSignalStrengthBin].stopRunningLocked(
elapsedRealtime);
@@ -4168,8 +4216,8 @@
public void noteFullWifiLockAcquiredLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mWifiFullLockNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
@@ -4182,8 +4230,8 @@
public void noteFullWifiLockReleasedLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mWifiFullLockNesting--;
if (mWifiFullLockNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
@@ -4198,8 +4246,8 @@
public void noteWifiScanStartedLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mWifiScanNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan started for: "
@@ -4212,8 +4260,8 @@
public void noteWifiScanStoppedLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mWifiScanNesting--;
if (mWifiScanNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_FLAG;
@@ -4226,13 +4274,13 @@
public void noteWifiBatchedScanStartedLocked(int uid, int csph) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
getUidStatsLocked(uid).noteWifiBatchedScanStartedLocked(csph, elapsedRealtime);
}
public void noteWifiBatchedScanStoppedLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
getUidStatsLocked(uid).noteWifiBatchedScanStoppedLocked(elapsedRealtime);
}
@@ -4240,8 +4288,8 @@
public void noteWifiMulticastEnabledLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mWifiMulticastNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
@@ -4254,8 +4302,8 @@
public void noteWifiMulticastDisabledLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mWifiMulticastNesting--;
if (mWifiMulticastNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
@@ -4369,7 +4417,7 @@
// During device boot, qtaguid isn't enabled until after the inital
// loading of battery stats. Now that they're enabled, take our initial
// snapshot for future delta calculation.
- updateMobileRadioStateLocked(SystemClock.elapsedRealtime(), null);
+ updateMobileRadioStateLocked(mClocks.elapsedRealtime(), null);
updateWifiStateLocked(null);
}
@@ -4623,8 +4671,8 @@
@Override public long getStartClockTime() {
final long currentTime = System.currentTimeMillis();
if (ensureStartClockTime(currentTime)) {
- recordCurrentTimeChangeLocked(currentTime, SystemClock.elapsedRealtime(),
- SystemClock.uptimeMillis());
+ recordCurrentTimeChangeLocked(currentTime, mClocks.elapsedRealtime(),
+ mClocks.uptimeMillis());
}
return mStartClockTime;
}
@@ -4652,7 +4700,11 @@
/**
* The statistics associated with a particular uid.
*/
- public final class Uid extends BatteryStats.Uid {
+ public static class Uid extends BatteryStats.Uid {
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected BatteryStatsImpl mBsi;
final int mUid;
@@ -4717,35 +4769,25 @@
long mCurStepUserTime;
long mCurStepSystemTime;
- LongSamplingCounter mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase);
- LongSamplingCounter mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase);
- LongSamplingCounter mCpuPower = new LongSamplingCounter(mOnBatteryTimeBase);
+ LongSamplingCounter mUserCpuTime;
+ LongSamplingCounter mSystemCpuTime;
+ LongSamplingCounter mCpuPower;
LongSamplingCounter[][] mCpuClusterSpeed;
/**
* The statistics we have collected for this uid's wake locks.
*/
- final OverflowArrayMap<Wakelock> mWakelockStats = new OverflowArrayMap<Wakelock>() {
- @Override public Wakelock instantiateObject() { return new Wakelock(); }
- };
+ final OverflowArrayMap<Wakelock> mWakelockStats;
/**
* The statistics we have collected for this uid's syncs.
*/
- final OverflowArrayMap<StopwatchTimer> mSyncStats = new OverflowArrayMap<StopwatchTimer>() {
- @Override public StopwatchTimer instantiateObject() {
- return new StopwatchTimer(Uid.this, SYNC, null, mOnBatteryTimeBase);
- }
- };
+ final OverflowArrayMap<StopwatchTimer> mSyncStats;
/**
* The statistics we have collected for this uid's jobs.
*/
- final OverflowArrayMap<StopwatchTimer> mJobStats = new OverflowArrayMap<StopwatchTimer>() {
- @Override public StopwatchTimer instantiateObject() {
- return new StopwatchTimer(Uid.this, JOB, null, mOnBatteryTimeBase);
- }
- };
+ final OverflowArrayMap<StopwatchTimer> mJobStats;
/**
* The statistics we have collected for this uid's sensor activations.
@@ -4767,17 +4809,41 @@
*/
final SparseArray<Pid> mPids = new SparseArray<>();
- public Uid(int uid) {
+ public Uid(BatteryStatsImpl bsi, int uid) {
+ mBsi = bsi;
mUid = uid;
- mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
- mWifiRunningTimers, mOnBatteryTimeBase);
- mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
- mFullWifiLockTimers, mOnBatteryTimeBase);
- mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
- mWifiScanTimers, mOnBatteryTimeBase);
+
+ mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+ mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+ mCpuPower = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+
+ mWakelockStats = mBsi.new OverflowArrayMap<Wakelock>() {
+ @Override public Wakelock instantiateObject() {
+ return new Wakelock(mBsi, Uid.this);
+ }
+ };
+ mSyncStats = mBsi.new OverflowArrayMap<StopwatchTimer>() {
+ @Override public StopwatchTimer instantiateObject() {
+ return new StopwatchTimer(mBsi.mClocks, Uid.this, SYNC, null,
+ mBsi.mOnBatteryTimeBase);
+ }
+ };
+ mJobStats = mBsi.new OverflowArrayMap<StopwatchTimer>() {
+ @Override public StopwatchTimer instantiateObject() {
+ return new StopwatchTimer(mBsi.mClocks, Uid.this, JOB, null,
+ mBsi.mOnBatteryTimeBase);
+ }
+ };
+
+ mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_RUNNING,
+ mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase);
+ mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, this, FULL_WIFI_LOCK,
+ mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase);
+ mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_SCAN,
+ mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase);
mWifiBatchedScanTimer = new StopwatchTimer[NUM_WIFI_BATCHED_SCAN_BINS];
- mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
- mWifiMulticastTimers, mOnBatteryTimeBase);
+ mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_MULTICAST_ENABLED,
+ mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase);
mProcessStateTimer = new StopwatchTimer[NUM_PROCESS_STATE];
}
@@ -4821,8 +4887,8 @@
if (!mWifiRunning) {
mWifiRunning = true;
if (mWifiRunningTimer == null) {
- mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
- mWifiRunningTimers, mOnBatteryTimeBase);
+ mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_RUNNING,
+ mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase);
}
mWifiRunningTimer.startRunningLocked(elapsedRealtimeMs);
}
@@ -4841,8 +4907,8 @@
if (!mFullWifiLockOut) {
mFullWifiLockOut = true;
if (mFullWifiLockTimer == null) {
- mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
- mFullWifiLockTimers, mOnBatteryTimeBase);
+ mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, FULL_WIFI_LOCK,
+ mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase);
}
mFullWifiLockTimer.startRunningLocked(elapsedRealtimeMs);
}
@@ -4861,8 +4927,8 @@
if (!mWifiScanStarted) {
mWifiScanStarted = true;
if (mWifiScanTimer == null) {
- mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
- mWifiScanTimers, mOnBatteryTimeBase);
+ mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_SCAN,
+ mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase);
}
mWifiScanTimer.startRunningLocked(elapsedRealtimeMs);
}
@@ -4911,8 +4977,8 @@
if (!mWifiMulticastEnabled) {
mWifiMulticastEnabled = true;
if (mWifiMulticastTimer == null) {
- mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
- mWifiMulticastTimers, mOnBatteryTimeBase);
+ mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ WIFI_MULTICAST_ENABLED, mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase);
}
mWifiMulticastTimer.startRunningLocked(elapsedRealtimeMs);
}
@@ -4943,7 +5009,7 @@
public ControllerActivityCounterImpl getOrCreateWifiControllerActivityLocked() {
if (mWifiControllerActivity == null) {
- mWifiControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mWifiControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
NUM_BT_TX_LEVELS);
}
return mWifiControllerActivity;
@@ -4951,7 +5017,7 @@
public ControllerActivityCounterImpl getOrCreateBluetoothControllerActivityLocked() {
if (mBluetoothControllerActivity == null) {
- mBluetoothControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mBluetoothControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
NUM_BT_TX_LEVELS);
}
return mBluetoothControllerActivity;
@@ -4959,7 +5025,7 @@
public ControllerActivityCounterImpl getOrCreateModemControllerActivityLocked() {
if (mModemControllerActivity == null) {
- mModemControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
ModemActivityInfo.TX_POWER_LEVELS);
}
return mModemControllerActivity;
@@ -4967,8 +5033,8 @@
public StopwatchTimer createAudioTurnedOnTimerLocked() {
if (mAudioTurnedOnTimer == null) {
- mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
- mAudioTurnedOnTimers, mOnBatteryTimeBase);
+ mAudioTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, AUDIO_TURNED_ON,
+ mBsi.mAudioTurnedOnTimers, mBsi.mOnBatteryTimeBase);
}
return mAudioTurnedOnTimer;
}
@@ -4991,8 +5057,8 @@
public StopwatchTimer createVideoTurnedOnTimerLocked() {
if (mVideoTurnedOnTimer == null) {
- mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
- mVideoTurnedOnTimers, mOnBatteryTimeBase);
+ mVideoTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, VIDEO_TURNED_ON,
+ mBsi.mVideoTurnedOnTimers, mBsi.mOnBatteryTimeBase);
}
return mVideoTurnedOnTimer;
}
@@ -5015,8 +5081,8 @@
public StopwatchTimer createFlashlightTurnedOnTimerLocked() {
if (mFlashlightTurnedOnTimer == null) {
- mFlashlightTurnedOnTimer = new StopwatchTimer(Uid.this, FLASHLIGHT_TURNED_ON,
- mFlashlightTurnedOnTimers, mOnBatteryTimeBase);
+ mFlashlightTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ FLASHLIGHT_TURNED_ON, mBsi.mFlashlightTurnedOnTimers, mBsi.mOnBatteryTimeBase);
}
return mFlashlightTurnedOnTimer;
}
@@ -5039,8 +5105,8 @@
public StopwatchTimer createCameraTurnedOnTimerLocked() {
if (mCameraTurnedOnTimer == null) {
- mCameraTurnedOnTimer = new StopwatchTimer(Uid.this, CAMERA_TURNED_ON,
- mCameraTurnedOnTimers, mOnBatteryTimeBase);
+ mCameraTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, CAMERA_TURNED_ON,
+ mBsi.mCameraTurnedOnTimers, mBsi.mOnBatteryTimeBase);
}
return mCameraTurnedOnTimer;
}
@@ -5063,16 +5129,16 @@
public StopwatchTimer createForegroundActivityTimerLocked() {
if (mForegroundActivityTimer == null) {
- mForegroundActivityTimer = new StopwatchTimer(
- Uid.this, FOREGROUND_ACTIVITY, null, mOnBatteryTimeBase);
+ mForegroundActivityTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ FOREGROUND_ACTIVITY, null, mBsi.mOnBatteryTimeBase);
}
return mForegroundActivityTimer;
}
public StopwatchTimer createBluetoothScanTimerLocked() {
if (mBluetoothScanTimer == null) {
- mBluetoothScanTimer = new StopwatchTimer(Uid.this, BLUETOOTH_SCAN_ON,
- mBluetoothScanOnTimers, mOnBatteryTimeBase);
+ mBluetoothScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON,
+ mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase);
}
return mBluetoothScanTimer;
}
@@ -5108,18 +5174,19 @@
public BatchTimer createVibratorOnTimerLocked() {
if (mVibratorOnTimer == null) {
- mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON, mOnBatteryTimeBase);
+ mVibratorOnTimer = new BatchTimer(mBsi.mClocks, Uid.this, VIBRATOR_ON,
+ mBsi.mOnBatteryTimeBase);
}
return mVibratorOnTimer;
}
public void noteVibratorOnLocked(long durationMillis) {
- createVibratorOnTimerLocked().addDuration(BatteryStatsImpl.this, durationMillis);
+ createVibratorOnTimerLocked().addDuration(mBsi, durationMillis);
}
public void noteVibratorOffLocked() {
if (mVibratorOnTimer != null) {
- mVibratorOnTimer.abortLastDuration(BatteryStatsImpl.this);
+ mVibratorOnTimer.abortLastDuration(mBsi);
}
}
@@ -5215,11 +5282,11 @@
if (i < 0 || i >= NUM_PROCESS_STATE) return;
if (in == null) {
- mProcessStateTimer[i] = new StopwatchTimer(this, PROCESS_STATE, null,
- mOnBatteryTimeBase);
+ mProcessStateTimer[i] = new StopwatchTimer(mBsi.mClocks, this, PROCESS_STATE, null,
+ mBsi.mOnBatteryTimeBase);
} else {
- mProcessStateTimer[i] = new StopwatchTimer(this, PROCESS_STATE, null,
- mOnBatteryTimeBase, in);
+ mProcessStateTimer[i] = new StopwatchTimer(mBsi.mClocks, this, PROCESS_STATE, null,
+ mBsi.mOnBatteryTimeBase, in);
}
}
@@ -5266,17 +5333,17 @@
void makeWifiBatchedScanBin(int i, Parcel in) {
if (i < 0 || i >= NUM_WIFI_BATCHED_SCAN_BINS) return;
- ArrayList<StopwatchTimer> collected = mWifiBatchedScanTimers.get(i);
+ ArrayList<StopwatchTimer> collected = mBsi.mWifiBatchedScanTimers.get(i);
if (collected == null) {
collected = new ArrayList<StopwatchTimer>();
- mWifiBatchedScanTimers.put(i, collected);
+ mBsi.mWifiBatchedScanTimers.put(i, collected);
}
if (in == null) {
- mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
- mOnBatteryTimeBase);
+ mWifiBatchedScanTimer[i] = new StopwatchTimer(mBsi.mClocks, this, WIFI_BATCHED_SCAN,
+ collected, mBsi.mOnBatteryTimeBase);
} else {
- mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
- mOnBatteryTimeBase, in);
+ mWifiBatchedScanTimer[i] = new StopwatchTimer(mBsi.mClocks, this, WIFI_BATCHED_SCAN,
+ collected, mBsi.mOnBatteryTimeBase, in);
}
}
@@ -5284,7 +5351,7 @@
void initUserActivityLocked() {
mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
- mUserActivityCounters[i] = new Counter(mOnBatteryTimeBase);
+ mUserActivityCounters[i] = new Counter(mBsi.mOnBatteryTimeBase);
}
}
@@ -5383,11 +5450,11 @@
mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
mNetworkPacketActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
- mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
- mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
+ mNetworkByteActivityCounters[i] = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+ mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
}
- mMobileRadioActiveTime = new LongSamplingCounter(mOnBatteryTimeBase);
- mMobileRadioActiveCount = new LongSamplingCounter(mOnBatteryTimeBase);
+ mMobileRadioActiveTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+ mMobileRadioActiveCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
}
/**
@@ -5475,12 +5542,12 @@
mWifiControllerActivity.reset(false);
}
- if (mBluetoothActivity != null) {
- mBluetoothActivity.reset(false);
+ if (mBsi.mBluetoothActivity != null) {
+ mBsi.mBluetoothActivity.reset(false);
}
- if (mModemActivity != null) {
- mModemActivity.reset(false);
+ if (mBsi.mModemActivity != null) {
+ mBsi.mModemActivity.reset(false);
}
mUserCpuTime.reset(false);
@@ -5871,7 +5938,7 @@
mWakelockStats.clear();
for (int j = 0; j < numWakelocks; j++) {
String wakelockName = in.readString();
- Uid.Wakelock wakelock = new Wakelock();
+ Uid.Wakelock wakelock = new Wakelock(mBsi, this);
wakelock.readFromParcelLocked(timeBase, screenOffTimeBase, in);
mWakelockStats.add(wakelockName, wakelock);
}
@@ -5882,7 +5949,7 @@
String syncName = in.readString();
if (in.readInt() != 0) {
mSyncStats.add(syncName,
- new StopwatchTimer(Uid.this, SYNC, null, timeBase, in));
+ new StopwatchTimer(mBsi.mClocks, Uid.this, SYNC, null, timeBase, in));
}
}
@@ -5891,7 +5958,8 @@
for (int j = 0; j < numJobs; j++) {
String jobName = in.readString();
if (in.readInt() != 0) {
- mJobStats.add(jobName, new StopwatchTimer(Uid.this, JOB, null, timeBase, in));
+ mJobStats.add(jobName, new StopwatchTimer(mBsi.mClocks, Uid.this, JOB, null,
+ timeBase, in));
}
}
@@ -5899,8 +5967,8 @@
mSensorStats.clear();
for (int k = 0; k < numSensors; k++) {
int sensorNumber = in.readInt();
- Uid.Sensor sensor = new Sensor(sensorNumber);
- sensor.readFromParcelLocked(mOnBatteryTimeBase, in);
+ Uid.Sensor sensor = new Sensor(mBsi, this, sensorNumber);
+ sensor.readFromParcelLocked(mBsi.mOnBatteryTimeBase, in);
mSensorStats.put(sensorNumber, sensor);
}
@@ -5908,7 +5976,7 @@
mProcessStats.clear();
for (int k = 0; k < numProcs; k++) {
String processName = in.readString();
- Uid.Proc proc = new Proc(processName);
+ Uid.Proc proc = new Proc(mBsi, processName);
proc.readFromParcelLocked(in);
mProcessStats.put(processName, proc);
}
@@ -5917,29 +5985,29 @@
mPackageStats.clear();
for (int l = 0; l < numPkgs; l++) {
String packageName = in.readString();
- Uid.Pkg pkg = new Pkg();
+ Uid.Pkg pkg = new Pkg(mBsi);
pkg.readFromParcelLocked(in);
mPackageStats.put(packageName, pkg);
}
mWifiRunning = false;
if (in.readInt() != 0) {
- mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
- mWifiRunningTimers, mOnBatteryTimeBase, in);
+ mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_RUNNING,
+ mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mWifiRunningTimer = null;
}
mFullWifiLockOut = false;
if (in.readInt() != 0) {
- mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
- mFullWifiLockTimers, mOnBatteryTimeBase, in);
+ mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, FULL_WIFI_LOCK,
+ mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mFullWifiLockTimer = null;
}
mWifiScanStarted = false;
if (in.readInt() != 0) {
- mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
- mWifiScanTimers, mOnBatteryTimeBase, in);
+ mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_SCAN,
+ mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mWifiScanTimer = null;
}
@@ -5953,44 +6021,44 @@
}
mWifiMulticastEnabled = false;
if (in.readInt() != 0) {
- mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
- mWifiMulticastTimers, mOnBatteryTimeBase, in);
+ mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_MULTICAST_ENABLED,
+ mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mWifiMulticastTimer = null;
}
if (in.readInt() != 0) {
- mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
- mAudioTurnedOnTimers, mOnBatteryTimeBase, in);
+ mAudioTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, AUDIO_TURNED_ON,
+ mBsi.mAudioTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mAudioTurnedOnTimer = null;
}
if (in.readInt() != 0) {
- mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
- mVideoTurnedOnTimers, mOnBatteryTimeBase, in);
+ mVideoTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, VIDEO_TURNED_ON,
+ mBsi.mVideoTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mVideoTurnedOnTimer = null;
}
if (in.readInt() != 0) {
- mFlashlightTurnedOnTimer = new StopwatchTimer(Uid.this, FLASHLIGHT_TURNED_ON,
- mFlashlightTurnedOnTimers, mOnBatteryTimeBase, in);
+ mFlashlightTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ FLASHLIGHT_TURNED_ON, mBsi.mFlashlightTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mFlashlightTurnedOnTimer = null;
}
if (in.readInt() != 0) {
- mCameraTurnedOnTimer = new StopwatchTimer(Uid.this, CAMERA_TURNED_ON,
- mCameraTurnedOnTimers, mOnBatteryTimeBase, in);
+ mCameraTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, CAMERA_TURNED_ON,
+ mBsi.mCameraTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mCameraTurnedOnTimer = null;
}
if (in.readInt() != 0) {
- mForegroundActivityTimer = new StopwatchTimer(
- Uid.this, FOREGROUND_ACTIVITY, null, mOnBatteryTimeBase, in);
+ mForegroundActivityTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ FOREGROUND_ACTIVITY, null, mBsi.mOnBatteryTimeBase, in);
} else {
mForegroundActivityTimer = null;
}
if (in.readInt() != 0) {
- mBluetoothScanTimer = new StopwatchTimer(Uid.this, BLUETOOTH_SCAN_ON,
- mBluetoothScanOnTimers, mOnBatteryTimeBase, in);
+ mBluetoothScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON,
+ mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mBluetoothScanTimer = null;
}
@@ -6003,14 +6071,15 @@
}
}
if (in.readInt() != 0) {
- mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON, mOnBatteryTimeBase, in);
+ mVibratorOnTimer = new BatchTimer(mBsi.mClocks, Uid.this, VIBRATOR_ON,
+ mBsi.mOnBatteryTimeBase, in);
} else {
mVibratorOnTimer = null;
}
if (in.readInt() != 0) {
mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
- mUserActivityCounters[i] = new Counter(mOnBatteryTimeBase, in);
+ mUserActivityCounters[i] = new Counter(mBsi.mOnBatteryTimeBase, in);
}
} else {
mUserActivityCounters = null;
@@ -6021,45 +6090,45 @@
= new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i]
- = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
mNetworkPacketActivityCounters[i]
- = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
}
- mMobileRadioActiveTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
- mMobileRadioActiveCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ mMobileRadioActiveTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
+ mMobileRadioActiveCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
} else {
mNetworkByteActivityCounters = null;
mNetworkPacketActivityCounters = null;
}
if (in.readInt() != 0) {
- mWifiControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mWifiControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
NUM_WIFI_TX_LEVELS, in);
} else {
mWifiControllerActivity = null;
}
if (in.readInt() != 0) {
- mBluetoothControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mBluetoothControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
NUM_BT_TX_LEVELS, in);
} else {
mBluetoothControllerActivity = null;
}
if (in.readInt() != 0) {
- mModemControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
ModemActivityInfo.TX_POWER_LEVELS, in);
} else {
mModemControllerActivity = null;
}
- mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
- mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
- mCpuPower = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
+ mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
+ mCpuPower = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
if (in.readInt() != 0) {
int numCpuClusters = in.readInt();
- if (mPowerProfile != null && mPowerProfile.getNumCpuClusters() != numCpuClusters) {
+ if (mBsi.mPowerProfile != null && mBsi.mPowerProfile.getNumCpuClusters() != numCpuClusters) {
throw new ParcelFormatException("Incompatible number of cpu clusters");
}
@@ -6067,8 +6136,8 @@
for (int cluster = 0; cluster < numCpuClusters; cluster++) {
if (in.readInt() != 0) {
int numSpeeds = in.readInt();
- if (mPowerProfile != null &&
- mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
+ if (mBsi.mPowerProfile != null &&
+ mBsi.mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
throw new ParcelFormatException("Incompatible number of cpu speeds");
}
@@ -6076,7 +6145,7 @@
mCpuClusterSpeed[cluster] = cpuSpeeds;
for (int speed = 0; speed < numSpeeds; speed++) {
if (in.readInt() != 0) {
- cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ cpuSpeeds[speed] = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
}
}
} else {
@@ -6091,7 +6160,17 @@
/**
* The statistics associated with a particular wake lock.
*/
- public final class Wakelock extends BatteryStats.Uid.Wakelock {
+ public static class Wakelock extends BatteryStats.Uid.Wakelock {
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected BatteryStatsImpl mBsi;
+
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected Uid mUid;
+
/**
* How long (in ms) this uid has been keeping the device partially awake.
*/
@@ -6112,6 +6191,11 @@
*/
StopwatchTimer mTimerDraw;
+ public Wakelock(BatteryStatsImpl bsi, Uid uid) {
+ mBsi = bsi;
+ mUid = uid;
+ }
+
/**
* Reads a possibly null Timer from a Parcel. The timer is associated with the
* proper timer pool from the given BatteryStatsImpl object.
@@ -6125,7 +6209,7 @@
return null;
}
- return new StopwatchTimer(Uid.this, type, pool, timeBase, in);
+ return new StopwatchTimer(mBsi.mClocks, mUid, type, pool, timeBase, in);
}
boolean reset() {
@@ -6165,10 +6249,10 @@
void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
- mPartialTimers, screenOffTimeBase, in);
- mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL, mFullTimers, timeBase, in);
- mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW, mWindowTimers, timeBase, in);
- mTimerDraw = readTimerFromParcel(WAKE_TYPE_DRAW, mDrawTimers, timeBase, in);
+ mBsi.mPartialTimers, screenOffTimeBase, in);
+ mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL, mBsi.mFullTimers, timeBase, in);
+ mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW, mBsi.mWindowTimers, timeBase, in);
+ mTimerDraw = readTimerFromParcel(WAKE_TYPE_DRAW, mBsi.mDrawTimers, timeBase, in);
}
void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
@@ -6195,32 +6279,32 @@
case WAKE_TYPE_PARTIAL:
t = mTimerPartial;
if (t == null) {
- t = new StopwatchTimer(Uid.this, WAKE_TYPE_PARTIAL,
- mPartialTimers, mOnBatteryScreenOffTimeBase);
+ t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_PARTIAL,
+ mBsi.mPartialTimers, mBsi.mOnBatteryScreenOffTimeBase);
mTimerPartial = t;
}
return t;
case WAKE_TYPE_FULL:
t = mTimerFull;
if (t == null) {
- t = new StopwatchTimer(Uid.this, WAKE_TYPE_FULL,
- mFullTimers, mOnBatteryTimeBase);
+ t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_FULL,
+ mBsi.mFullTimers, mBsi.mOnBatteryTimeBase);
mTimerFull = t;
}
return t;
case WAKE_TYPE_WINDOW:
t = mTimerWindow;
if (t == null) {
- t = new StopwatchTimer(Uid.this, WAKE_TYPE_WINDOW,
- mWindowTimers, mOnBatteryTimeBase);
+ t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_WINDOW,
+ mBsi.mWindowTimers, mBsi.mOnBatteryTimeBase);
mTimerWindow = t;
}
return t;
case WAKE_TYPE_DRAW:
t = mTimerDraw;
if (t == null) {
- t = new StopwatchTimer(Uid.this, WAKE_TYPE_DRAW,
- mDrawTimers, mOnBatteryTimeBase);
+ t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_DRAW,
+ mBsi.mDrawTimers, mBsi.mOnBatteryTimeBase);
mTimerDraw = t;
}
return t;
@@ -6230,11 +6314,23 @@
}
}
- public final class Sensor extends BatteryStats.Uid.Sensor {
+ public static class Sensor extends BatteryStats.Uid.Sensor {
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected BatteryStatsImpl mBsi;
+
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected Uid mUid;
+
final int mHandle;
StopwatchTimer mTimer;
- public Sensor(int handle) {
+ public Sensor(BatteryStatsImpl bsi, Uid uid, int handle) {
+ mBsi = bsi;
+ mUid = uid;
mHandle = handle;
}
@@ -6243,12 +6339,12 @@
return null;
}
- ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
+ ArrayList<StopwatchTimer> pool = mBsi.mSensorTimers.get(mHandle);
if (pool == null) {
pool = new ArrayList<StopwatchTimer>();
- mSensorTimers.put(mHandle, pool);
+ mBsi.mSensorTimers.put(mHandle, pool);
}
- return new StopwatchTimer(Uid.this, 0, pool, timeBase, in);
+ return new StopwatchTimer(mBsi.mClocks, mUid, 0, pool, timeBase, in);
}
boolean reset() {
@@ -6281,7 +6377,12 @@
/**
* The statistics associated with a particular process.
*/
- public final class Proc extends BatteryStats.Uid.Proc implements TimeBaseObs {
+ public static class Proc extends BatteryStats.Uid.Proc implements TimeBaseObs {
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected BatteryStatsImpl mBsi;
+
/**
* The name of this process.
*/
@@ -6384,9 +6485,10 @@
ArrayList<ExcessivePower> mExcessivePower;
- Proc(String name) {
+ public Proc(BatteryStatsImpl bsi, String name) {
+ mBsi = bsi;
mName = name;
- mOnBatteryTimeBase.add(this);
+ mBsi.mOnBatteryTimeBase.add(this);
}
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
@@ -6403,7 +6505,7 @@
void detach() {
mActive = false;
- mOnBatteryTimeBase.remove(this);
+ mBsi.mOnBatteryTimeBase.remove(this);
}
public int countExcessivePowers() {
@@ -6617,7 +6719,12 @@
/**
* The statistics associated with a particular package.
*/
- public final class Pkg extends BatteryStats.Uid.Pkg implements TimeBaseObs {
+ public static class Pkg extends BatteryStats.Uid.Pkg implements TimeBaseObs {
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected BatteryStatsImpl mBsi;
+
/**
* Number of times wakeup alarms have occurred for this app.
*/
@@ -6628,8 +6735,9 @@
*/
final ArrayMap<String, Serv> mServiceStats = new ArrayMap<>();
- Pkg() {
- mOnBatteryScreenOffTimeBase.add(this);
+ public Pkg(BatteryStatsImpl bsi) {
+ mBsi = bsi;
+ mBsi.mOnBatteryScreenOffTimeBase.add(this);
}
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
@@ -6639,7 +6747,7 @@
}
void detach() {
- mOnBatteryScreenOffTimeBase.remove(this);
+ mBsi.mOnBatteryScreenOffTimeBase.remove(this);
}
void readFromParcelLocked(Parcel in) {
@@ -6647,14 +6755,14 @@
mWakeupAlarms.clear();
for (int i=0; i<numWA; i++) {
String tag = in.readString();
- mWakeupAlarms.put(tag, new Counter(mOnBatteryTimeBase, in));
+ mWakeupAlarms.put(tag, new Counter(mBsi.mOnBatteryTimeBase, in));
}
int numServs = in.readInt();
mServiceStats.clear();
for (int m = 0; m < numServs; m++) {
String serviceName = in.readString();
- Uid.Pkg.Serv serv = new Serv();
+ Uid.Pkg.Serv serv = new Serv(mBsi);
mServiceStats.put(serviceName, serv);
serv.readFromParcelLocked(in);
@@ -6686,7 +6794,7 @@
public void noteWakeupAlarmLocked(String tag) {
Counter c = mWakeupAlarms.get(tag);
if (c == null) {
- c = new Counter(mOnBatteryTimeBase);
+ c = new Counter(mBsi.mOnBatteryTimeBase);
mWakeupAlarms.put(tag, c);
}
c.stepAtomic();
@@ -6700,99 +6808,113 @@
/**
* The statistics associated with a particular service.
*/
- public final class Serv extends BatteryStats.Uid.Pkg.Serv implements TimeBaseObs {
+ public static class Serv extends BatteryStats.Uid.Pkg.Serv implements TimeBaseObs {
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected BatteryStatsImpl mBsi;
+
+ /**
+ * The android package in which this service resides.
+ */
+ protected Pkg mPkg;
+
/**
* Total time (ms in battery uptime) the service has been left started.
*/
- long mStartTime;
+ protected long mStartTime;
/**
* If service has been started and not yet stopped, this is
* when it was started.
*/
- long mRunningSince;
+ protected long mRunningSince;
/**
* True if we are currently running.
*/
- boolean mRunning;
+ protected boolean mRunning;
/**
* Total number of times startService() has been called.
*/
- int mStarts;
+ protected int mStarts;
/**
* Total time (ms in battery uptime) the service has been left launched.
*/
- long mLaunchedTime;
+ protected long mLaunchedTime;
/**
* If service has been launched and not yet exited, this is
* when it was launched (ms in battery uptime).
*/
- long mLaunchedSince;
+ protected long mLaunchedSince;
/**
* True if we are currently launched.
*/
- boolean mLaunched;
+ protected boolean mLaunched;
/**
* Total number times the service has been launched.
*/
- int mLaunches;
+ protected int mLaunches;
/**
* The amount of time spent started loaded from a previous save
* (ms in battery uptime).
*/
- long mLoadedStartTime;
+ protected long mLoadedStartTime;
/**
* The number of starts loaded from a previous save.
*/
- int mLoadedStarts;
+ protected int mLoadedStarts;
/**
* The number of launches loaded from a previous save.
*/
- int mLoadedLaunches;
+ protected int mLoadedLaunches;
/**
* The amount of time spent started as of the last run (ms
* in battery uptime).
*/
- long mLastStartTime;
+ protected long mLastStartTime;
/**
* The number of starts as of the last run.
*/
- int mLastStarts;
+ protected int mLastStarts;
/**
* The number of launches as of the last run.
*/
- int mLastLaunches;
+ protected int mLastLaunches;
/**
* The amount of time spent started when last unplugged (ms
* in battery uptime).
*/
- long mUnpluggedStartTime;
+ protected long mUnpluggedStartTime;
/**
* The number of starts when last unplugged.
*/
- int mUnpluggedStarts;
+ protected int mUnpluggedStarts;
/**
* The number of launches when last unplugged.
*/
- int mUnpluggedLaunches;
+ protected int mUnpluggedLaunches;
- Serv() {
- mOnBatteryTimeBase.add(this);
+ /**
+ * Construct a Serv. Also adds it to the on-battery time base as a listener.
+ */
+ public Serv(BatteryStatsImpl bsi) {
+ mBsi = bsi;
+ mBsi.mOnBatteryTimeBase.add(this);
}
public void onTimeStarted(long elapsedRealtime, long baseUptime,
@@ -6806,11 +6928,14 @@
long baseRealtime) {
}
- void detach() {
- mOnBatteryTimeBase.remove(this);
+ /**
+ * Remove this Serv as a listener from the time base.
+ */
+ public void detach() {
+ mBsi.mOnBatteryTimeBase.remove(this);
}
- void readFromParcelLocked(Parcel in) {
+ public void readFromParcelLocked(Parcel in) {
mStartTime = in.readLong();
mRunningSince = in.readLong();
mRunning = in.readInt() != 0;
@@ -6830,7 +6955,7 @@
mUnpluggedLaunches = in.readInt();
}
- void writeToParcelLocked(Parcel out) {
+ public void writeToParcelLocked(Parcel out) {
out.writeLong(mStartTime);
out.writeLong(mRunningSince);
out.writeInt(mRunning ? 1 : 0);
@@ -6847,12 +6972,12 @@
out.writeInt(mUnpluggedLaunches);
}
- long getLaunchTimeToNowLocked(long batteryUptime) {
+ public long getLaunchTimeToNowLocked(long batteryUptime) {
if (!mLaunched) return mLaunchedTime;
return mLaunchedTime + batteryUptime - mLaunchedSince;
}
- long getStartTimeToNowLocked(long batteryUptime) {
+ public long getStartTimeToNowLocked(long batteryUptime) {
if (!mRunning) return mStartTime;
return mStartTime + batteryUptime - mRunningSince;
}
@@ -6860,14 +6985,14 @@
public void startLaunchedLocked() {
if (!mLaunched) {
mLaunches++;
- mLaunchedSince = getBatteryUptimeLocked();
+ mLaunchedSince = mBsi.getBatteryUptimeLocked();
mLaunched = true;
}
}
public void stopLaunchedLocked() {
if (mLaunched) {
- long time = getBatteryUptimeLocked() - mLaunchedSince;
+ long time = mBsi.getBatteryUptimeLocked() - mLaunchedSince;
if (time > 0) {
mLaunchedTime += time;
} else {
@@ -6880,14 +7005,14 @@
public void startRunningLocked() {
if (!mRunning) {
mStarts++;
- mRunningSince = getBatteryUptimeLocked();
+ mRunningSince = mBsi.getBatteryUptimeLocked();
mRunning = true;
}
}
public void stopRunningLocked() {
if (mRunning) {
- long time = getBatteryUptimeLocked() - mRunningSince;
+ long time = mBsi.getBatteryUptimeLocked() - mRunningSince;
if (time > 0) {
mStartTime += time;
} else {
@@ -6898,7 +7023,7 @@
}
public BatteryStatsImpl getBatteryStats() {
- return BatteryStatsImpl.this;
+ return mBsi;
}
@Override
@@ -6937,7 +7062,7 @@
}
final Serv newServiceStatsLocked() {
- return new Serv();
+ return new Serv(mBsi);
}
}
@@ -6948,7 +7073,7 @@
public Proc getProcessStatsLocked(String name) {
Proc ps = mProcessStats.get(name);
if (ps == null) {
- ps = new Proc(name);
+ ps = new Proc(mBsi, name);
mProcessStats.put(name, ps);
}
@@ -6977,7 +7102,7 @@
if (mProcessState == uidRunningState) return;
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mBsi.mClocks.elapsedRealtime();
if (mProcessState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
mProcessStateTimer[mProcessState].stopRunningLocked(elapsedRealtime);
@@ -7011,7 +7136,7 @@
public Pkg getPackageStatsLocked(String name) {
Pkg ps = mPackageStats.get(name);
if (ps == null) {
- ps = new Pkg();
+ ps = new Pkg(mBsi);
mPackageStats.put(name, ps);
}
@@ -7046,7 +7171,7 @@
}
public void readWakeSummaryFromParcelLocked(String wlName, Parcel in) {
- Wakelock wl = new Wakelock();
+ Wakelock wl = new Wakelock(mBsi, this);
mWakelockStats.add(wlName, wl);
if (in.readInt() != 0) {
wl.getStopwatchTimer(WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
@@ -7068,19 +7193,20 @@
if (!create) {
return null;
}
- se = new Sensor(sensor);
+ se = new Sensor(mBsi, this, sensor);
mSensorStats.put(sensor, se);
}
StopwatchTimer t = se.mTimer;
if (t != null) {
return t;
}
- ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
+ ArrayList<StopwatchTimer> timers = mBsi.mSensorTimers.get(sensor);
if (timers == null) {
timers = new ArrayList<StopwatchTimer>();
- mSensorTimers.put(sensor, timers);
+ mBsi.mSensorTimers.put(sensor, timers);
}
- t = new StopwatchTimer(Uid.this, BatteryStats.SENSOR, timers, mOnBatteryTimeBase);
+ t = new StopwatchTimer(mBsi.mClocks, this, BatteryStats.SENSOR, timers,
+ mBsi.mOnBatteryTimeBase);
se.mTimer = t;
return t;
}
@@ -7186,11 +7312,18 @@
}
public BatteryStatsImpl getBatteryStats() {
- return BatteryStatsImpl.this;
+ return mBsi;
}
}
public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) {
+ this(new SystemClocks(), systemDir, handler, externalSync);
+ }
+
+ public BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
+ ExternalStatsSync externalSync) {
+ init(clocks);
+
if (systemDir != null) {
mFile = new JournaledFile(new File(systemDir, "batterystats.bin"),
new File(systemDir, "batterystats.bin.tmp"));
@@ -7202,24 +7335,28 @@
mExternalSync = externalSync;
mHandler = new MyHandler(handler.getLooper());
mStartCount++;
- mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase);
+ mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
- mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase);
- }
- mInteractiveTimer = new StopwatchTimer(null, -10, null, mOnBatteryTimeBase);
- mPowerSaveModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase);
- mDeviceIdleModeLightTimer = new StopwatchTimer(null, -11, null, mOnBatteryTimeBase);
- mDeviceIdleModeFullTimer = new StopwatchTimer(null, -14, null, mOnBatteryTimeBase);
- mDeviceLightIdlingTimer = new StopwatchTimer(null, -15, null, mOnBatteryTimeBase);
- mDeviceIdlingTimer = new StopwatchTimer(null, -12, null, mOnBatteryTimeBase);
- mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase);
- for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
- mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null,
+ mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
mOnBatteryTimeBase);
}
- mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mOnBatteryTimeBase);
+ mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase);
+ mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null,
+ mOnBatteryTimeBase);
+ mDeviceIdleModeLightTimer = new StopwatchTimer(mClocks, null, -11, null,
+ mOnBatteryTimeBase);
+ mDeviceIdleModeFullTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
+ mDeviceLightIdlingTimer = new StopwatchTimer(mClocks, null, -15, null, mOnBatteryTimeBase);
+ mDeviceIdlingTimer = new StopwatchTimer(mClocks, null, -12, null, mOnBatteryTimeBase);
+ mPhoneOnTimer = new StopwatchTimer(mClocks, null, -3, null, mOnBatteryTimeBase);
+ for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
+ mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -200-i, null,
+ mOnBatteryTimeBase);
+ }
+ mPhoneSignalScanningTimer = new StopwatchTimer(mClocks, null, -200+1, null,
+ mOnBatteryTimeBase);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
- mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null,
+ mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClocks, null, -300-i, null,
mOnBatteryTimeBase);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
@@ -7232,31 +7369,34 @@
mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
ModemActivityInfo.TX_POWER_LEVELS);
- mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase);
- mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase);
+ mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null, mOnBatteryTimeBase);
+ mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
+ mOnBatteryTimeBase);
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase);
- mWifiOnTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase);
- mGlobalWifiRunningTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase);
+ mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase);
+ mGlobalWifiRunningTimer = new StopwatchTimer(mClocks, null, -5, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_WIFI_STATES; i++) {
- mWifiStateTimer[i] = new StopwatchTimer(null, -600-i, null, mOnBatteryTimeBase);
- }
- for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
- mWifiSupplStateTimer[i] = new StopwatchTimer(null, -700-i, null, mOnBatteryTimeBase);
- }
- for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
- mWifiSignalStrengthsTimer[i] = new StopwatchTimer(null, -800-i, null,
+ mWifiStateTimer[i] = new StopwatchTimer(mClocks, null, -600-i, null,
mOnBatteryTimeBase);
}
- mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
- mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
- mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase);
- mCameraOnTimer = new StopwatchTimer(null, -13, null, mOnBatteryTimeBase);
- mBluetoothScanTimer = new StopwatchTimer(null, -14, null, mOnBatteryTimeBase);
+ for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+ mWifiSupplStateTimer[i] = new StopwatchTimer(mClocks, null, -700-i, null,
+ mOnBatteryTimeBase);
+ }
+ for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+ mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i, null,
+ mOnBatteryTimeBase);
+ }
+ mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
+ mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
+ mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase);
+ mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase);
+ mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
mOnBattery = mOnBatteryInternal = false;
- long uptime = SystemClock.uptimeMillis() * 1000;
- long realtime = SystemClock.elapsedRealtime() * 1000;
+ long uptime = mClocks.uptimeMillis() * 1000;
+ long realtime = mClocks.elapsedRealtime() * 1000;
initTimes(uptime, realtime);
mStartPlatformVersion = mEndPlatformVersion = Build.ID;
mDischargeStartLevel = 0;
@@ -7270,6 +7410,11 @@
}
public BatteryStatsImpl(Parcel p) {
+ this(new SystemClocks(), p);
+ }
+
+ public BatteryStatsImpl(Clocks clocks, Parcel p) {
+ init(clocks);
mFile = null;
mCheckinFile = null;
mDailyFile = null;
@@ -7808,9 +7953,9 @@
public void resetAllStatsCmdLocked() {
resetAllStatsLocked();
- final long mSecUptime = SystemClock.uptimeMillis();
+ final long mSecUptime = mClocks.uptimeMillis();
long uptime = mSecUptime * 1000;
- long mSecRealtime = SystemClock.elapsedRealtime();
+ long mSecRealtime = mClocks.elapsedRealtime();
long realtime = mSecRealtime * 1000;
mDischargeStartLevel = mHistoryCur.batteryLevel;
pullPendingStateUpdatesLocked();
@@ -7835,7 +7980,7 @@
private void resetAllStatsLocked() {
mStartCount = 0;
- initTimes(SystemClock.uptimeMillis() * 1000, SystemClock.elapsedRealtime() * 1000);
+ initTimes(mClocks.uptimeMillis() * 1000, mClocks.elapsedRealtime() * 1000);
mScreenOnTimer.reset(false);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].reset(false);
@@ -7983,17 +8128,8 @@
private static final int NETWORK_STATS_NEXT = 1;
private static final int NETWORK_STATS_DELTA = 2;
- private final NetworkStats[] mMobileNetworkStats = new NetworkStats[] {
- new NetworkStats(SystemClock.elapsedRealtime(), 50),
- new NetworkStats(SystemClock.elapsedRealtime(), 50),
- new NetworkStats(SystemClock.elapsedRealtime(), 50)
- };
-
- private final NetworkStats[] mWifiNetworkStats = new NetworkStats[] {
- new NetworkStats(SystemClock.elapsedRealtime(), 50),
- new NetworkStats(SystemClock.elapsedRealtime(), 50),
- new NetworkStats(SystemClock.elapsedRealtime(), 50)
- };
+ private NetworkStats[] mMobileNetworkStats;
+ private NetworkStats[] mWifiNetworkStats;
/**
* Retrieves the delta of network stats for the given network ifaces. Uses networkStatsBuffer
@@ -8026,7 +8162,7 @@
Slog.d(TAG, "Updating wifi stats");
}
- final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
+ final long elapsedRealtimeMs = mClocks.elapsedRealtime();
NetworkStats delta = null;
try {
if (!ArrayUtils.isEmpty(mWifiIfaces)) {
@@ -8570,7 +8706,7 @@
SamplingTimer kwlt = mKernelWakelockStats.get(name);
if (kwlt == null) {
- kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase,
+ kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase,
true /* track reported val */);
mKernelWakelockStats.put(name, kwlt);
}
@@ -8663,7 +8799,7 @@
// Read the CPU data for each UID. This will internally generate a snapshot so next time
// we read, we get a delta. If we are to distribute the cpu time, then do so. Otherwise
// we just ignore the data.
- final long startTimeMs = SystemClock.elapsedRealtime();
+ final long startTimeMs = mClocks.elapsedRealtime();
mKernelUidCpuTimeReader.readDelta(!mOnBatteryInternal ? null :
new KernelUidCpuTimeReader.Callback() {
@Override
@@ -8735,7 +8871,7 @@
});
if (DEBUG_ENERGY_CPU) {
- Slog.d(TAG, "Reading cpu stats took " + (SystemClock.elapsedRealtime() - startTimeMs) +
+ Slog.d(TAG, "Reading cpu stats took " + (mClocks.elapsedRealtime() - startTimeMs) +
" ms");
}
@@ -9000,8 +9136,8 @@
public void setBatteryStateLocked(int status, int health, int plugType, int level,
int temp, int volt) {
final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
- final long uptime = SystemClock.uptimeMillis();
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
if (!mHaveBatteryLevel) {
mHaveBatteryLevel = true;
// We start out assuming that the device is plugged in (not
@@ -9147,7 +9283,7 @@
}
public long getAwakeTimePlugged() {
- return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
+ return (mClocks.uptimeMillis() * 1000) - getAwakeTimeBattery();
}
@Override
@@ -9310,8 +9446,8 @@
return mDailyPackageChanges;
}
- long getBatteryUptimeLocked() {
- return mOnBatteryTimeBase.getUptime(SystemClock.uptimeMillis() * 1000);
+ protected long getBatteryUptimeLocked() {
+ return mOnBatteryTimeBase.getUptime(mClocks.uptimeMillis() * 1000);
}
@Override
@@ -9429,7 +9565,7 @@
public Uid getUidStatsLocked(int uid) {
Uid u = mUidStats.get(uid);
if (u == null) {
- u = new Uid(uid);
+ u = new Uid(this, uid);
mUidStats.put(uid, u);
}
return u;
@@ -9474,7 +9610,7 @@
}
public void shutdownLocked() {
- recordShutdownLocked(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
+ recordShutdownLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
writeSyncLocked();
mShuttingDown = true;
}
@@ -9502,7 +9638,7 @@
Parcel out = Parcel.obtain();
writeSummaryToParcel(out, true);
- mLastWriteTime = SystemClock.elapsedRealtime();
+ mLastWriteTime = mClocks.elapsedRealtime();
if (mPendingWrite != null) {
mPendingWrite.recycle();
@@ -9583,8 +9719,8 @@
if (mHistoryBuffer.dataPosition() > 0) {
mRecordingHistory = true;
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (USE_OLD_HISTORY) {
addHistoryRecordLocked(elapsedRealtime, uptime, HistoryItem.CMD_START, mHistoryCur);
}
@@ -9663,7 +9799,7 @@
// We are just arbitrarily going to insert 1 minute from the sample of
// the last run until samples in this run.
if (mHistoryBaseTime > 0) {
- long oldnow = SystemClock.elapsedRealtime();
+ long oldnow = mClocks.elapsedRealtime();
mHistoryBaseTime = mHistoryBaseTime - oldnow + 1;
if (DEBUG_HISTORY) {
StringBuilder sb = new StringBuilder(128);
@@ -9870,7 +10006,7 @@
}
for (int iu = 0; iu < NU; iu++) {
int uid = in.readInt();
- Uid u = new Uid(uid);
+ Uid u = new Uid(this, uid);
mUidStats.put(uid, u);
u.mWifiRunning = false;
@@ -10083,8 +10219,8 @@
// if we had originally pulled a time before the RTC was set.
long startClockTime = getStartClockTime();
- final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
- final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
+ final long NOW_SYS = mClocks.uptimeMillis() * 1000;
+ final long NOWREAL_SYS = mClocks.elapsedRealtime() * 1000;
out.writeInt(VERSION);
@@ -10469,29 +10605,34 @@
mOnBatteryScreenOffTimeBase.readFromParcel(in);
mScreenState = Display.STATE_UNKNOWN;
- mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase, in);
+ mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase, in);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
- mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase,
- in);
+ mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
+ mOnBatteryTimeBase, in);
}
mInteractive = false;
- mInteractiveTimer = new StopwatchTimer(null, -10, null, mOnBatteryTimeBase, in);
+ mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase, in);
mPhoneOn = false;
- mPowerSaveModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+ mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null,
+ mOnBatteryTimeBase, in);
mLongestLightIdleTime = in.readLong();
mLongestFullIdleTime = in.readLong();
- mDeviceIdleModeLightTimer = new StopwatchTimer(null, -14, null, mOnBatteryTimeBase, in);
- mDeviceIdleModeFullTimer = new StopwatchTimer(null, -11, null, mOnBatteryTimeBase, in);
- mDeviceLightIdlingTimer = new StopwatchTimer(null, -15, null, mOnBatteryTimeBase, in);
- mDeviceIdlingTimer = new StopwatchTimer(null, -12, null, mOnBatteryTimeBase, in);
- mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase, in);
+ mDeviceIdleModeLightTimer = new StopwatchTimer(mClocks, null, -14, null,
+ mOnBatteryTimeBase, in);
+ mDeviceIdleModeFullTimer = new StopwatchTimer(mClocks, null, -11, null,
+ mOnBatteryTimeBase, in);
+ mDeviceLightIdlingTimer = new StopwatchTimer(mClocks, null, -15, null,
+ mOnBatteryTimeBase, in);
+ mDeviceIdlingTimer = new StopwatchTimer(mClocks, null, -12, null, mOnBatteryTimeBase, in);
+ mPhoneOnTimer = new StopwatchTimer(mClocks, null, -3, null, mOnBatteryTimeBase, in);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
- mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
+ mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -200-i,
null, mOnBatteryTimeBase, in);
}
- mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mOnBatteryTimeBase, in);
+ mPhoneSignalScanningTimer = new StopwatchTimer(mClocks, null, -200+1, null,
+ mOnBatteryTimeBase, in);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
- mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i,
+ mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClocks, null, -300-i,
null, mOnBatteryTimeBase, in);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
@@ -10499,27 +10640,29 @@
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
}
mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
- mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase, in);
- mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase,
- in);
+ mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null,
+ mOnBatteryTimeBase, in);
+ mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
+ mOnBatteryTimeBase, in);
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mWifiOn = false;
- mWifiOnTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase, in);
+ mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase, in);
mGlobalWifiRunning = false;
- mGlobalWifiRunningTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase, in);
+ mGlobalWifiRunningTimer = new StopwatchTimer(mClocks, null, -5, null,
+ mOnBatteryTimeBase, in);
for (int i=0; i<NUM_WIFI_STATES; i++) {
- mWifiStateTimer[i] = new StopwatchTimer(null, -600-i,
+ mWifiStateTimer[i] = new StopwatchTimer(mClocks, null, -600-i,
null, mOnBatteryTimeBase, in);
}
for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
- mWifiSupplStateTimer[i] = new StopwatchTimer(null, -700-i,
+ mWifiSupplStateTimer[i] = new StopwatchTimer(mClocks, null, -700-i,
null, mOnBatteryTimeBase, in);
}
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
- mWifiSignalStrengthsTimer[i] = new StopwatchTimer(null, -800-i,
+ mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i,
null, mOnBatteryTimeBase, in);
}
@@ -10537,15 +10680,15 @@
mLoadedNumConnectivityChange = in.readInt();
mUnpluggedNumConnectivityChange = in.readInt();
mAudioOnNesting = 0;
- mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
+ mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
mVideoOnNesting = 0;
- mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
+ mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
mFlashlightOnNesting = 0;
- mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase, in);
+ mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase, in);
mCameraOnNesting = 0;
- mCameraOnTimer = new StopwatchTimer(null, -13, null, mOnBatteryTimeBase, in);
+ mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase, in);
mBluetoothScanNesting = 0;
- mBluetoothScanTimer = new StopwatchTimer(null, -14, null, mOnBatteryTimeBase, in);
+ mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase, in);
mDischargeUnplugLevel = in.readInt();
mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
@@ -10565,7 +10708,7 @@
for (int ikw = 0; ikw < NKW; ikw++) {
if (in.readInt() != 0) {
String wakelockName = in.readString();
- SamplingTimer kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase, in);
+ SamplingTimer kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase, in);
mKernelWakelockStats.put(wakelockName, kwlt);
}
}
@@ -10575,7 +10718,7 @@
for (int iwr = 0; iwr < NWR; iwr++) {
if (in.readInt() != 0) {
String reasonName = in.readString();
- SamplingTimer timer = new SamplingTimer(mOnBatteryTimeBase, in);
+ SamplingTimer timer = new SamplingTimer(mClocks, mOnBatteryTimeBase, in);
mWakeupReasonStats.put(reasonName, timer);
}
}
@@ -10597,7 +10740,7 @@
mUidStats.clear();
for (int i = 0; i < numUids; i++) {
int uid = in.readInt();
- Uid u = new Uid(uid);
+ Uid u = new Uid(this, uid);
u.readFromParcelLocked(mOnBatteryTimeBase, mOnBatteryScreenOffTimeBase, in);
mUidStats.append(uid, u);
}
@@ -10620,8 +10763,8 @@
// if we had originally pulled a time before the RTC was set.
long startClockTime = getStartClockTime();
- final long uSecUptime = SystemClock.uptimeMillis() * 1000;
- final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
+ final long uSecUptime = mClocks.uptimeMillis() * 1000;
+ final long uSecRealtime = mClocks.elapsedRealtime() * 1000;
final long batteryRealtime = mOnBatteryTimeBase.getRealtime(uSecRealtime);
final long batteryScreenOffRealtime = mOnBatteryScreenOffTimeBase.getRealtime(uSecRealtime);
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 3d60926..4832881 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -585,14 +585,14 @@
w = 0;
}
if (DEBUG_MEASURE) Log.d(mLogTag, "Fixed width: " + w);
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
if (w > 0) {
- final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
widthMeasureSpec = MeasureSpec.makeMeasureSpec(
Math.min(w, widthSize), EXACTLY);
fixedWidth = true;
} else {
widthMeasureSpec = MeasureSpec.makeMeasureSpec(
- widthMeasureSpec - mFloatingInsets.left - mFloatingInsets.right,
+ widthSize - mFloatingInsets.left - mFloatingInsets.right,
AT_MOST);
mApplyFloatingHorizontalInsets = true;
}
diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
index 14badb7..4b2a72d 100644
--- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
@@ -175,13 +175,13 @@
{"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder},
{"nCreateRootAlphaPropertyHolder", "!(JFF)J", (void*)createRootAlphaPropertyHolder},
{"nSetPropertyHolderData", "(J[FI)V", (void*)setPropertyHolderData},
- {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)start},
- {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)reverse},
+ {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)start},
+ {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)reverse},
{"nEnd", "!(J)V", (void*)end},
{"nReset", "!(J)V", (void*)reset},
};
-const char* const kClassPathName = "android/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator";
+const char* const kClassPathName = "android/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT";
int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env) {
gVectorDrawableAnimatorClassInfo.clazz = FindClassOrDie(env, kClassPathName);
gVectorDrawableAnimatorClassInfo.clazz = MakeGlobalRefOrDie(env,
@@ -189,7 +189,7 @@
gVectorDrawableAnimatorClassInfo.callOnFinished = GetStaticMethodIDOrDie(
env, gVectorDrawableAnimatorClassInfo.clazz, "callOnFinished",
- "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V");
+ "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V");
return RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedVectorDrawable",
gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index 03c94a6..c87a770 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -160,7 +160,7 @@
}
// In the emulator this property will be set > 0 when OpenGL ES 2.0 is
// enabled, 0 otherwise. On old emulator versions it will be undefined.
- property_get("ro.kernel.qemu.gles", prop, "0");
+ property_get("qemu.gles", prop, "0");
return atoi(prop) > 0 ? JNI_TRUE : JNI_FALSE;
}
diff --git a/core/res/res/layout/language_picker_item.xml b/core/res/res/layout/language_picker_item.xml
index 22cb514..88012a9 100644
--- a/core/res/res/layout/language_picker_item.xml
+++ b/core/res/res/layout/language_picker_item.xml
@@ -14,37 +14,16 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- android:layoutDirection="locale"
- android:textDirection="locale"
- android:paddingBottom="8dp"
- android:paddingTop="8dp">
-
- <TextView
- android:id="@+id/locale"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- tools:text="France"
- android:layout_weight="1"
- android:padding="12dp"
- android:paddingStart="18dp"
- android:paddingEnd="18dp"
- android:textAppearance="?android:attr/textAppearanceListItem"/>
-
- <ImageView
- android:id="@+id/l10nWarn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@android:drawable/stat_sys_warning"
- android:focusableInTouchMode="false"
- android:focusable="false"
- android:paddingStart="12dp"
- android:paddingEnd="12dp"
- android:tint="?android:attr/colorAccent"/>
-
-</LinearLayout>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/locale"
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:layoutDirection="locale"
+ android:textDirection="locale"
+ android:paddingBottom="8dp"
+ android:paddingTop="8dp" />
diff --git a/core/res/res/layout/language_picker_section_header.xml b/core/res/res/layout/language_picker_section_header.xml
index b12ec8c..6cbd7c3 100644
--- a/core/res/res/layout/language_picker_section_header.xml
+++ b/core/res/res/layout/language_picker_section_header.xml
@@ -23,4 +23,5 @@
android:paddingStart="18dp"
android:paddingEnd="18dp"
android:textColor="?android:attr/colorAccent"
+ android:textStyle="bold"
tools:text="@string/language_picker_section_all"/>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3e9a6ca..70bed2d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -185,8 +185,6 @@
<!-- Displayed to tell the user that they cannot change the caller ID setting. -->
<string name="CLIRPermanent">You can\'t change the caller ID setting.</string>
- <!-- Notification title to tell the user that restricted state is changed by access control. -->
- <string name="RestrictedChangedTitle">Restricted access changed</string>
<!-- Displayed to tell the user that data service is blocked by access control. -->
<string name="RestrictedOnData">Data service is blocked.</string>
<!-- Displayed to tell the user that emergency service is blocked by access control. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a7a9292..f791ce6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -484,7 +484,6 @@
<java-symbol type="string" name="Noon" />
<java-symbol type="string" name="PinMmi" />
<java-symbol type="string" name="PwdMmi" />
- <java-symbol type="string" name="RestrictedChangedTitle" />
<java-symbol type="string" name="RestrictedOnAllVoice" />
<java-symbol type="string" name="RestrictedOnData" />
<java-symbol type="string" name="RestrictedOnEmergency" />
@@ -2486,7 +2485,6 @@
<java-symbol type="string" name="status_bar_clock" />
<!-- Locale picker -->
- <java-symbol type="id" name="l10nWarn" />
<java-symbol type="id" name="locale_search_menu" />
<java-symbol type="layout" name="language_picker_item" />
<java-symbol type="layout" name="language_picker_section_header" />
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
new file mode 100644
index 0000000..1c3cd38
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
@@ -0,0 +1,745 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import com.android.internal.os.BatteryStatsImpl;
+
+/**
+ * Provides test cases for android.os.BatteryStats.
+ */
+public class BatteryStatsServTest extends TestCase {
+ private static final String TAG = "BatteryStatsServTest";
+
+ public static class TestServ extends BatteryStatsImpl.Uid.Pkg.Serv {
+ TestServ(MockBatteryStatsImpl bsi) {
+ super(bsi);
+ }
+
+ void populate() {
+ mStartTime = 1010;
+ mRunningSince = 2021;
+ mRunning = true;
+ mStarts = 4042;
+ mLaunchedTime = 5053;
+ mLaunchedSince = 6064;
+ mLaunched = true;
+ mLaunches = 8085;
+ mLoadedStartTime = 9096;
+ mLoadedStarts = 10017;
+ mLoadedLaunches = 11118;
+ mLastStartTime = 12219;
+ mLastStarts = 13310;
+ mLastLaunches = 14411;
+ mUnpluggedStartTime = 15512;
+ mUnpluggedStarts = 16613;
+ mUnpluggedLaunches = 17714;
+ }
+
+ long getStartTime() {
+ return mStartTime;
+ }
+
+ long getRunningSince() {
+ return mRunningSince;
+ }
+
+ void setRunning(boolean val) {
+ mRunning = val;
+ }
+
+ boolean getRunning() {
+ return mRunning;
+ }
+
+ int getStarts() {
+ return mStarts;
+ }
+
+ long getLaunchedTime() {
+ return mLaunchedTime;
+ }
+
+ long getLaunchedSince() {
+ return mLaunchedSince;
+ }
+
+ void setLaunched(boolean val) {
+ mLaunched = val;
+ }
+
+ boolean getLaunched() {
+ return mLaunched;
+ }
+
+ int getLaunches() {
+ return mLaunches;
+ }
+
+ long getLoadedStartTime() {
+ return mLoadedStartTime;
+ }
+
+ int getLoadedStarts() {
+ return mLoadedStarts;
+ }
+
+ int getLoadedLaunches() {
+ return mLoadedLaunches;
+ }
+
+ long getLastStartTime() {
+ return mLastStartTime;
+ }
+
+ int getLastStarts() {
+ return mLastStarts;
+ }
+
+ int getLastLaunches() {
+ return mLastLaunches;
+ }
+
+ long getUnpluggedStartTime() {
+ return mUnpluggedStartTime;
+ }
+
+ int getUnpluggedStarts() {
+ return mUnpluggedStarts;
+ }
+
+ int getUnpluggedLaunches() {
+ return mUnpluggedLaunches;
+ }
+ }
+
+ /**
+ * Test that the constructor and detach methods touch the time bast observer list.
+ */
+ @SmallTest
+ public void testConstructAndDetach() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+
+ TestServ serv = new TestServ(bsi);
+ Assert.assertTrue(bsi.getOnBatteryTimeBase().hasObserver(serv));
+
+ serv.detach();
+ Assert.assertFalse(bsi.getOnBatteryTimeBase().hasObserver(serv));
+ }
+
+ /**
+ * Test OnTimeStarted
+ */
+ @SmallTest
+ public void testOnTimeStarted() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setRunning(true);
+ serv.onTimeStarted(111111, 20000, 222222);
+ Assert.assertEquals(18989, serv.getUnpluggedStartTime());
+ Assert.assertEquals(4042, serv.getUnpluggedStarts());
+ Assert.assertEquals(8085, serv.getUnpluggedLaunches());
+
+ serv.populate();
+ serv.setRunning(false);
+ serv.onTimeStarted(111111, 20000, 222222);
+ Assert.assertEquals(1010, serv.getUnpluggedStartTime());
+ Assert.assertEquals(4042, serv.getUnpluggedStarts());
+ Assert.assertEquals(8085, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test parceling and unparceling.
+ */
+ @SmallTest
+ public void testParceling() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ orig = new TestServ(bsi);
+ orig.populate();
+
+ Parcel parcel = Parcel.obtain();
+ orig.writeToParcelLocked(parcel);
+
+ parcel.setDataPosition(0);
+
+ TestServ serv = new TestServ(bsi);
+ serv.readFromParcelLocked(parcel);
+
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(0, serv.getLastStartTime());
+ Assert.assertEquals(0, serv.getLastStarts());
+ Assert.assertEquals(0, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test getLaunchTimeToNow()
+ */
+ @SmallTest
+ public void testLaunchTimeToNow() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setLaunched(true);
+ Assert.assertEquals(8989, serv.getLaunchTimeToNowLocked(10000));
+
+ serv.populate();
+ serv.setLaunched(false);
+ Assert.assertEquals(5053, serv.getLaunchTimeToNowLocked(10000));
+
+ }
+
+ /**
+ * Test getStartTimeToNow()
+ */
+ @SmallTest
+ public void testStartTimeToNow() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setRunning(true);
+ Assert.assertEquals(18989, serv.getStartTimeToNowLocked(20000));
+
+ serv.populate();
+ serv.setRunning(false);
+ Assert.assertEquals(1010, serv.getStartTimeToNowLocked(20000));
+ }
+
+ /**
+ * Test startLaunchedLocked while not previously launched
+ */
+ @SmallTest
+ public void testStartLaunchedLockedWhileLaunched() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 777777L;
+ }
+ };
+
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setLaunched(true);
+ serv.startLaunchedLocked();
+
+ // No changes
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test startLaunchedLocked while previously launched
+ */
+ @SmallTest
+ public void testStartLaunchedLockedWhileNotLaunched() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 777777L;
+ }
+ };
+
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setLaunched(false);
+ serv.startLaunchedLocked();
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(777777L, serv.getLaunchedSince()); // <-- changed
+ Assert.assertTrue(serv.getLaunched()); // <-- changed
+ Assert.assertEquals(8086, serv.getLaunches()); // <-- changed
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test stopLaunchedLocked when not previously launched.
+ */
+ @SmallTest
+ public void testStopLaunchedLockedWhileNotLaunched() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 777777L;
+ }
+ };
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setLaunched(false);
+
+ serv.stopLaunchedLocked();
+
+ // No changes
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertFalse(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test stopLaunchedLocked when previously launched, with measurable time between
+ * start and stop.
+ */
+ @SmallTest
+ public void testStopLaunchedLockedWhileLaunchedNormal() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 777777L;
+ }
+ };
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setLaunched(true);
+
+ serv.stopLaunchedLocked();
+
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(777777L-6064+5053, serv.getLaunchedTime()); // <-- changed
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertFalse(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test stopLaunchedLocked when previously launched, with no measurable time between
+ * start and stop.
+ */
+ @SmallTest
+ public void testStopLaunchedLockedWhileLaunchedTooQuick() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 6064L;
+ }
+ };
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setLaunched(true);
+
+ serv.stopLaunchedLocked();
+
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertFalse(serv.getLaunched());
+ Assert.assertEquals(8085-1, serv.getLaunches()); // <-- changed
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test startRunningLocked while previously running
+ */
+ @SmallTest
+ public void testStartRunningLockedWhileRunning() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 777777L;
+ }
+ };
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setRunning(true);
+
+ serv.startRunningLocked();
+
+ // no change
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test startRunningLocked while not previously launched
+ */
+ @SmallTest
+ public void testStartRunningLockedWhileNotRunning() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 777777L;
+ }
+ };
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setRunning(false);
+
+ serv.startRunningLocked();
+
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(777777L, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042+1, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test stopRunningLocked when previously launched, with measurable time between
+ * start and stop.
+ */
+ @SmallTest
+ public void testStopRunningLockedWhileRunningNormal() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 777777L;
+ }
+ };
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setRunning(true);
+
+ serv.stopRunningLocked();
+
+ Assert.assertEquals(777777L-2021+1010, serv.getStartTime()); // <-- changed
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertFalse(serv.getRunning()); // <-- changed
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test stopRunningLocked when previously launched, with measurable time between
+ * start and stop.
+ */
+ @SmallTest
+ public void testStopRunningLockedWhileRunningTooQuick() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 2021;
+ }
+ };
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setRunning(true);
+
+ serv.stopRunningLocked();
+
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertFalse(serv.getRunning()); // <-- changed
+ Assert.assertEquals(4042-1, serv.getStarts()); // <-- changed
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test that getBatteryStats returns the BatteryStatsImpl passed in to the contstructor.
+ */
+ @SmallTest
+ public void testGetBatteryStats() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+
+ Assert.assertEquals(bsi, serv.getBatteryStats());
+ }
+
+ /**
+ * Test getLaunches
+ */
+ @SmallTest
+ public void testGetLaunches() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+ serv.populate();
+
+ Assert.assertEquals(8085, serv.getLaunches(BatteryStats.STATS_SINCE_CHARGED));
+ Assert.assertEquals(8085-11118, serv.getLaunches(BatteryStats.STATS_CURRENT));
+ Assert.assertEquals(8085-17714, serv.getLaunches(BatteryStats.STATS_SINCE_UNPLUGGED));
+
+ // No change to fields
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test getStartTime while running
+ */
+ @SmallTest
+ public void testGetStartTimeRunning() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+ serv.populate();
+ serv.setRunning(true);
+
+ final long startTimeToNow = 1010 + 20000 - 2021;
+
+ Assert.assertEquals(startTimeToNow,
+ serv.getStartTime(20000, BatteryStats.STATS_SINCE_CHARGED));
+ Assert.assertEquals(startTimeToNow-9096,
+ serv.getStartTime(20000, BatteryStats.STATS_CURRENT));
+ Assert.assertEquals(startTimeToNow-15512,
+ serv.getStartTime(20000, BatteryStats.STATS_SINCE_UNPLUGGED));
+
+ // No change to fields
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test getStartTime while not running
+ */
+ @SmallTest
+ public void testGetStartTimeNotRunning() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+ serv.populate();
+ serv.setRunning(false);
+
+ final long startTimeToNow = 1010;
+
+ Assert.assertEquals(startTimeToNow,
+ serv.getStartTime(20000, BatteryStats.STATS_SINCE_CHARGED));
+ Assert.assertEquals(startTimeToNow-9096,
+ serv.getStartTime(20000, BatteryStats.STATS_CURRENT));
+ Assert.assertEquals(startTimeToNow-15512,
+ serv.getStartTime(20000, BatteryStats.STATS_SINCE_UNPLUGGED));
+
+ // No change to fields
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertFalse(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+
+ /**
+ * Test getStarts
+ */
+ @SmallTest
+ public void testGetStarts() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+ serv.populate();
+
+ Assert.assertEquals(4042, serv.getStarts(BatteryStats.STATS_SINCE_CHARGED));
+ Assert.assertEquals(4042-10017, serv.getStarts(BatteryStats.STATS_CURRENT));
+ Assert.assertEquals(4042-16613, serv.getStarts(BatteryStats.STATS_SINCE_UNPLUGGED));
+
+ // No change to fields
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
new file mode 100644
index 0000000..05aa53c
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -0,0 +1,15 @@
+package com.android.internal.os;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+ BatteryStatsServTest.class,
+ BatteryStatsTimeBaseTest.class,
+ BatteryStatsTimerTest.class,
+ BatteryStatsUidTest.class,
+ })
+public class BatteryStatsTests {
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
new file mode 100644
index 0000000..ab92f15
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.mockito.Mockito;
+
+/**
+ * Provides test cases for android.os.BatteryStats.
+ */
+public class BatteryStatsTimeBaseTest extends TestCase {
+ private static final String TAG = "BatteryStatsTimeBaseTest";
+
+ static class TestTimeBase extends BatteryStatsImpl.TimeBase {
+
+ public void populate(long uptime, long realtime, boolean running, long pastUptime,
+ long uptimeStart, long pastRealtime, long realtimeStart,
+ long unpluggedUptime, long unpluggedRealtime) {
+ mUptime = uptime;
+ mRealtime = realtime;
+ mRunning = running;
+ mPastUptime = pastUptime;
+ mUptimeStart = uptimeStart;
+ mPastRealtime = pastRealtime;
+ mRealtimeStart = realtimeStart;
+ mUnpluggedUptime = unpluggedUptime;
+ mUnpluggedRealtime = unpluggedRealtime;
+ }
+
+ public void verify(long uptime, long realtime, boolean running, long pastUptime,
+ long uptimeStart, long pastRealtime, long realtimeStart,
+ long unpluggedUptime, long unpluggedRealtime) {
+ Assert.assertEquals(uptime, mUptime);
+ Assert.assertEquals(realtime, mRealtime);
+ Assert.assertEquals(running, mRunning);
+ Assert.assertEquals(pastUptime, mPastUptime);
+ Assert.assertEquals(uptimeStart, mUptimeStart);
+ Assert.assertEquals(pastRealtime, mPastRealtime);
+ Assert.assertEquals(realtimeStart, mRealtimeStart);
+ Assert.assertEquals(unpluggedUptime, mUnpluggedUptime);
+ Assert.assertEquals(unpluggedRealtime, mUnpluggedRealtime);
+ }
+ }
+
+ /**
+ * Test the observers and the setRunning call.
+ */
+ @SmallTest
+ public void testRunning() throws Exception {
+ TestTimeBase tb = new TestTimeBase();
+
+ // Toggle running once, to accumulate past uptime and past realtime
+ // so the test values aren't 0.
+ tb.setRunning(true, 100, 10000);
+ tb.setRunning(false, 200, 11000);
+ Assert.assertEquals(100, tb.getUptimeStart());
+ Assert.assertEquals(10000, tb.getRealtimeStart());
+
+ // Create some observers
+ BatteryStatsImpl.TimeBaseObs observer1 = Mockito.mock(BatteryStatsImpl.TimeBaseObs.class);
+ BatteryStatsImpl.TimeBaseObs observer2 = Mockito.mock(BatteryStatsImpl.TimeBaseObs.class);
+ BatteryStatsImpl.TimeBaseObs observer3 = Mockito.mock(BatteryStatsImpl.TimeBaseObs.class);
+
+ // Add them
+ tb.add(observer1);
+ tb.add(observer2);
+ tb.add(observer3);
+ Assert.assertTrue(tb.hasObserver(observer1));
+ Assert.assertTrue(tb.hasObserver(observer2));
+ Assert.assertTrue(tb.hasObserver(observer3));
+
+ // Remove one
+ tb.remove(observer3);
+ Assert.assertTrue(tb.hasObserver(observer1));
+ Assert.assertTrue(tb.hasObserver(observer2));
+ Assert.assertFalse(tb.hasObserver(observer3));
+
+ // Start running, make sure we get a started call on the two active observers
+ // and not the third.
+ tb.setRunning(true, 250, 14000);
+
+ Assert.assertTrue(tb.isRunning());
+
+ if (false) {
+ Log.d(TAG, "mUptimeStart=" + tb.getUptimeStart()
+ + " mRealtimeStart=" + tb.getRealtimeStart()
+ + " mUptime=" + tb.getUptime(250)
+ + " mRealtime=" + tb.getRealtime(14000)
+ + " isRunning=" + tb.isRunning());
+ }
+
+ Assert.assertEquals(250, tb.getUptimeStart());
+ Assert.assertEquals(14000, tb.getRealtimeStart());
+ Assert.assertEquals(100, tb.getUptime(250));
+ Assert.assertEquals(1000, tb.getRealtime(14000));
+
+ Mockito.verify(observer1).onTimeStarted(14000, 100, 1000);
+ Mockito.verify(observer1, Mockito.never()).onTimeStopped(-1, -1, -1);
+ Mockito.verifyNoMoreInteractions(observer1);
+ Mockito.verify(observer2).onTimeStarted(14000, 100, 1000);
+ Mockito.verify(observer2, Mockito.never()).onTimeStopped(-1, -1, -1);
+ Mockito.verifyNoMoreInteractions(observer2);
+
+ Mockito.reset(observer1);
+ Mockito.reset(observer2);
+ Mockito.reset(observer3);
+
+ // Advance the "timer" and make sure the getters account for the current time passed in
+ Assert.assertEquals(400, tb.getUptime(550));
+ Assert.assertEquals(1555, tb.getRealtime(14555));
+
+ // Stop running, make sure we get a stopped call on the two active observers
+ // and not the third.
+ tb.setRunning(false, 402, 14002);
+
+ Assert.assertFalse(tb.isRunning());
+
+ if (false) {
+ Log.d(TAG, "mUptimeStart=" + tb.getUptimeStart()
+ + " mRealtimeStart=" + tb.getRealtimeStart()
+ + " mUptime=" + tb.getUptime(250)
+ + " mRealtime=" + tb.getRealtime(14000)
+ + " isRunning=" + tb.isRunning());
+ }
+
+ Assert.assertEquals(252, tb.getUptime(402));
+ Assert.assertEquals(1002, tb.getRealtime(14002));
+
+ Mockito.verify(observer1).onTimeStopped(14002, 252, 1002);
+ Mockito.verify(observer1, Mockito.never()).onTimeStopped(-1, -1, -1);
+ Mockito.verifyNoMoreInteractions(observer1);
+ Mockito.verify(observer2).onTimeStopped(14002, 252, 1002);
+ Mockito.verify(observer2, Mockito.never()).onTimeStopped(-1, -1, -1);
+ Mockito.verifyNoMoreInteractions(observer2);
+
+ // Advance the "timer" and make sure the getters account for the current time passed in
+ // is the same as the time when running went to false.
+ Assert.assertEquals(252, tb.getUptime(600));
+ Assert.assertEquals(1002, tb.getRealtime(17000));
+ }
+
+ /**
+ * Test that reset while running updates the plugged and unplugged times
+ */
+ @SmallTest
+ public void testResetWhileRunning() throws Exception {
+ TestTimeBase tb = new TestTimeBase();
+ tb.populate(100, 200, true, 300, 400, 500, 600, 700, 800);
+
+ tb.reset(666, 6666);
+
+ // Not sure if this is a bug: reset while running does not
+ // reset mPastUptime, but while it is running it does.
+ tb.verify(100, 200, true, 300, 666, 500, 6666, 300, 500);
+ }
+
+ /**
+ * Test that reset while running updates the plugged and unplugged times
+ */
+ @SmallTest
+ public void testResetWhileNotRunning() throws Exception {
+ TestTimeBase tb = new TestTimeBase();
+ tb.populate(100, 200, false, 300, 400, 500, 600, 700, 800);
+
+ tb.reset(666, 6666);
+
+ tb.verify(100, 200, false, 0, 400, 0, 600, 700, 800);
+ }
+
+ /**
+ * Test init
+ */
+ @SmallTest
+ public void testInit() throws Exception {
+ TestTimeBase tb = new TestTimeBase();
+ tb.populate(100, 200, false, 300, 400, 500, 600, 700, 800);
+
+ tb.init(666, 6666);
+
+ tb.verify(0, 0, false, 0, 666, 0, 6666, 0, 0);
+ }
+
+ /**
+ * Test writeToParcel and readFromParcel
+ */
+ @SmallTest
+ public void testParcellingWhileRunning() throws Exception {
+ TestTimeBase tb1 = new TestTimeBase();
+
+ tb1.populate(100, 200, true, 300, 400, 500, 600, 700, 800);
+
+ Parcel parcel = Parcel.obtain();
+ tb1.writeToParcel(parcel, 666, 6666);
+
+ parcel.setDataPosition(0);
+
+ TestTimeBase tb2 = new TestTimeBase();
+ tb2.readFromParcel(parcel);
+
+ // Running is not preserved across parceling
+ tb2.verify(100, 200, false, 300+666-400, 400, 500+6666-600, 600, 700, 800);
+ }
+
+ /**
+ * Test writeToParcel and readFromParcel
+ */
+ @SmallTest
+ public void testParcellingWhileNotRunning() throws Exception {
+ TestTimeBase tb1 = new TestTimeBase();
+
+ tb1.populate(100, 200, false, 300, 400, 500, 600, 700, 800);
+
+ Parcel parcel = Parcel.obtain();
+ tb1.writeToParcel(parcel, 666, 6666);
+
+ parcel.setDataPosition(0);
+
+ TestTimeBase tb2 = new TestTimeBase();
+ tb2.readFromParcel(parcel);
+
+ tb2.verify(100, 200, false, 300, 400, 500, 600, 700, 800);
+ }
+
+ /**
+ * Test writeSummaryToParcel and readSummaryFromParcel
+ */
+ @SmallTest
+ public void testSummary() throws Exception {
+ TestTimeBase tb1 = new TestTimeBase();
+
+ tb1.populate(100, 200, true, 300, 400, 500, 600, 700, 800);
+
+ Parcel parcel = Parcel.obtain();
+ tb1.writeSummaryToParcel(parcel, 666, 6666);
+
+ parcel.setDataPosition(0);
+
+ TestTimeBase tb2 = new TestTimeBase();
+
+ // readSummaryFromParcel doesn't affect the other fields.
+ // Not sure if this is deliberate
+ tb2.populate(1, 2, true, 3, 4, 5, 6, 7, 8);
+
+ tb2.readSummaryFromParcel(parcel);
+
+ tb2.verify(666, 6766, true, 3, 4, 5, 6, 7, 8);
+ }
+
+ /**
+ * Test computeUptime
+ */
+ @SmallTest
+ public void testComputeUptime() throws Exception {
+ TestTimeBase tb = new TestTimeBase();
+
+ tb.populate(100, 200, true, 300, 400, 500, 600, 50, 60);
+
+ Assert.assertEquals(100+300+666-400,
+ tb.computeUptime(666, BatteryStats.STATS_SINCE_CHARGED));
+ Assert.assertEquals(300+666-400,
+ tb.computeUptime(666, BatteryStats.STATS_CURRENT));
+ Assert.assertEquals(300+666-400-50,
+ tb.computeUptime(666, BatteryStats.STATS_SINCE_UNPLUGGED));
+
+ Assert.assertEquals(0, tb.computeUptime(666, 6000));
+ }
+
+ /**
+ * Test computeUptime
+ */
+ @SmallTest
+ public void testComputeRealtime() throws Exception {
+ TestTimeBase tb = new TestTimeBase();
+
+ tb.populate(100, 200, true, 300, 400, 500, 600, 50, 60);
+
+ Assert.assertEquals(200+500+6666-600,
+ tb.computeRealtime(6666, BatteryStats.STATS_SINCE_CHARGED));
+ Assert.assertEquals(500+6666-600,
+ tb.computeRealtime(6666, BatteryStats.STATS_CURRENT));
+ Assert.assertEquals(500+6666-600-60,
+ tb.computeRealtime(6666, BatteryStats.STATS_SINCE_UNPLUGGED));
+
+ Assert.assertEquals(0, tb.computeUptime(666, 6000));
+ }
+
+ /**
+ * Test dump
+ */
+ @SmallTest
+ public void testDump() throws Exception {
+ TestTimeBase tb = new TestTimeBase();
+
+ tb.populate(100, 200, true, 300, 400, 500, 600, 50, 60);
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+
+ tb.dump(pw, "+++++ ");
+
+ pw.close();
+
+ // note the spaces at the ends of the lines which come from formatTimeMs.
+ final String CORRECT = "+++++ mRunning=true\n"
+ + "+++++ mUptime=0ms \n"
+ + "+++++ mRealtime=0ms \n"
+ + "+++++ mPastUptime=0ms mUptimeStart=0ms mUnpluggedUptime=0ms \n"
+ + "+++++ mPastRealtime=0ms mRealtimeStart=0ms mUnpluggedRealtime=0ms \n";
+
+ Assert.assertEquals(CORRECT, sw.toString());
+ }
+
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
new file mode 100644
index 0000000..3e17fcb
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import android.util.StringBuilderPrinter;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import com.android.internal.os.BatteryStatsImpl.Clocks;
+import com.android.internal.os.BatteryStatsImpl.TimeBase;
+import com.android.internal.os.BatteryStatsImpl.Timer;
+
+/**
+ * Provides test cases for android.os.BatteryStats.
+ */
+public class BatteryStatsTimerTest extends TestCase {
+ private static final String TAG = "BatteryStatsTest";
+
+ class TestTimer extends Timer {
+ long nextComputeRunTime;
+ long lastComputeRunTimeRealtime;
+
+ int nextComputeCurrentCount;
+
+ TestTimer(Clocks clocks, int type, TimeBase timeBase, Parcel in) {
+ super(clocks, type, timeBase, in);
+ }
+
+ TestTimer(Clocks clocks, int type, TimeBase timeBase) {
+ super(clocks, type, timeBase);
+ }
+
+ protected long computeRunTimeLocked(long curBatteryRealtime) {
+ lastComputeRunTimeRealtime = curBatteryRealtime;
+ return nextComputeRunTime;
+ }
+
+ protected int computeCurrentCountLocked() {
+ return nextComputeCurrentCount;
+ }
+
+ public int getCount() {
+ return mCount;
+ }
+
+ public void setCount(int val) {
+ mCount = val;
+ }
+
+ public int getLoadedCount() {
+ return mLoadedCount;
+ }
+
+ public void setLoadedCount(int val) {
+ mLoadedCount = val;
+ }
+
+ public int getLastCount() {
+ return mLastCount;
+ }
+
+ public void setLastCount(int val) {
+ mLastCount = val;
+ }
+
+ public int getUnpluggedCount() {
+ return mUnpluggedCount;
+ }
+
+ public void setUnpluggedCount(int val) {
+ mUnpluggedCount = val;
+ }
+
+ public long getTotalTime() {
+ return mTotalTime;
+ }
+
+ public void setTotalTime(long val) {
+ mTotalTime = val;
+ }
+
+ public long getLoadedTime() {
+ return mLoadedTime;
+ }
+
+ public void setLoadedTime(long val) {
+ mLoadedTime = val;
+ }
+
+ public long getLastTime() {
+ return mLastTime;
+ }
+
+ public void setLastTime(long val) {
+ mLastTime = val;
+ }
+
+ public long getUnpluggedTime() {
+ return mUnpluggedTime;
+ }
+
+ public void setUnpluggedTime(long val) {
+ mUnpluggedTime = val;
+ }
+
+ public long getTimeBeforeMark() {
+ return mTimeBeforeMark;
+ }
+
+ public void setTimeBeforeMark(long val) {
+ mTimeBeforeMark = val;
+ }
+ }
+
+ /**
+ * Tests that the flow through TimeBase.setRunning propagates through
+ * to the timer.
+ */
+ @SmallTest
+ public void testRunning() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer = new TestTimer(clocks, 0, timeBase);
+ timer.nextComputeCurrentCount = 3000;
+
+ // Test that starting the timer counts the unplugged time and counters
+ timer.nextComputeRunTime = 4;
+ timer.onTimeStarted(10, 20, 50);
+ Assert.assertEquals(50, timer.lastComputeRunTimeRealtime);
+ Assert.assertEquals(4, timer.getUnpluggedTime());
+ Assert.assertEquals(0, timer.getUnpluggedCount());
+
+ // Test that stopping the timer updates mTotalTime and mCount
+ timer.nextComputeRunTime = 17;
+ timer.onTimeStopped(100, 130, 170);
+ Assert.assertEquals(17, timer.getTotalTime());
+ Assert.assertEquals(3000, timer.getCount());
+ }
+
+ /**
+ * Tests that the parcel can be parceled and unparceled without losing anything.
+ */
+ @SmallTest
+ public void testParceling() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ MockClocks clocks = new MockClocks();
+
+ // Test write then read
+ TestTimer timer1 = new TestTimer(clocks, 0, timeBase);
+ timer1.setCount(1);
+ timer1.setLoadedCount(2);
+ timer1.setLastCount(3);
+ timer1.setUnpluggedCount(4);
+ timer1.setTotalTime(9223372036854775807L);
+ timer1.setLoadedTime(9223372036854775806L);
+ timer1.setLastTime(9223372036854775805L);
+ timer1.setUnpluggedTime(9223372036854775804L);
+ timer1.setTimeBeforeMark(9223372036854775803L);
+ timer1.nextComputeRunTime = 201;
+
+ Parcel parcel = Parcel.obtain();
+ Timer.writeTimerToParcel(parcel, timer1, 77);
+
+ parcel.setDataPosition(0);
+ Assert.assertTrue("parcel null object", parcel.readInt() != 0);
+
+ TestTimer timer2 = new TestTimer(clocks, 0, timeBase, parcel);
+ Assert.assertEquals(1, timer2.getCount());
+ Assert.assertEquals(2, timer2.getLoadedCount());
+ Assert.assertEquals(0, timer2.getLastCount()); // NOT saved
+ Assert.assertEquals(4, timer2.getUnpluggedCount());
+ Assert.assertEquals(201, timer2.getTotalTime()); // from computeRunTimeLocked()
+ Assert.assertEquals(9223372036854775806L, timer2.getLoadedTime());
+ Assert.assertEquals(0, timer2.getLastTime()); // NOT saved
+ Assert.assertEquals(9223372036854775804L, timer2.getUnpluggedTime());
+ Assert.assertEquals(9223372036854775803L, timer2.getTimeBeforeMark());
+
+ parcel.recycle();
+ }
+
+ /**
+ * Tests that the parcel can be parceled and unparceled without losing anything.
+ */
+ @SmallTest
+ public void testParcelingNull() throws Exception {
+ // Test writing null
+ Parcel parcel = Parcel.obtain();
+ Timer.writeTimerToParcel(parcel, null, 88);
+
+ parcel.setDataPosition(0);
+ Assert.assertEquals(0, parcel.readInt());
+
+ parcel.recycle();
+ }
+
+ /**
+ * Tests that reset() clears the correct times.
+ */
+ @SmallTest
+ public void testResetNoDetach() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer = new TestTimer(clocks, 0, timeBase);
+ timer.setCount(1);
+ timer.setLoadedCount(2);
+ timer.setLastCount(3);
+ timer.setUnpluggedCount(4);
+ timer.setTotalTime(9223372036854775807L);
+ timer.setLoadedTime(9223372036854775806L);
+ timer.setLastTime(9223372036854775805L);
+ timer.setUnpluggedTime(9223372036854775804L);
+ timer.setTimeBeforeMark(9223372036854775803L);
+
+ timer.reset(false);
+
+ Assert.assertEquals(0, timer.getCount());
+ Assert.assertEquals(0, timer.getLoadedCount());
+ Assert.assertEquals(0, timer.getLastCount());
+ Assert.assertEquals(4, timer.getUnpluggedCount());
+ Assert.assertEquals(0, timer.getTotalTime());
+ Assert.assertEquals(0, timer.getLoadedTime());
+ Assert.assertEquals(0, timer.getLastTime());
+ Assert.assertEquals(9223372036854775804L, timer.getUnpluggedTime());
+ Assert.assertEquals(0, timer.getTimeBeforeMark());
+
+ // reset(false) shouldn't remove it from the list
+ Assert.assertEquals(true, timeBase.hasObserver(timer));
+ }
+
+ /**
+ * Tests that reset() clears the correct times.
+ */
+ @SmallTest
+ public void testResetDetach() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer = new TestTimer(clocks, 0, timeBase);
+ timer.setCount(1);
+ timer.setLoadedCount(2);
+ timer.setLastCount(3);
+ timer.setUnpluggedCount(4);
+ timer.setTotalTime(9223372036854775807L);
+ timer.setLoadedTime(9223372036854775806L);
+ timer.setLastTime(9223372036854775805L);
+ timer.setUnpluggedTime(9223372036854775804L);
+ timer.setTimeBeforeMark(9223372036854775803L);
+
+ timer.reset(true);
+
+ Assert.assertEquals(0, timer.getCount());
+ Assert.assertEquals(0, timer.getLoadedCount());
+ Assert.assertEquals(0, timer.getLastCount());
+ Assert.assertEquals(4, timer.getUnpluggedCount());
+ Assert.assertEquals(0, timer.getTotalTime());
+ Assert.assertEquals(0, timer.getLoadedTime());
+ Assert.assertEquals(0, timer.getLastTime());
+ Assert.assertEquals(9223372036854775804L, timer.getUnpluggedTime());
+ Assert.assertEquals(0, timer.getTimeBeforeMark());
+
+ // reset(true) should remove it from the list
+ Assert.assertEquals(false, timeBase.hasObserver(timer));
+ }
+
+ /**
+ * Tests reading and writing the summary to a parcel
+ */
+ @SmallTest
+ public void testSummaryParceling() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ timeBase.setRunning(true, 10, 20);
+ timeBase.setRunning(false, 45, 60);
+ Assert.assertEquals(40, timeBase.getRealtime(200));
+ // the past uptime is 35 and the past runtime is 40
+
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer1 = new TestTimer(clocks, 0, timeBase);
+ timer1.setCount(1);
+ timer1.setLoadedCount(2);
+ timer1.setLastCount(3);
+ timer1.setUnpluggedCount(4);
+ timer1.setTotalTime(9223372036854775807L);
+ timer1.setLoadedTime(9223372036854775806L);
+ timer1.setLastTime(9223372036854775805L);
+ timer1.setUnpluggedTime(9223372036854775804L);
+ timer1.setTimeBeforeMark(9223372036854775803L);
+
+ Parcel parcel = Parcel.obtain();
+ timer1.nextComputeRunTime = 9223372036854775800L;
+ timer1.writeSummaryFromParcelLocked(parcel, 201);
+ Assert.assertEquals(40, timer1.lastComputeRunTimeRealtime);
+
+ TestTimer timer2 = new TestTimer(clocks, 0, timeBase);
+
+ // Make sure that all the values get touched
+ timer2.setCount(666);
+ timer2.setLoadedCount(666);
+ timer2.setLastCount(666);
+ timer2.setUnpluggedCount(666);
+ timer2.setTotalTime(666);
+ timer2.setLoadedTime(666);
+ timer2.setLastTime(666);
+ timer2.setUnpluggedTime(666);
+ timer2.setTimeBeforeMark(666);
+
+ parcel.setDataPosition(0);
+
+ parcel.setDataPosition(0);
+ timer2.readSummaryFromParcelLocked(parcel);
+
+ Assert.assertEquals(1, timer2.getCount());
+ Assert.assertEquals(1, timer2.getLoadedCount());
+ Assert.assertEquals(0, timer2.getLastCount());
+ Assert.assertEquals(1, timer2.getUnpluggedCount());
+ Assert.assertEquals(9223372036854775800L, timer2.getTotalTime());
+ Assert.assertEquals(9223372036854775800L, timer2.getLoadedTime());
+ Assert.assertEquals(0, timer2.getLastTime());
+ Assert.assertEquals(9223372036854775800L, timer2.getUnpluggedTime());
+ Assert.assertEquals(9223372036854775800L, timer2.getTimeBeforeMark());
+
+ parcel.recycle();
+ }
+
+ /**
+ * Tests getTotalTimeLocked
+ */
+ @SmallTest
+ public void testGetTotalTimeLocked() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ timeBase.setRunning(true, 10, 20);
+ timeBase.setRunning(false, 45, 60);
+ Assert.assertEquals(40, timeBase.getRealtime(200));
+
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer = new TestTimer(clocks, 0, timeBase);
+ timer.setCount(1);
+ timer.setLoadedCount(2);
+ timer.setLastCount(3);
+ timer.setUnpluggedCount(4);
+ timer.setTotalTime(100);
+ timer.setLoadedTime(200);
+ timer.setLastTime(300);
+ timer.setUnpluggedTime(400);
+ timer.setTimeBeforeMark(500);
+
+ timer.nextComputeRunTime = 10000;
+
+ // Timer.getTotalTimeLocked(STATS_SINCE_CHARGED)
+ timer.lastComputeRunTimeRealtime = -1;
+ Assert.assertEquals(10000,
+ timer.getTotalTimeLocked(66, BatteryStats.STATS_SINCE_CHARGED));
+ Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
+
+ // Timer.getTotalTimeLocked(STATS_CURRENT)
+ timer.lastComputeRunTimeRealtime = -1;
+ Assert.assertEquals(9800, timer.getTotalTimeLocked(66, BatteryStats.STATS_CURRENT));
+ Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
+
+ // Timer.getTotalTimeLocked(STATS_SINCE_UNPLUGGED)
+ timer.lastComputeRunTimeRealtime = -1;
+ Assert.assertEquals(9600, timer.getTotalTimeLocked(66, BatteryStats.STATS_SINCE_UNPLUGGED));
+ Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
+ }
+
+ /**
+ * Tests getCountLocked
+ */
+ @SmallTest
+ public void testGetCountLocked() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ timeBase.setRunning(true, 10, 20);
+ timeBase.setRunning(false, 45, 60);
+ Assert.assertEquals(40, timeBase.getRealtime(200));
+
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer = new TestTimer(clocks, 0, timeBase);
+ timer.setCount(1);
+ timer.setLoadedCount(2);
+ timer.setLastCount(3);
+ timer.setUnpluggedCount(4);
+ timer.setTotalTime(100);
+ timer.setLoadedTime(200);
+ timer.setLastTime(300);
+ timer.setUnpluggedTime(400);
+ timer.setTimeBeforeMark(500);
+
+ // Timer.getCountLocked(STATS_SINCE_CHARGED)
+ timer.nextComputeCurrentCount = 10000;
+ Assert.assertEquals(10000, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+
+ // Timer.getCountLocked(STATS_CURRENT)
+ timer.nextComputeCurrentCount = 10000;
+ Assert.assertEquals(9998, timer.getCountLocked(BatteryStats.STATS_CURRENT));
+
+ // Timer.getCountLocked(STATS_SINCE_UNPLUGGED)
+ timer.nextComputeCurrentCount = 10000;
+ Assert.assertEquals(9996, timer.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
+ }
+
+ /**
+ * Tests getTimeSinceMarkLocked
+ */
+ @SmallTest
+ public void testGetTimeSinceMarked() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ timeBase.setRunning(true, 10, 20);
+ timeBase.setRunning(false, 45, 60);
+ Assert.assertEquals(40, timeBase.getRealtime(200));
+
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer = new TestTimer(clocks, 0, timeBase);
+ timer.setCount(1);
+ timer.setLoadedCount(2);
+ timer.setLastCount(3);
+ timer.setUnpluggedCount(4);
+ timer.setTotalTime(100);
+ timer.setLoadedTime(200);
+ timer.setLastTime(300);
+ timer.setUnpluggedTime(400);
+ timer.setTimeBeforeMark(500);
+
+ timer.nextComputeRunTime = 10000;
+ Assert.assertEquals(9500, timer.getTimeSinceMarkLocked(666));
+ }
+
+ /**
+ * Tests logState
+ */
+ @SmallTest
+ public void testLogState() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer = new TestTimer(clocks, 0, timeBase);
+ timer.setTotalTime(100);
+ timer.setLoadedTime(200);
+ timer.setLastTime(300);
+ timer.setUnpluggedTime(400);
+ timer.setTimeBeforeMark(500);
+ timer.setCount(1);
+ timer.setLoadedCount(2);
+ timer.setLastCount(3);
+ timer.setUnpluggedCount(4);
+ timer.setTotalTime(9223372036854775807L);
+ timer.setLoadedTime(9223372036854775806L);
+ timer.setLastTime(9223372036854775805L);
+ timer.setUnpluggedTime(9223372036854775804L);
+ timer.setTimeBeforeMark(9223372036854775803L);
+
+ StringBuilder sb = new StringBuilder();
+ StringBuilderPrinter pw = new StringBuilderPrinter(sb);
+
+ timer.logState(pw, " ");
+
+ Assert.assertEquals(
+ " mCount=1 mLoadedCount=2 mLastCount=3 mUnpluggedCount=4\n"
+ + " mTotalTime=9223372036854775807 mLoadedTime=9223372036854775806\n"
+ + " mLastTime=9223372036854775805 mUnpluggedTime=9223372036854775804\n",
+ sb.toString());
+ }
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
new file mode 100644
index 0000000..a7e75a2
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import com.android.internal.os.BatteryStatsImpl;
+
+import org.mockito.Mockito;
+
+/**
+ * Provides test cases for android.os.BatteryStats.
+ */
+public class BatteryStatsUidTest extends TestCase {
+ private static final String TAG = "BatteryStatsTimeBaseTest";
+
+ static class TestBsi extends BatteryStatsImpl {
+ TestBsi(MockClocks clocks) {
+ super(clocks);
+ }
+ }
+
+ /**
+ * Test the observers and the setRunning call.
+ */
+ @SmallTest
+ public void testParceling() throws Exception {
+ }
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
new file mode 100644
index 0000000..3924489
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import com.android.internal.os.BatteryStatsImpl;
+
+import org.mockito.Mockito;
+
+/**
+ * Mocks a BatteryStatsImpl object.
+ */
+public class MockBatteryStatsImpl extends BatteryStatsImpl {
+ public BatteryStatsImpl.Clocks clocks;
+
+ MockBatteryStatsImpl() {
+ super(new MockClocks());
+ this.clocks = mClocks;
+ }
+
+ public TimeBase getOnBatteryTimeBase() {
+ return mOnBatteryTimeBase;
+ }
+
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/MockClocks.java b/core/tests/coretests/src/com/android/internal/os/MockClocks.java
new file mode 100644
index 0000000..f750c37
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/MockClocks.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+public class MockClocks implements BatteryStatsImpl.Clocks {
+ public long realtime;
+ public long uptime;
+
+ @Override
+ public long elapsedRealtime() {
+ return realtime;
+ }
+
+ @Override
+ public long uptimeMillis() {
+ return uptime;
+ }
+}
diff --git a/docs/html/preview/behavior-changes.jd b/docs/html/preview/behavior-changes.jd
index cab4163..264e741 100644
--- a/docs/html/preview/behavior-changes.jd
+++ b/docs/html/preview/behavior-changes.jd
@@ -393,7 +393,7 @@
only affects notifications generated by applications in the managed profile.</li>
</ul>
</li>
- <li>The {@link android.app.admin.DevicePolicyManager#createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle) createAndInitializeUser()} and {@link android.app.admin.DevicePolicyManager#createUser(android.content.ComponentName, java.lang.String) createUser()} methods have been deprecated.</li>
+ <li>The {@link android.app.admin.DevicePolicyManager#createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int) createAndManageUser()} method replaces createAndInitializeUser(), which has been removed.</li>
<li>The {@link android.app.admin.DevicePolicyManager#setScreenCaptureDisabled(android.content.ComponentName, boolean) setScreenCaptureDisabled()}
method now also blocks the assist structure when an app of the given user is in the foreground. </li>
<li>{@link android.app.admin.DevicePolicyManager#EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index aa40408..99fa9fe 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -18,6 +18,7 @@
import android.annotation.FloatRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.drawable.Drawable;
/**
@@ -176,6 +177,34 @@
}
/**
+ * Populates {@code outBounds} with the outline bounds, if set, and returns
+ * {@code true}. If no outline bounds are set, or if a path has been set
+ * via {@link #setConvexPath(Path)}, returns {@code false}.
+ *
+ * @param outRect the rect to populate with the outline bounds, if set
+ * @return {@code true} if {@code outBounds} was populated with outline
+ * bounds, or {@code false} if no outline bounds are set
+ */
+ public boolean getRect(@NonNull Rect outRect) {
+ if (mRect == null) {
+ return false;
+ }
+ outRect.set(mRect);
+ return true;
+ }
+
+ /**
+ * Returns the rounded rect radius, if set, or {@code -1} if a path has
+ * been set via {@link #setConvexPath(Path)}. A return value of {@code 0}
+ * indicates a non-rounded rect.
+ *
+ * @return the rounded rect radius or {@code -1}
+ */
+ public float getRadius() {
+ return mRadius;
+ }
+
+ /**
* Sets the outline to the oval defined by input rect.
*/
public void setOval(int left, int top, int right, int bottom) {
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index c486c1f..3901af3 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -154,7 +154,7 @@
private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
/** Local, mutable animator set. */
- private final VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimator(this);
+ private VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimatorRT(this);
/**
* The resources against which this drawable was created. Used to attempt
@@ -164,8 +164,8 @@
private AnimatedVectorDrawableState mAnimatedVectorState;
- /** Whether the animator set has been prepared. */
- private boolean mHasAnimatorSet;
+ /** The animator set that is parsed from the xml. */
+ private AnimatorSet mAnimatorSetFromXml = null;
private boolean mMutated;
@@ -234,9 +234,7 @@
@Override
public void draw(Canvas canvas) {
- if (canvas.isHardwareAccelerated()) {
- mAnimatorSet.recordLastSeenTarget((DisplayListCanvas) canvas);
- }
+ mAnimatorSet.onDraw(canvas);
mAnimatedVectorState.mVectorDrawable.draw(canvas);
}
@@ -392,6 +390,24 @@
mRes = state.mPendingAnims == null ? null : res;
}
+ /**
+ * Force to animate on UI thread.
+ * @hide
+ */
+ public void forceAnimationOnUI() {
+ if (mAnimatorSet instanceof VectorDrawableAnimatorRT) {
+ VectorDrawableAnimatorRT animator = (VectorDrawableAnimatorRT) mAnimatorSet;
+ if (animator.isRunning()) {
+ throw new UnsupportedOperationException("Cannot force Animated Vector Drawable to" +
+ " run on UI thread when the animation has started on RenderThread.");
+ }
+ mAnimatorSet = new VectorDrawableAnimatorUI(this);
+ if (mAnimatorSetFromXml != null) {
+ mAnimatorSet.init(mAnimatorSetFromXml);
+ }
+ }
+ }
+
@Override
public boolean canApplyTheme() {
return (mAnimatedVectorState != null && mAnimatedVectorState.canApplyTheme())
@@ -612,6 +628,7 @@
* Resets the AnimatedVectorDrawable to the start state as specified in the animators.
*/
public void reset() {
+ ensureAnimatorSet();
mAnimatorSet.reset();
}
@@ -623,13 +640,12 @@
@NonNull
private void ensureAnimatorSet() {
- if (!mHasAnimatorSet) {
+ if (mAnimatorSetFromXml == null) {
// TODO: Skip the AnimatorSet creation and init the VectorDrawableAnimator directly
// with a list of LocalAnimators.
- AnimatorSet set = new AnimatorSet();
- mAnimatedVectorState.prepareLocalAnimators(set, mRes);
- mHasAnimatorSet = true;
- mAnimatorSet.initWithAnimatorSet(set);
+ mAnimatorSetFromXml = new AnimatorSet();
+ mAnimatedVectorState.prepareLocalAnimators(mAnimatorSetFromXml, mRes);
+ mAnimatorSet.init(mAnimatorSetFromXml);
mRes = null;
}
}
@@ -724,7 +740,7 @@
// A helper function to clean up the animator listener in the mAnimatorSet.
private void removeAnimatorSetListener() {
if (mAnimatorListener != null) {
- mAnimatorSet.removeListener();
+ mAnimatorSet.removeListener(mAnimatorListener);
mAnimatorListener = null;
}
}
@@ -754,10 +770,100 @@
mAnimationCallbacks.clear();
}
+ private interface VectorDrawableAnimator {
+ void init(AnimatorSet set);
+ void start();
+ void end();
+ void reset();
+ void reverse();
+ boolean canReverse();
+ void setListener(AnimatorListener listener);
+ void removeListener(AnimatorListener listener);
+ void onDraw(Canvas canvas);
+ boolean isStarted();
+ boolean isRunning();
+ }
+
+ private static class VectorDrawableAnimatorUI implements VectorDrawableAnimator {
+ private AnimatorSet mSet = new AnimatorSet();
+ private final Drawable mDrawable;
+
+ VectorDrawableAnimatorUI(AnimatedVectorDrawable drawable) {
+ mDrawable = drawable;
+ }
+
+ @Override
+ public void init(AnimatorSet set) {
+ mSet = set;
+ }
+
+ @Override
+ public void start() {
+ if (mSet.isStarted()) {
+ return;
+ }
+ mSet.start();
+ invalidateOwningView();
+ }
+
+ @Override
+ public void end() {
+ mSet.end();
+ }
+
+ @Override
+ public void reset() {
+ start();
+ mSet.cancel();
+ }
+
+ @Override
+ public void reverse() {
+ mSet.reverse();
+ invalidateOwningView();
+ }
+
+ @Override
+ public boolean canReverse() {
+ return mSet.canReverse();
+ }
+
+ @Override
+ public void setListener(AnimatorListener listener) {
+ mSet.addListener(listener);
+ }
+
+ @Override
+ public void removeListener(AnimatorListener listener) {
+ mSet.removeListener(listener);
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ if (mSet.isStarted()) {
+ invalidateOwningView();
+ }
+ }
+
+ @Override
+ public boolean isStarted() {
+ return mSet.isStarted();
+ }
+
+ @Override
+ public boolean isRunning() {
+ return mSet.isRunning();
+ }
+
+ private void invalidateOwningView() {
+ mDrawable.invalidateSelf();
+ }
+ }
+
/**
* @hide
*/
- public static class VectorDrawableAnimator {
+ public static class VectorDrawableAnimatorRT implements VectorDrawableAnimator {
private static final int NONE = 0;
private static final int START_ANIMATION = 1;
private static final int REVERSE_ANIMATION = 2;
@@ -779,7 +885,7 @@
private int mPendingAnimationAction = NONE;
private final Drawable mDrawable;
- VectorDrawableAnimator(AnimatedVectorDrawable drawable) {
+ VectorDrawableAnimatorRT(AnimatedVectorDrawable drawable) {
mDrawable = drawable;
mSetPtr = nCreateAnimatorSet();
// Increment ref count on native AnimatorSet, so it doesn't get released before Java
@@ -787,7 +893,8 @@
mSetRefBasePtr = new VirtualRefBasePtr(mSetPtr);
}
- private void initWithAnimatorSet(AnimatorSet set) {
+ @Override
+ public void init(AnimatorSet set) {
if (mInitialized) {
// Already initialized
throw new UnsupportedOperationException("VectorDrawableAnimator cannot be " +
@@ -816,7 +923,7 @@
ArrayList<Animator> animators = set.getChildAnimations();
boolean playTogether = set.shouldPlayTogether();
- // Convert AnimatorSet to VectorDrawableAnimator
+ // Convert AnimatorSet to VectorDrawableAnimatorRT
for (int i = 0; i < animators.size(); i++) {
Animator animator = animators.get(i);
// Here we only support ObjectAnimator
@@ -1060,6 +1167,7 @@
mDrawable.invalidateSelf();
}
+ @Override
public void start() {
if (!mInitialized) {
return;
@@ -1083,6 +1191,7 @@
}
}
+ @Override
public void end() {
if (mInitialized && useLastSeenTarget()) {
// If no target has ever been set, no-op
@@ -1091,6 +1200,7 @@
}
}
+ @Override
public void reset() {
if (mInitialized && useLastSeenTarget()) {
// If no target has ever been set, no-op
@@ -1101,7 +1211,8 @@
// Current (imperfect) Java AnimatorSet cannot be reversed when the set contains sequential
// animators or when the animator set has a start delay
- void reverse() {
+ @Override
+ public void reverse() {
if (!mIsReversible || !mInitialized) {
return;
}
@@ -1125,29 +1236,41 @@
return mSetPtr;
}
- boolean canReverse() {
+ @Override
+ public boolean canReverse() {
return mIsReversible;
}
- boolean isStarted() {
+ @Override
+ public boolean isStarted() {
return mStarted;
}
- boolean isRunning() {
+ @Override
+ public boolean isRunning() {
if (!mInitialized) {
return false;
}
return mStarted;
}
- void setListener(AnimatorListener listener) {
+ @Override
+ public void setListener(AnimatorListener listener) {
mListener = listener;
}
- void removeListener() {
+ @Override
+ public void removeListener(AnimatorListener listener) {
mListener = null;
}
+ @Override
+ public void onDraw(Canvas canvas) {
+ if (canvas.isHardwareAccelerated()) {
+ recordLastSeenTarget((DisplayListCanvas) canvas);
+ }
+ }
+
private void onAnimationEnd(int listenerId) {
if (listenerId != mLastListenerId) {
return;
@@ -1162,7 +1285,7 @@
}
// onFinished: should be called from native
- private static void callOnFinished(VectorDrawableAnimator set, int id) {
+ private static void callOnFinished(VectorDrawableAnimatorRT set, int id) {
set.onAnimationEnd(id);
}
}
@@ -1183,8 +1306,8 @@
private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue,
float endValue);
private static native void nSetPropertyHolderData(long nativePtr, float[] data, int length);
- private static native void nStart(long animatorSetPtr, VectorDrawableAnimator set, int id);
- private static native void nReverse(long animatorSetPtr, VectorDrawableAnimator set, int id);
+ private static native void nStart(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
+ private static native void nReverse(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
private static native void nEnd(long animatorSetPtr);
private static native void nReset(long animatorSetPtr);
}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index bfbdfa5..6816539 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -66,11 +66,16 @@
public class NinePatchDrawable extends Drawable {
// dithering helps a lot, and is pretty cheap, so default is true
private static final boolean DEFAULT_DITHER = false;
+
+ /** Temporary rect used for density scaling. */
+ private Rect mTempRect;
+
private NinePatchState mNinePatchState;
- private NinePatch mNinePatch;
private PorterDuffColorFilter mTintFilter;
private Rect mPadding;
private Insets mOpticalInsets = Insets.NONE;
+ private Rect mOutlineInsets;
+ private float mOutlineRadius;
private Paint mPaint;
private boolean mMutated;
@@ -86,8 +91,9 @@
/**
* Create drawable from raw nine-patch data, not dealing with density.
+ *
* @deprecated Use {@link #NinePatchDrawable(Resources, Bitmap, byte[], Rect, String)}
- * to ensure that the drawable has correctly set its target density.
+ * to ensure that the drawable has correctly set its target density.
*/
@Deprecated
public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
@@ -101,7 +107,6 @@
public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
Rect padding, String srcName) {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
- mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
@@ -114,16 +119,17 @@
Rect padding, Rect opticalInsets, String srcName) {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, opticalInsets),
res);
- mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
* Create drawable from existing nine-patch, not dealing with density.
+ *
* @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)}
- * to ensure that the drawable has correctly set its target density.
+ * to ensure that the drawable has correctly set its target
+ * density.
*/
@Deprecated
- public NinePatchDrawable(NinePatch patch) {
+ public NinePatchDrawable(@NonNull NinePatch patch) {
this(new NinePatchState(patch, new Rect()), null);
}
@@ -131,9 +137,8 @@
* Create drawable from existing nine-patch, setting initial target density
* based on the display metrics of the resources.
*/
- public NinePatchDrawable(Resources res, NinePatch patch) {
+ public NinePatchDrawable(@Nullable Resources res, @NonNull NinePatch patch) {
this(new NinePatchState(patch, new Rect()), res);
- mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
@@ -146,7 +151,7 @@
* @see android.graphics.Bitmap#setDensity(int)
* @see android.graphics.Bitmap#getDensity()
*/
- public void setTargetDensity(Canvas canvas) {
+ public void setTargetDensity(@NonNull Canvas canvas) {
setTargetDensity(canvas.getDensity());
}
@@ -158,7 +163,7 @@
* @see android.graphics.Bitmap#setDensity(int)
* @see android.graphics.Bitmap#getDensity()
*/
- public void setTargetDensity(DisplayMetrics metrics) {
+ public void setTargetDensity(@NonNull DisplayMetrics metrics) {
setTargetDensity(metrics.densityDpi);
}
@@ -171,78 +176,24 @@
* @see android.graphics.Bitmap#getDensity()
*/
public void setTargetDensity(int density) {
- if (density != mTargetDensity) {
- mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
- if (mNinePatch != null) {
- computeBitmapSize();
- }
+ if (density == 0) {
+ density = DisplayMetrics.DENSITY_DEFAULT;
+ }
+
+ if (mTargetDensity != density) {
+ mTargetDensity = density;
+
+ computeBitmapSize();
invalidateSelf();
}
}
- private static Insets scaleFromDensity(Insets insets, int sdensity, int tdensity) {
- int left = Drawable.scaleFromDensity(insets.left, sdensity, tdensity, true);
- int top = Drawable.scaleFromDensity(insets.top, sdensity, tdensity, true);
- int right = Drawable.scaleFromDensity(insets.right, sdensity, tdensity, true);
- int bottom = Drawable.scaleFromDensity(insets.bottom, sdensity, tdensity, true);
- return Insets.of(left, top, right, bottom);
- }
-
- private void computeBitmapSize() {
- final int sdensity = mNinePatch.getDensity();
- final int tdensity = mTargetDensity;
- if (sdensity == tdensity) {
- mBitmapWidth = mNinePatch.getWidth();
- mBitmapHeight = mNinePatch.getHeight();
- mOpticalInsets = mNinePatchState.mOpticalInsets;
- } else {
- mBitmapWidth = Drawable.scaleFromDensity(
- mNinePatch.getWidth(), sdensity, tdensity, true);
- mBitmapHeight = Drawable.scaleFromDensity(
- mNinePatch.getHeight(), sdensity, tdensity, true);
- if (mNinePatchState.mPadding != null && mPadding != null) {
- Rect dest = mPadding;
- Rect src = mNinePatchState.mPadding;
- if (dest == src) {
- mPadding = dest = new Rect(src);
- }
- dest.left = Drawable.scaleFromDensity(src.left, sdensity, tdensity, true);
- dest.top = Drawable.scaleFromDensity(src.top, sdensity, tdensity, true);
- dest.right = Drawable.scaleFromDensity(src.right, sdensity, tdensity, true);
- dest.bottom = Drawable.scaleFromDensity(src.bottom, sdensity, tdensity, true);
- }
- mOpticalInsets = scaleFromDensity(mNinePatchState.mOpticalInsets, sdensity, tdensity);
- }
- }
-
- /**
- * Sets the nine patch used by this drawable.
- *
- * @param ninePatch the nine patch for this drawable
- */
- public void setNinePatch(NinePatch ninePatch) {
- if (mNinePatch != ninePatch) {
- mNinePatch = ninePatch;
- if (ninePatch != null) {
- computeBitmapSize();
- } else {
- mBitmapWidth = mBitmapHeight = -1;
- mOpticalInsets = Insets.NONE;
- }
- invalidateSelf();
- }
- }
-
- /**
- * @return the nine patch used by this drawable
- */
- public NinePatch getNinePatch() {
- return mNinePatch;
- }
-
@Override
public void draw(Canvas canvas) {
- final Rect bounds = getBounds();
+ final NinePatchState state = mNinePatchState;
+
+ Rect bounds = getBounds();
+ int restoreToCount = -1;
final boolean clearColorFilter;
if (mTintFilter != null && getPaint().getColorFilter() == null) {
@@ -252,22 +203,52 @@
clearColorFilter = false;
}
- final boolean needsMirroring = needsMirroring();
- if (needsMirroring) {
- // Mirror the 9patch
- canvas.translate(bounds.right - bounds.left, 0);
- canvas.scale(-1.0f, 1.0f);
- }
-
final int restoreAlpha;
- if (mNinePatchState.mBaseAlpha != 1.0f) {
- restoreAlpha = mPaint.getAlpha();
- mPaint.setAlpha((int) (restoreAlpha * mNinePatchState.mBaseAlpha + 0.5f));
+ if (state.mBaseAlpha != 1.0f) {
+ restoreAlpha = getPaint().getAlpha();
+ mPaint.setAlpha((int) (restoreAlpha * state.mBaseAlpha + 0.5f));
} else {
restoreAlpha = -1;
}
- mNinePatch.draw(canvas, bounds, mPaint);
+ final boolean needsDensityScaling = canvas.getDensity() == 0;
+ if (needsDensityScaling) {
+ restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
+
+ // Apply density scaling.
+ final float scale = mTargetDensity / (float) state.mNinePatch.getDensity();
+ final float px = bounds.left;
+ final float py = bounds.top;
+ canvas.scale(scale, scale, px, py);
+
+ if (mTempRect == null) {
+ mTempRect = new Rect();
+ }
+
+ // Scale the bounds to match.
+ final Rect scaledBounds = mTempRect;
+ scaledBounds.left = bounds.left;
+ scaledBounds.top = bounds.top;
+ scaledBounds.right = bounds.left + Math.round(bounds.width() / scale);
+ scaledBounds.bottom = bounds.top + Math.round(bounds.height() / scale);
+ bounds = scaledBounds;
+ }
+
+ final boolean needsMirroring = needsMirroring();
+ if (needsMirroring) {
+ restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
+
+ // Mirror the 9patch.
+ final float cx = (bounds.left + bounds.right) / 2.0f;
+ final float cy = (bounds.top + bounds.bottom) / 2.0f;
+ canvas.scale(-1.0f, 1.0f, cx, cy);
+ }
+
+ state.mNinePatch.draw(canvas, bounds, mPaint);
+
+ if (restoreToCount >= 0) {
+ canvas.restoreToCount(restoreToCount);
+ }
if (clearColorFilter) {
mPaint.setColorFilter(null);
@@ -284,38 +265,36 @@
}
@Override
- public boolean getPadding(Rect padding) {
- final Rect scaledPadding = mPadding;
- if (scaledPadding != null) {
- if (needsMirroring()) {
- padding.set(scaledPadding.right, scaledPadding.top,
- scaledPadding.left, scaledPadding.bottom);
- } else {
- padding.set(scaledPadding);
- }
+ public boolean getPadding(@NonNull Rect padding) {
+ if (mPadding != null) {
+ padding.set(mPadding);
return (padding.left | padding.top | padding.right | padding.bottom) != 0;
+ } else {
+ return super.getPadding(padding);
}
- return false;
}
@Override
public void getOutline(@NonNull Outline outline) {
final Rect bounds = getBounds();
- if (bounds.isEmpty()) return;
+ if (bounds.isEmpty()) {
+ return;
+ }
- if (mNinePatchState != null) {
- NinePatch.InsetStruct insets = mNinePatchState.mNinePatch.getBitmap().getNinePatchInsets();
+ if (mNinePatchState != null && mOutlineInsets != null) {
+ final NinePatch.InsetStruct insets =
+ mNinePatchState.mNinePatch.getBitmap().getNinePatchInsets();
if (insets != null) {
- final Rect outlineInsets = insets.outlineRect;
- outline.setRoundRect(bounds.left + outlineInsets.left,
- bounds.top + outlineInsets.top,
- bounds.right - outlineInsets.right,
- bounds.bottom - outlineInsets.bottom,
- insets.outlineRadius);
+ outline.setRoundRect(bounds.left + mOutlineInsets.left,
+ bounds.top + mOutlineInsets.top,
+ bounds.right - mOutlineInsets.right,
+ bounds.bottom - mOutlineInsets.bottom,
+ mOutlineRadius);
outline.setAlpha(insets.outlineAlpha * (getAlpha() / 255.0f));
return;
}
}
+
super.getOutline(outline);
}
@@ -324,11 +303,12 @@
*/
@Override
public Insets getOpticalInsets() {
+ final Insets opticalInsets = mOpticalInsets;
if (needsMirroring()) {
- return Insets.of(mOpticalInsets.right, mOpticalInsets.top,
- mOpticalInsets.left, mOpticalInsets.bottom);
+ return Insets.of(opticalInsets.right, opticalInsets.top,
+ opticalInsets.left, opticalInsets.bottom);
} else {
- return mOpticalInsets;
+ return opticalInsets;
}
}
@@ -352,7 +332,7 @@
}
@Override
- public void setColorFilter(ColorFilter colorFilter) {
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
if (mPaint == null && colorFilter == null) {
// Fast common case -- leave at no color filter.
return;
@@ -362,14 +342,14 @@
}
@Override
- public void setTintList(ColorStateList tint) {
+ public void setTintList(@Nullable ColorStateList tint) {
mNinePatchState.mTint = tint;
mTintFilter = updateTintFilter(mTintFilter, tint, mNinePatchState.mTintMode);
invalidateSelf();
}
@Override
- public void setTintMode(PorterDuff.Mode tintMode) {
+ public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
mNinePatchState.mTintMode = tintMode;
mTintFilter = updateTintFilter(mTintFilter, mNinePatchState.mTint, tintMode);
invalidateSelf();
@@ -409,10 +389,7 @@
@Override
public boolean isFilterBitmap() {
- if (mPaint == null) {
- return false;
- }
- return getPaint().isFilterBitmap();
+ return mPaint != null && getPaint().isFilterBitmap();
}
@Override
@@ -430,7 +407,7 @@
/**
* Updates the constant state from the values in the typed array.
*/
- private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+ private void updateStateFromTypedArray(@NonNull TypedArray a) throws XmlPullParserException {
final Resources r = a.getResources();
final NinePatchState state = mNinePatchState;
@@ -491,12 +468,10 @@
if (tint != null) {
state.mTint = tint;
}
-
- state.mTargetDensity = Drawable.resolveDensity(r, state.mTargetDensity);
}
@Override
- public void applyTheme(Theme t) {
+ public void applyTheme(@NonNull Theme t) {
super.applyTheme(t);
final NinePatchState state = mNinePatchState;
@@ -528,6 +503,7 @@
return mNinePatchState != null && mNinePatchState.canApplyTheme();
}
+ @NonNull
public Paint getPaint() {
if (mPaint == null) {
mPaint = new Paint();
@@ -536,45 +512,26 @@
return mPaint;
}
- /**
- * Retrieves the width of the source .png file (before resizing).
- */
@Override
public int getIntrinsicWidth() {
return mBitmapWidth;
}
- /**
- * Retrieves the height of the source .png file (before resizing).
- */
@Override
public int getIntrinsicHeight() {
return mBitmapHeight;
}
@Override
- public int getMinimumWidth() {
- return mBitmapWidth;
- }
-
- @Override
- public int getMinimumHeight() {
- return mBitmapHeight;
- }
-
- /**
- * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat}
- * value of OPAQUE or TRANSLUCENT.
- */
- @Override
public int getOpacity() {
- return mNinePatch.hasAlpha() || (mPaint != null && mPaint.getAlpha() < 255) ?
- PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
+ return mNinePatchState.mNinePatch.hasAlpha()
+ || (mPaint != null && mPaint.getAlpha() < 255) ?
+ PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
}
@Override
public Region getTransparentRegion() {
- return mNinePatch.getTransparentRegion(getBounds());
+ return mNinePatchState.mNinePatch.getTransparentRegion(getBounds());
}
@Override
@@ -587,7 +544,6 @@
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
mNinePatchState = new NinePatchState(mNinePatchState);
- mNinePatch = mNinePatchState.mNinePatch;
mMutated = true;
}
return this;
@@ -619,8 +575,9 @@
}
final static class NinePatchState extends ConstantState {
+ int mChangingConfigurations;
+
// Values loaded during inflation.
- int[] mThemeAttrs = null;
NinePatch mNinePatch = null;
ColorStateList mTint = null;
Mode mTintMode = DEFAULT_TINT_MODE;
@@ -628,10 +585,9 @@
Insets mOpticalInsets = Insets.NONE;
float mBaseAlpha = 1.0f;
boolean mDither = DEFAULT_DITHER;
- int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
boolean mAutoMirrored = false;
- int mChangingConfigurations;
+ int[] mThemeAttrs;
NinePatchState() {
// Empty constructor.
@@ -655,27 +611,24 @@
mAutoMirrored = autoMirror;
}
- // Copy constructor
-
- NinePatchState(@NonNull NinePatchState state) {
- // We don't deep-copy any fields because they are all immutable.
- mNinePatch = state.mNinePatch;
- mTint = state.mTint;
- mTintMode = state.mTintMode;
- mThemeAttrs = state.mThemeAttrs;
- mPadding = state.mPadding;
- mOpticalInsets = state.mOpticalInsets;
- mBaseAlpha = state.mBaseAlpha;
- mDither = state.mDither;
- mChangingConfigurations = state.mChangingConfigurations;
- mTargetDensity = state.mTargetDensity;
- mAutoMirrored = state.mAutoMirrored;
+ NinePatchState(@NonNull NinePatchState orig) {
+ mChangingConfigurations = orig.mChangingConfigurations;
+ mNinePatch = orig.mNinePatch;
+ mTint = orig.mTint;
+ mTintMode = orig.mTintMode;
+ mPadding = orig.mPadding;
+ mOpticalInsets = orig.mOpticalInsets;
+ mBaseAlpha = orig.mBaseAlpha;
+ mDither = orig.mDither;
+ mAutoMirrored = orig.mAutoMirrored;
+ mThemeAttrs = orig.mThemeAttrs;
}
@Override
public boolean canApplyTheme() {
return mThemeAttrs != null
- || (mTint != null && mTint.canApplyTheme());
+ || (mTint != null && mTint.canApplyTheme())
+ || super.canApplyTheme();
}
@Override
@@ -704,44 +657,98 @@
}
}
+ private void computeBitmapSize() {
+ final NinePatch ninePatch = mNinePatchState.mNinePatch;
+ if (ninePatch == null) {
+ return;
+ }
+
+ final int sourceDensity = ninePatch.getDensity();
+ final int targetDensity = mTargetDensity;
+
+ final Insets sourceOpticalInsets = mNinePatchState.mOpticalInsets;
+ if (sourceOpticalInsets != Insets.NONE) {
+ final int left = Drawable.scaleFromDensity(
+ sourceOpticalInsets.left, sourceDensity, targetDensity, true);
+ final int top = Drawable.scaleFromDensity(
+ sourceOpticalInsets.top, sourceDensity, targetDensity, true);
+ final int right = Drawable.scaleFromDensity(
+ sourceOpticalInsets.right, sourceDensity, targetDensity, true);
+ final int bottom = Drawable.scaleFromDensity(
+ sourceOpticalInsets.bottom, sourceDensity, targetDensity, true);
+ mOpticalInsets = Insets.of(left, top, right, bottom);
+ } else {
+ mOpticalInsets = Insets.NONE;
+ }
+
+ final Rect sourcePadding = mNinePatchState.mPadding;
+ if (sourcePadding != null) {
+ if (mPadding == null) {
+ mPadding = new Rect();
+ }
+ mPadding.left = Drawable.scaleFromDensity(
+ sourcePadding.left, sourceDensity, targetDensity, false);
+ mPadding.top = Drawable.scaleFromDensity(
+ sourcePadding.top, sourceDensity, targetDensity, false);
+ mPadding.right = Drawable.scaleFromDensity(
+ sourcePadding.right, sourceDensity, targetDensity, false);
+ mPadding.bottom = Drawable.scaleFromDensity(
+ sourcePadding.bottom, sourceDensity, targetDensity, false);
+ } else {
+ mPadding = null;
+ }
+
+ mBitmapHeight = Drawable.scaleFromDensity(
+ ninePatch.getHeight(), sourceDensity, targetDensity, true);
+ mBitmapWidth = Drawable.scaleFromDensity(
+ ninePatch.getWidth(), sourceDensity, targetDensity, true);
+
+ final NinePatch.InsetStruct insets = ninePatch.getBitmap().getNinePatchInsets();
+ if (insets != null) {
+ if (mOutlineInsets == null) {
+ mOutlineInsets = new Rect();
+ }
+ final Rect outlineInsets = insets.outlineRect;
+ mOutlineInsets.left = Drawable.scaleFromDensity(
+ outlineInsets.left, sourceDensity, targetDensity, false);
+ mOutlineInsets.top = Drawable.scaleFromDensity(
+ outlineInsets.top, sourceDensity, targetDensity, false);
+ mOutlineInsets.right = Drawable.scaleFromDensity(
+ outlineInsets.right, sourceDensity, targetDensity, false);
+ mOutlineInsets.bottom = Drawable.scaleFromDensity(
+ outlineInsets.bottom, sourceDensity, targetDensity, false);
+ mOutlineRadius = Drawable.scaleFromDensity(
+ insets.outlineRadius, sourceDensity, targetDensity);
+ } else {
+ mOutlineInsets = null;
+ }
+ }
+
/**
* The one constructor to rule them all. This is called by all public
* constructors to set the state and initialize local properties.
+ *
+ * @param state constant state to assign to the new drawable
*/
- private NinePatchDrawable(NinePatchState state, Resources res) {
+ private NinePatchDrawable(@NonNull NinePatchState state, @Nullable Resources res) {
mNinePatchState = state;
updateLocalState(res);
-
- // Push density applied by setNinePatchState into state.
- mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
* Initializes local dynamic properties from state.
*/
- private void updateLocalState(Resources res) {
+ private void updateLocalState(@Nullable Resources res) {
final NinePatchState state = mNinePatchState;
- if (res != null) {
- final int densityDpi = res.getDisplayMetrics().densityDpi;
- mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
- } else {
- mTargetDensity = state.mTargetDensity;
- }
-
-
// If we can, avoid calling any methods that initialize Paint.
if (state.mDither != DEFAULT_DITHER) {
setDither(state.mDither);
}
- // Make a local copy of the padding.
- if (state.mPadding != null) {
- mPadding = new Rect(state.mPadding);
- }
-
+ mTargetDensity = Drawable.resolveDensity(res, mTargetDensity);
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
- setNinePatch(state.mNinePatch);
+ computeBitmapSize();
}
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 1321a83..b234d0f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -234,7 +234,8 @@
KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
spec.isUserAuthenticationRequired(),
spec.getUserAuthenticationValidityDurationSeconds(),
- spec.isUserAuthenticationValidWhileOnBody());
+ spec.isUserAuthenticationValidWhileOnBody(),
+ spec.isInvalidatedByBiometricEnrollment());
} catch (IllegalStateException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -273,7 +274,8 @@
KeymasterUtils.addUserAuthArgs(args,
spec.isUserAuthenticationRequired(),
spec.getUserAuthenticationValidityDurationSeconds(),
- spec.isUserAuthenticationValidWhileOnBody());
+ spec.isUserAuthenticationValidWhileOnBody(),
+ spec.isInvalidatedByBiometricEnrollment());
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
mKeymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 830402a..1818f52 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -345,7 +345,8 @@
KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
mSpec.isUserAuthenticationRequired(),
mSpec.getUserAuthenticationValidityDurationSeconds(),
- mSpec.isUserAuthenticationValidWhileOnBody());
+ mSpec.isUserAuthenticationValidWhileOnBody(),
+ mSpec.isInvalidatedByBiometricEnrollment());
} catch (IllegalArgumentException | IllegalStateException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -531,7 +532,8 @@
KeymasterUtils.addUserAuthArgs(args,
mSpec.isUserAuthenticationRequired(),
mSpec.getUserAuthenticationValidityDurationSeconds(),
- mSpec.isUserAuthenticationValidWhileOnBody());
+ mSpec.isUserAuthenticationValidWhileOnBody(),
+ mSpec.isInvalidatedByBiometricEnrollment());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
mSpec.getKeyValidityForOriginationEnd());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 5f5f2c2..0379863 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -17,10 +17,12 @@
package android.security.keystore;
import android.security.Credentials;
+import android.security.GateKeeper;
import android.security.KeyStore;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterDefs;
+import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.ProviderException;
import java.security.spec.InvalidKeySpecException;
@@ -91,6 +93,7 @@
@KeyProperties.BlockModeEnum String[] blockModes;
int keymasterSwEnforcedUserAuthenticators;
int keymasterHwEnforcedUserAuthenticators;
+ List<BigInteger> keymasterSecureUserIds;
try {
if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
insideSecureHardware = true;
@@ -147,6 +150,8 @@
keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
keymasterHwEnforcedUserAuthenticators =
keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
+ keymasterSecureUserIds =
+ keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
} catch (IllegalArgumentException e) {
throw new ProviderException("Unsupported key characteristic", e);
}
@@ -170,6 +175,15 @@
boolean userAuthenticationValidWhileOnBody =
keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
+ boolean invalidatedByBiometricEnrollment = false;
+ if (keymasterSwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_FINGERPRINT
+ || keymasterHwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_FINGERPRINT) {
+ // Fingerprint-only key; will be invalidated if the root SID isn't in the SID list.
+ invalidatedByBiometricEnrollment = keymasterSecureUserIds != null
+ && !keymasterSecureUserIds.isEmpty()
+ && !keymasterSecureUserIds.contains(getGateKeeperSecureUserId());
+ }
+
return new KeyInfo(entryAlias,
insideSecureHardware,
origin,
@@ -185,7 +199,16 @@
userAuthenticationRequired,
(int) userAuthenticationValidityDurationSeconds,
userAuthenticationRequirementEnforcedBySecureHardware,
- userAuthenticationValidWhileOnBody);
+ userAuthenticationValidWhileOnBody,
+ invalidatedByBiometricEnrollment);
+ }
+
+ private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
+ try {
+ return BigInteger.valueOf(GateKeeper.getSecureUserId());
+ } catch (IllegalStateException e) {
+ throw new ProviderException("Failed to get GateKeeper secure user ID", e);
+ }
}
@Override
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index d660020..d7d4f1c 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -499,7 +499,8 @@
KeymasterUtils.addUserAuthArgs(importArgs,
spec.isUserAuthenticationRequired(),
spec.getUserAuthenticationValidityDurationSeconds(),
- spec.isUserAuthenticationValidWhileOnBody());
+ spec.isUserAuthenticationValidWhileOnBody(),
+ spec.isInvalidatedByBiometricEnrollment());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
spec.getKeyValidityStart());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
@@ -694,7 +695,8 @@
KeymasterUtils.addUserAuthArgs(args,
params.isUserAuthenticationRequired(),
params.getUserAuthenticationValidityDurationSeconds(),
- params.isUserAuthenticationValidWhileOnBody());
+ params.isUserAuthenticationValidWhileOnBody(),
+ params.isInvalidatedByBiometricEnrollment());
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
keymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index a84e7f34..127d756 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -253,6 +253,7 @@
private final byte[] mAttestationChallenge;
private final boolean mUniqueIdIncluded;
private final boolean mUserAuthenticationValidWhileOnBody;
+ private final boolean mInvalidatedByBiometricEnrollment;
/**
* @hide should be built with Builder
@@ -279,7 +280,8 @@
int userAuthenticationValidityDurationSeconds,
byte[] attestationChallenge,
boolean uniqueIdIncluded,
- boolean userAuthenticationValidWhileOnBody) {
+ boolean userAuthenticationValidWhileOnBody,
+ boolean invalidatedByBiometricEnrollment) {
if (TextUtils.isEmpty(keyStoreAlias)) {
throw new IllegalArgumentException("keyStoreAlias must not be empty");
}
@@ -324,6 +326,7 @@
mAttestationChallenge = Utils.cloneIfNotNull(attestationChallenge);
mUniqueIdIncluded = uniqueIdIncluded;
mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
+ mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
}
/**
@@ -607,6 +610,19 @@
}
/**
+ * Returns {@code true} if the key is irreversibly invalidated when a new fingerprint is
+ * enrolled or all enrolled fingerprints are removed. This has effect only for keys that
+ * require fingerprint user authentication for every use.
+ *
+ * @see #isUserAuthenticationRequired()
+ * @see #getUserAuthenticationValidityDurationSeconds()
+ * @see Builder#setInvalidatedByBiometricEnrollment(boolean)
+ */
+ public boolean isInvalidatedByBiometricEnrollment() {
+ return mInvalidatedByBiometricEnrollment;
+ }
+
+ /**
* Builder of {@link KeyGenParameterSpec} instances.
*/
public final static class Builder {
@@ -633,6 +649,7 @@
private byte[] mAttestationChallenge = null;
private boolean mUniqueIdIncluded = false;
private boolean mUserAuthenticationValidWhileOnBody;
+ private boolean mInvalidatedByBiometricEnrollment = true;
/**
* Creates a new instance of the {@code Builder}.
@@ -966,8 +983,10 @@
* or when the secure lock screen is forcibly reset (e.g., by a Device Administrator).
* Additionally, if the key requires that user authentication takes place for every use of
* the key, it is also irreversibly invalidated once a new fingerprint is enrolled or once\
- * no more fingerprints are enrolled. Attempts to initialize cryptographic operations using
- * such keys will throw {@link KeyPermanentlyInvalidatedException}.</li>
+ * no more fingerprints are enrolled, unless {@link
+ * #setInvalidatedByBiometricEnrollment(boolean)} is used to allow validity after
+ * enrollment. Attempts to initialize cryptographic operations using such keys will throw
+ * {@link KeyPermanentlyInvalidatedException}.</li>
* </ul>
*
* <p>This authorization applies only to secret key and private key operations. Public key
@@ -1110,6 +1129,30 @@
}
/**
+ * Sets whether this key should be invalidated on fingerprint enrollment. This
+ * applies only to keys which require user authentication (see {@link
+ * #setUserAuthenticationRequired(boolean)}) and if no positive validity duration has been
+ * set (see {@link #setUserAuthenticationValidityDurationSeconds(int)}, meaning the key is
+ * valid for fingerprint authentication only.
+ *
+ * <p>By default, {@code invalidateKey} is {@code true}, so keys that are valid for
+ * fingerprint authentication only are <em>irreversibly invalidated</em> when a new
+ * fingerprint is enrolled, or when all existing fingerprints are deleted. That may be
+ * changed by calling this method with {@code invalidateKey} set to {@code false}.
+ *
+ * <p>Invalidating keys on enrollment of a new finger or unenrollment of all fingers
+ * improves security by ensuring that an unauthorized person who obtains the password can't
+ * gain the use of fingerprint-authenticated keys by enrolling their own finger. However,
+ * invalidating keys makes key-dependent operations impossible, requiring some fallback
+ * procedure to authenticate the user and set up a new key.
+ */
+ @NonNull
+ public Builder setInvalidatedByBiometricEnrollment(boolean invalidateKey) {
+ mInvalidatedByBiometricEnrollment = invalidateKey;
+ return this;
+ }
+
+ /**
* Builds an instance of {@code KeyGenParameterSpec}.
*/
@NonNull
@@ -1136,7 +1179,8 @@
mUserAuthenticationValidityDurationSeconds,
mAttestationChallenge,
mUniqueIdIncluded,
- mUserAuthenticationValidWhileOnBody);
+ mUserAuthenticationValidWhileOnBody,
+ mInvalidatedByBiometricEnrollment);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java
index f77b5ba..fa6d8b3 100644
--- a/keystore/java/android/security/keystore/KeyInfo.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -80,6 +80,7 @@
private final int mUserAuthenticationValidityDurationSeconds;
private final boolean mUserAuthenticationRequirementEnforcedBySecureHardware;
private final boolean mUserAuthenticationValidWhileOnBody;
+ private final boolean mInvalidatedByBiometricEnrollment;
/**
* @hide
@@ -99,7 +100,8 @@
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
boolean userAuthenticationRequirementEnforcedBySecureHardware,
- boolean userAuthenticationValidWhileOnBody) {
+ boolean userAuthenticationValidWhileOnBody,
+ boolean invalidatedByBiometricEnrollment) {
mKeystoreAlias = keystoreKeyAlias;
mInsideSecureHardware = insideSecureHardware;
mOrigin = origin;
@@ -119,6 +121,7 @@
mUserAuthenticationRequirementEnforcedBySecureHardware =
userAuthenticationRequirementEnforcedBySecureHardware;
mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
+ mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
}
/**
@@ -290,4 +293,12 @@
public boolean isUserAuthenticationValidWhileOnBody() {
return mUserAuthenticationValidWhileOnBody;
}
+
+ /**
+ * Returns {@code true} if the key will be invalidated by enrollment of a new fingerprint or
+ * removal of all fingerprints.
+ */
+ public boolean isInvalidatedByBiometricEnrollment() {
+ return mInvalidatedByBiometricEnrollment;
+ }
}
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 4700b68..fa57bdb 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -215,6 +215,7 @@
private final boolean mUserAuthenticationRequired;
private final int mUserAuthenticationValidityDurationSeconds;
private final boolean mUserAuthenticationValidWhileOnBody;
+ private final boolean mInvalidatedByBiometricEnrollment;
private KeyProtection(
Date keyValidityStart,
@@ -228,7 +229,8 @@
boolean randomizedEncryptionRequired,
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
- boolean userAuthenticationValidWhileOnBody) {
+ boolean userAuthenticationValidWhileOnBody,
+ boolean invalidatedByBiometricEnrollment) {
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -243,6 +245,7 @@
mUserAuthenticationRequired = userAuthenticationRequired;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
+ mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
}
/**
@@ -412,6 +415,19 @@
}
/**
+ * Returns {@code true} if the key is irreversibly invalidated when a new fingerprint is
+ * enrolled or all enrolled fingerprints are removed. This has effect only for keys that
+ * require fingerprint user authentication for every use.
+ *
+ * @see #isUserAuthenticationRequired()
+ * @see #getUserAuthenticationValidityDurationSeconds()
+ * @see Builder#setInvalidatedByBiometricEnrollment(boolean)
+ */
+ public boolean isInvalidatedByBiometricEnrollment() {
+ return mInvalidatedByBiometricEnrollment;
+ }
+
+ /**
* Builder of {@link KeyProtection} instances.
*/
public final static class Builder {
@@ -428,6 +444,7 @@
private boolean mUserAuthenticationRequired;
private int mUserAuthenticationValidityDurationSeconds = -1;
private boolean mUserAuthenticationValidWhileOnBody;
+ private boolean mInvalidatedByBiometricEnrollment = true;
/**
* Creates a new instance of the {@code Builder}.
@@ -638,9 +655,10 @@
* or when the secure lock screen is forcibly reset (e.g., by a Device Administrator).
* Additionally, if the key requires that user authentication takes place for every use of
* the key, it is also irreversibly invalidated once a new fingerprint is enrolled or once\
- * no more fingerprints are enrolled. Attempts to initialize cryptographic operations using
- * such keys will throw {@link KeyPermanentlyInvalidatedException}.</li>
- * </ul>
+ * no more fingerprints are enrolled, unless {@link
+ * #setInvalidatedByBiometricEnrollment(boolean)} is used to allow validity after
+ * enrollment. Attempts to initialize cryptographic operations using such keys will throw
+ * {@link KeyPermanentlyInvalidatedException}.</li> </ul>
*
* <p>This authorization applies only to secret key and private key operations. Public key
* operations are not restricted.
@@ -729,6 +747,30 @@
}
/**
+ * Sets whether this key should be invalidated on fingerprint enrollment. This
+ * applies only to keys which require user authentication (see {@link
+ * #setUserAuthenticationRequired(boolean)}) and if no positive validity duration has been
+ * set (see {@link #setUserAuthenticationValidityDurationSeconds(int)}, meaning the key is
+ * valid for fingerprint authentication only.
+ *
+ * <p>By default, {@code invalidateKey} is {@code true}, so keys that are valid for
+ * fingerprint authentication only are <em>irreversibly invalidated</em> when a new
+ * fingerprint is enrolled, or when all existing fingerprints are deleted. That may be
+ * changed by calling this method with {@code invalidateKey} set to {@code false}.
+ *
+ * <p>Invalidating keys on enrollment of a new finger or unenrollment of all fingers
+ * improves security by ensuring that an unauthorized person who obtains the password can't
+ * gain the use of fingerprint-authenticated keys by enrolling their own finger. However,
+ * invalidating keys makes key-dependent operations impossible, requiring some fallback
+ * procedure to authenticate the user and set up a new key.
+ */
+ @NonNull
+ public Builder setInvalidatedByBiometricEnrollment(boolean invalidateKey) {
+ mInvalidatedByBiometricEnrollment = invalidateKey;
+ return this;
+ }
+
+ /**
* Builds an instance of {@link KeyProtection}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -747,7 +789,8 @@
mRandomizedEncryptionRequired,
mUserAuthenticationRequired,
mUserAuthenticationValidityDurationSeconds,
- mUserAuthenticationValidWhileOnBody);
+ mUserAuthenticationValidWhileOnBody,
+ mInvalidatedByBiometricEnrollment);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 3a008bc..f5272aa 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -97,7 +97,8 @@
public static void addUserAuthArgs(KeymasterArguments args,
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
- boolean userAuthenticationValidWhileOnBody) {
+ boolean userAuthenticationValidWhileOnBody,
+ boolean invalidatedByBiometricEnrollment) {
if (!userAuthenticationRequired) {
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
return;
@@ -117,8 +118,20 @@
"At least one fingerprint must be enrolled to create keys requiring user"
+ " authentication for every use");
}
- args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
- KeymasterArguments.toUint64(fingerprintOnlySid));
+
+ long sid;
+ if (invalidatedByBiometricEnrollment) {
+ // The fingerprint-only SID will change on fingerprint enrollment or removal of all,
+ // enrolled fingerprints, invalidating the key.
+ sid = fingerprintOnlySid;
+ } else {
+ // The root SID will *not* change on fingerprint enrollment, or removal of all
+ // enrolled fingerprints, allowing the key to remain valid.
+ sid = getRootSid();
+ }
+
+ args.addUnsignedLong(
+ KeymasterDefs.KM_TAG_USER_SECURE_ID, KeymasterArguments.toUint64(sid));
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
if (userAuthenticationValidWhileOnBody) {
throw new ProviderException("Key validity extension while device is on-body is not "
@@ -127,11 +140,7 @@
} else {
// The key is authorized for use for the specified amount of time after the user has
// authenticated. Whatever unlocks the secure lock screen should authorize this key.
- long rootSid = GateKeeper.getSecureUserId();
- if (rootSid == 0) {
- throw new IllegalStateException("Secure lock screen must be enabled"
- + " to create keys requiring user authentication");
- }
+ long rootSid = getRootSid();
args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
KeymasterArguments.toUint64(rootSid));
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
@@ -184,4 +193,13 @@
break;
}
}
+
+ private static long getRootSid() {
+ long rootSid = GateKeeper.getSecureUserId();
+ if (rootSid == 0) {
+ throw new IllegalStateException("Secure lock screen must be enabled"
+ + " to create keys requiring user authentication");
+ }
+ return rootSid;
+ }
}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 8660b75..da7b7fb 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -119,6 +119,7 @@
BakedOpState.cpp \
FrameBuilder.cpp \
LayerBuilder.cpp \
+ OpDumper.cpp \
RecordingCanvas.cpp
hwui_cflags += -DHWUI_NEW_OPS
@@ -253,6 +254,7 @@
tests/unit/BakedOpStateTests.cpp \
tests/unit/FrameBuilderTests.cpp \
tests/unit/LeakCheckTests.cpp \
+ tests/unit/OpDumperTests.cpp \
tests/unit/RecordingCanvasTests.cpp
endif
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 1c25f26..36007cd 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-#ifndef ANDROID_HWUI_MATRIX_H
-#define ANDROID_HWUI_MATRIX_H
-
-#include <SkMatrix.h>
-
-#include <cutils/compiler.h>
+#pragma once
#include "Rect.h"
+#include <cutils/compiler.h>
+#include <iomanip>
+#include <ostream>
+#include <SkMatrix.h>
+
namespace android {
namespace uirenderer {
@@ -218,6 +218,22 @@
void dump(const char* label = nullptr) const;
+ friend std::ostream& operator<<(std::ostream& os, const Matrix4& matrix) {
+ if (matrix.isSimple()) {
+ os << "offset " << matrix.getTranslateX() << "x" << matrix.getTranslateY();
+ if (!matrix.isPureTranslate()) {
+ os << ", scale " << matrix[kScaleX] << "x" << matrix[kScaleY];
+ }
+ } else {
+ os << "[" << matrix[0];
+ for (int i = 1; i < 16; i++) {
+ os << ", " << matrix[i];
+ }
+ os << "]";
+ }
+ return os;
+ }
+
static const Matrix4& identity();
private:
@@ -244,4 +260,3 @@
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_HWUI_MATRIX_H
diff --git a/libs/hwui/OpDumper.cpp b/libs/hwui/OpDumper.cpp
new file mode 100644
index 0000000..c34cfbe
--- /dev/null
+++ b/libs/hwui/OpDumper.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "OpDumper.h"
+
+#include "RecordedOp.h"
+
+namespace android {
+namespace uirenderer {
+
+#define STRINGIFY(n) #n,
+static const char* sOpNameLut[] = BUILD_FULL_OP_LUT(STRINGIFY);
+
+void OpDumper::dump(const RecordedOp& op, std::ostream& output, int level) {
+ for (int i = 0; i < level; i++) {
+ output << " ";
+ }
+
+ Rect localBounds(op.unmappedBounds);
+ op.localMatrix.mapRect(localBounds);
+ output << sOpNameLut[op.opId] << " " << localBounds;
+
+ if (op.localClip && !op.localClip->rect.contains(localBounds)) {
+ output << std::fixed << std::setprecision(0)
+ << " clip=" << op.localClip->rect
+ << " mode=" << (int)op.localClip->mode;
+ }
+}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/OpDumper.h b/libs/hwui/OpDumper.h
new file mode 100644
index 0000000..c99b517
--- /dev/null
+++ b/libs/hwui/OpDumper.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#pragma once
+
+#include <ostream>
+
+namespace android {
+namespace uirenderer {
+
+struct RecordedOp;
+
+class OpDumper {
+public:
+ static void dump(const RecordedOp& op, std::ostream& output, int level = 0);
+};
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index bb26e2e..c37458d 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -119,6 +119,9 @@
#define BUILD_RENDERABLE_OP_LUT(OP_FN) \
{ MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) }
+#define BUILD_FULL_OP_LUT(OP_FN) \
+ { MAP_OPS_BASED_ON_TYPE(OP_FN, OP_FN, OP_FN, OP_FN) }
+
/**
* Op mapping functions, which skip unsupported ops.
*
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 78a0b13..31de305 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -241,10 +241,13 @@
}
void RecordingCanvas::drawPaint(const SkPaint& paint) {
+ const ClipBase* clip = getRecordedClip();
+ // if there's no current clip, draw a big rect and hope we cover the eventual clip bounds
+ Rect bounds = clip ? clip->rect : Rect(-10000, -10000, 10000, 10000);
addOp(alloc().create_trivial<RectOp>(
- mState.getRenderTargetClipBounds(), // OK, since we've not passed transform
+ bounds,
Matrix4::identity(),
- getRecordedClip(),
+ clip,
refPaint(&paint)));
}
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 30c925c..d9fce9b 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -14,16 +14,17 @@
* limitations under the License.
*/
-#ifndef ANDROID_HWUI_RECT_H
-#define ANDROID_HWUI_RECT_H
+#pragma once
-#include <cmath>
-#include <algorithm>
-#include <SkRect.h>
+#include "Vertex.h"
#include <utils/Log.h>
-#include "Vertex.h"
+#include <algorithm>
+#include <cmath>
+#include <iomanip>
+#include <ostream>
+#include <SkRect.h>
namespace android {
namespace uirenderer {
@@ -282,9 +283,23 @@
void dump(const char* label = nullptr) const {
ALOGD("%s[l=%.2f t=%.2f r=%.2f b=%.2f]", label ? label : "Rect", left, top, right, bottom);
}
+
+ friend std::ostream& operator<<(std::ostream& os, const Rect& rect) {
+ if (rect.isEmpty()) {
+ return os << "empty";
+ }
+
+ if (rect.left == 0 && rect.top == 0) {
+ return os << "[" << rect.right << " x " << rect.bottom << "]";
+ }
+
+ return os << "[" << rect.left
+ << " " << rect.top
+ << " " << rect.right
+ << " " << rect.bottom << "]";
+ }
}; // class Rect
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_HWUI_RECT_H
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 9ac76a4..61441ce 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -19,8 +19,9 @@
#include "DamageAccumulator.h"
#include "Debug.h"
#if HWUI_NEW_OPS
-#include "RecordedOp.h"
#include "BakedOpRenderer.h"
+#include "RecordedOp.h"
+#include "OpDumper.h"
#endif
#include "DisplayListOp.h"
#include "LayerRenderer.h"
@@ -95,6 +96,34 @@
* This function is a simplified version of replay(), where we simply retrieve and log the
* display list. This function should remain in sync with the replay() function.
*/
+#if HWUI_NEW_OPS
+void RenderNode::output(uint32_t level, const char* label) {
+ ALOGD("%s (%s %p%s%s%s%s%s)",
+ label,
+ getName(),
+ this,
+ (MathUtils::isZero(properties().getAlpha()) ? ", zero alpha" : ""),
+ (properties().hasShadow() ? ", casting shadow" : ""),
+ (isRenderable() ? "" : ", empty"),
+ (properties().getProjectBackwards() ? ", projected" : ""),
+ (mLayer != nullptr ? ", on HW Layer" : ""));
+ properties().debugOutputProperties(level + 1);
+
+ if (mDisplayList) {
+ for (auto&& op : mDisplayList->getOps()) {
+ std::stringstream strout;
+ OpDumper::dump(*op, strout, level + 1);
+ if (op->opId == RecordedOpId::RenderNodeOp) {
+ auto rnOp = reinterpret_cast<const RenderNodeOp*>(op);
+ rnOp->renderNode->output(level + 1, strout.str().c_str());
+ } else {
+ ALOGD("%s", strout.str().c_str());
+ }
+ }
+ }
+ ALOGD("%*s/RenderNode(%s %p)", level * 2, "", getName(), this);
+}
+#else
void RenderNode::output(uint32_t level) {
ALOGD("%*sStart display list (%p, %s%s%s%s%s%s)", (level - 1) * 2, "", this,
getName(),
@@ -104,22 +133,16 @@
(properties().getProjectBackwards() ? ", projected" : ""),
(mLayer != nullptr ? ", on HW Layer" : ""));
ALOGD("%*s%s %d", level * 2, "", "Save", SaveFlags::MatrixClip);
-
properties().debugOutputProperties(level);
-
if (mDisplayList) {
-#if HWUI_NEW_OPS
- LOG_ALWAYS_FATAL("op dumping unsupported");
-#else
// TODO: consider printing the chunk boundaries here
for (auto&& op : mDisplayList->getOps()) {
op->output(level, DisplayListOp::kOpLogFlag_Recurse);
}
-#endif
}
-
ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName());
-}
+ }
+#endif
void RenderNode::copyTo(proto::RenderNode *pnode) {
pnode->set_id(static_cast<uint64_t>(
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index e037645..8381925 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -123,7 +123,11 @@
void defer(DeferStateStruct& deferStruct, const int level);
void replay(ReplayStateStruct& replayStruct, const int level);
+#if HWUI_NEW_OPS
+ ANDROID_API void output(uint32_t level = 0, const char* label = "Root");
+#else
ANDROID_API void output(uint32_t level = 1);
+#endif
ANDROID_API int getDebugSize();
void copyTo(proto::RenderNode* node);
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index b848af4..0b0f0fa 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -102,22 +102,23 @@
void RenderProperties::debugOutputProperties(const int level) const {
if (mPrimitiveFields.mLeft != 0 || mPrimitiveFields.mTop != 0) {
- ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mPrimitiveFields.mLeft, mPrimitiveFields.mTop);
+ ALOGD("%*s(Translate (left, top) %d, %d)", level * 2, "",
+ mPrimitiveFields.mLeft, mPrimitiveFields.mTop);
}
if (mStaticMatrix) {
- ALOGD("%*sConcatMatrix (static) %p: " SK_MATRIX_STRING,
+ ALOGD("%*s(ConcatMatrix (static) %p: " SK_MATRIX_STRING ")",
level * 2, "", mStaticMatrix, SK_MATRIX_ARGS(mStaticMatrix));
}
if (mAnimationMatrix) {
- ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
+ ALOGD("%*s(ConcatMatrix (animation) %p: " SK_MATRIX_STRING ")",
level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix));
}
if (hasTransformMatrix()) {
if (isTransformTranslateOnly()) {
- ALOGD("%*sTranslate %.2f, %.2f, %.2f",
+ ALOGD("%*s(Translate %.2f, %.2f, %.2f)",
level * 2, "", getTranslationX(), getTranslationY(), getZ());
} else {
- ALOGD("%*sConcatMatrix %p: " SK_MATRIX_STRING,
+ ALOGD("%*s(ConcatMatrix %p: " SK_MATRIX_STRING ")",
level * 2, "", mComputedFields.mTransformMatrix, SK_MATRIX_ARGS(mComputedFields.mTransformMatrix));
}
}
@@ -132,7 +133,7 @@
if (CC_LIKELY(isLayer || !getHasOverlappingRendering())) {
// simply scale rendering content's alpha
- ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
+ ALOGD("%*s(ScaleAlpha %.2f)", level * 2, "", mPrimitiveFields.mAlpha);
} else {
// savelayeralpha to create an offscreen buffer to apply alpha
Rect layerBounds(0, 0, getWidth(), getHeight());
@@ -140,19 +141,18 @@
getClippingRectForFlags(clipFlags, &layerBounds);
clipFlags = 0; // all clipping done by savelayer
}
- ALOGD("%*sSaveLayerAlpha %d, %d, %d, %d, %d, 0x%x", level * 2, "",
+ ALOGD("%*s(SaveLayerAlpha %d, %d, %d, %d, %d, 0x%x)", level * 2, "",
(int)layerBounds.left, (int)layerBounds.top,
(int)layerBounds.right, (int)layerBounds.bottom,
(int)(mPrimitiveFields.mAlpha * 255),
SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer);
}
-
-
}
+
if (clipFlags) {
Rect clipRect;
getClippingRectForFlags(clipFlags, &clipRect);
- ALOGD("%*sClipRect %d, %d, %d, %d", level * 2, "",
+ ALOGD("%*s(ClipRect %d, %d, %d, %d)", level * 2, "",
(int)clipRect.left, (int)clipRect.top, (int)clipRect.right, (int)clipRect.bottom);
}
}
diff --git a/libs/hwui/tests/unit/OpDumperTests.cpp b/libs/hwui/tests/unit/OpDumperTests.cpp
new file mode 100644
index 0000000..01840d7
--- /dev/null
+++ b/libs/hwui/tests/unit/OpDumperTests.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "tests/common/TestUtils.h"
+#include "OpDumper.h"
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(OpDumper, dump) {
+ SkPaint paint;
+ RectOp op(uirenderer::Rect(100, 100), Matrix4::identity(), nullptr, &paint);
+
+ std::stringstream stream;
+ OpDumper::dump(op, stream);
+ EXPECT_STREQ("RectOp [100 x 100]", stream.str().c_str());
+
+ stream.str("");
+ OpDumper::dump(op, stream, 2);
+ EXPECT_STREQ(" RectOp [100 x 100]", stream.str().c_str());
+
+ ClipRect clipRect(uirenderer::Rect(50, 50));
+ op.localClip = &clipRect;
+
+ stream.str("");
+ OpDumper::dump(op, stream, 2);
+ EXPECT_STREQ(" RectOp [100 x 100] clip=[50 x 50] mode=0", stream.str().c_str());
+}
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index cd9ffc5..f988da3 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -19,6 +19,7 @@
#include <RecordedOp.h>
#include <RecordingCanvas.h>
#include <tests/common/TestUtils.h>
+#include <utils/Color.h>
namespace android {
namespace uirenderer {
@@ -185,6 +186,19 @@
ASSERT_EQ(3, count);
}
+TEST(RecordingCanvas, drawColor) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ canvas.drawColor(Color::Black, SkXfermode::kSrcOver_Mode);
+ });
+
+ ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
+ auto op = *(dl->getOps()[0]);
+ EXPECT_EQ(RecordedOpId::RectOp, op.opId);
+ EXPECT_EQ(nullptr, op.localClip);
+ EXPECT_TRUE(op.unmappedBounds.contains(Rect(-1000, -1000, 1000, 1000)))
+ << "no clip, unmappedBounds should resolve to be much larger than DL bounds";
+}
+
TEST(RecordingCanvas, backgroundAndImage) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
SkBitmap bitmap;
diff --git a/libs/hwui/utils/StringUtils.h b/libs/hwui/utils/StringUtils.h
index 05a3d59..5add957 100644
--- a/libs/hwui/utils/StringUtils.h
+++ b/libs/hwui/utils/StringUtils.h
@@ -42,7 +42,7 @@
static const char* SUFFIXES[] = {"B", "KiB", "MiB"};
size_t suffix = 0;
double temp = d.bytes;
- while (temp > 1000 && suffix < 2) {
+ while (temp > 1024 && suffix < 2) {
temp /= 1024.0;
suffix++;
}
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 45529ef..9922b72 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -111,6 +111,10 @@
* A device type connected over IP.
*/
public static final int TYPE_IP = 20;
+ /**
+ * A type-agnostic device used for communication with external audio systems
+ */
+ public static final int TYPE_BUS = 21;
private final AudioDevicePort mPort;
@@ -279,6 +283,7 @@
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_FM, TYPE_FM);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_AUX_LINE, TYPE_AUX_LINE);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_IP, TYPE_IP);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BUS, TYPE_BUS);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO);
@@ -296,6 +301,7 @@
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_SPDIF, TYPE_LINE_DIGITAL);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, TYPE_BLUETOOTH_A2DP);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_IP, TYPE_IP);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUS, TYPE_BUS);
// not covered here, legacy
//AudioSystem.DEVICE_OUT_REMOTE_SUBMIX
@@ -323,6 +329,7 @@
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_TELEPHONY, AudioSystem.DEVICE_OUT_TELEPHONY_TX);
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_AUX_LINE, AudioSystem.DEVICE_OUT_AUX_LINE);
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_IP, AudioSystem.DEVICE_OUT_IP);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUS, AudioSystem.DEVICE_OUT_BUS);
}
}
diff --git a/media/java/android/media/AudioFormat.aidl b/media/java/android/media/AudioFormat.aidl
new file mode 100644
index 0000000..8613f55
--- /dev/null
+++ b/media/java/android/media/AudioFormat.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 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.media;
+
+parcelable AudioFormat;
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 000a56d..22f4f04 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -18,10 +18,13 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
+import java.util.Objects;
/**
* The {@link AudioFormat} class is used to access a number of audio format and
@@ -209,7 +212,7 @@
* AudioTrack.getPlaybackHeadPosition()}),
* depending on the context where audio frame is used.
*/
-public class AudioFormat {
+public class AudioFormat implements Parcelable {
//---------------------------------------------------------
// Constants
@@ -874,6 +877,44 @@
}
@Override
+ public int hashCode() {
+ return Objects.hash(mPropertySetMask, mSampleRate, mEncoding, mChannelMask,
+ mChannelIndexMask);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mPropertySetMask);
+ dest.writeInt(mEncoding);
+ dest.writeInt(mSampleRate);
+ dest.writeInt(mChannelMask);
+ dest.writeInt(mChannelIndexMask);
+ }
+
+ private AudioFormat(Parcel in) {
+ mPropertySetMask = in.readInt();
+ mEncoding = in.readInt();
+ mSampleRate = in.readInt();
+ mChannelMask = in.readInt();
+ mChannelIndexMask = in.readInt();
+ }
+
+ public static final Parcelable.Creator<AudioFormat> CREATOR =
+ new Parcelable.Creator<AudioFormat>() {
+ public AudioFormat createFromParcel(Parcel p) {
+ return new AudioFormat(p);
+ }
+ public AudioFormat[] newArray(int size) {
+ return new AudioFormat[size];
+ }
+ };
+
+ @Override
public String toString () {
return new String("AudioFormat:"
+ " props=" + mPropertySetMask
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index aa0d78d..b3f73be 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -346,6 +346,7 @@
public static final int DEVICE_OUT_AUX_LINE = 0x200000;
public static final int DEVICE_OUT_SPEAKER_SAFE = 0x400000;
public static final int DEVICE_OUT_IP = 0x800000;
+ public static final int DEVICE_OUT_BUS = 0x1000000;
public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT;
@@ -373,6 +374,7 @@
DEVICE_OUT_AUX_LINE |
DEVICE_OUT_SPEAKER_SAFE |
DEVICE_OUT_IP |
+ DEVICE_OUT_BUS |
DEVICE_OUT_DEFAULT);
public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
@@ -412,6 +414,7 @@
public static final int DEVICE_IN_BLUETOOTH_A2DP = DEVICE_BIT_IN | 0x20000;
public static final int DEVICE_IN_LOOPBACK = DEVICE_BIT_IN | 0x40000;
public static final int DEVICE_IN_IP = DEVICE_BIT_IN | 0x80000;
+ public static final int DEVICE_IN_BUS = DEVICE_BIT_IN | 0x100000;
public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;
public static final int DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION |
@@ -434,6 +437,7 @@
DEVICE_IN_BLUETOOTH_A2DP |
DEVICE_IN_LOOPBACK |
DEVICE_IN_IP |
+ DEVICE_IN_BUS |
DEVICE_IN_DEFAULT);
public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
@@ -469,6 +473,7 @@
public static final String DEVICE_OUT_AUX_LINE_NAME = "aux_line";
public static final String DEVICE_OUT_SPEAKER_SAFE_NAME = "speaker_safe";
public static final String DEVICE_OUT_IP_NAME = "ip";
+ public static final String DEVICE_OUT_BUS_NAME = "bus";
public static final String DEVICE_IN_COMMUNICATION_NAME = "communication";
public static final String DEVICE_IN_AMBIENT_NAME = "ambient";
@@ -490,6 +495,7 @@
public static final String DEVICE_IN_BLUETOOTH_A2DP_NAME = "bt_a2dp";
public static final String DEVICE_IN_LOOPBACK_NAME = "loopback";
public static final String DEVICE_IN_IP_NAME = "ip";
+ public static final String DEVICE_IN_BUS_NAME = "bus";
public static String getOutputDeviceName(int device)
{
@@ -542,6 +548,8 @@
return DEVICE_OUT_SPEAKER_SAFE_NAME;
case DEVICE_OUT_IP:
return DEVICE_OUT_IP_NAME;
+ case DEVICE_OUT_BUS:
+ return DEVICE_OUT_BUS_NAME;
case DEVICE_OUT_DEFAULT:
default:
return Integer.toString(device);
@@ -591,6 +599,8 @@
return DEVICE_IN_LOOPBACK_NAME;
case DEVICE_IN_IP:
return DEVICE_IN_IP_NAME;
+ case DEVICE_IN_BUS:
+ return DEVICE_IN_BUS_NAME;
case DEVICE_IN_DEFAULT:
default:
return Integer.toString(device);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 26e466e..adf8551 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -57,6 +57,7 @@
import android.media.SyncParams;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.Preconditions;
import libcore.io.IoBridge;
import libcore.io.Libcore;
@@ -964,8 +965,8 @@
* @param uri the Content URI of the data you want to play
* @throws IllegalStateException if it is called in an invalid state
*/
- public void setDataSource(Context context, Uri uri)
- throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
+ public void setDataSource(@NonNull Context context, @NonNull Uri uri)
+ throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
setDataSource(context, uri, null);
}
@@ -981,47 +982,46 @@
* to disallow or allow cross domain redirection.
* @throws IllegalStateException if it is called in an invalid state
*/
- public void setDataSource(Context context, Uri uri, Map<String, String> headers)
- throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
+ public void setDataSource(@NonNull Context context, @NonNull Uri uri,
+ @Nullable Map<String, String> headers) throws IOException, IllegalArgumentException,
+ SecurityException, IllegalStateException {
+ final ContentResolver resolver = context.getContentResolver();
final String scheme = uri.getScheme();
if (ContentResolver.SCHEME_FILE.equals(scheme)) {
setDataSource(uri.getPath());
return;
} else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
&& Settings.AUTHORITY.equals(uri.getAuthority())) {
- // Redirect ringtones to go directly to underlying provider
- uri = RingtoneManager.getActualDefaultRingtoneUri(context,
- RingtoneManager.getDefaultType(uri));
- if (uri == null) {
- throw new FileNotFoundException("Failed to resolve default ringtone");
- }
- }
-
- AssetFileDescriptor fd = null;
- try {
- ContentResolver resolver = context.getContentResolver();
- fd = resolver.openAssetFileDescriptor(uri, "r");
- if (fd == null) {
+ // Try cached ringtone first since the actual provider may not be
+ // encryption aware, or it may be stored on CE media storage
+ final int type = RingtoneManager.getDefaultType(uri);
+ final Uri cacheUri = RingtoneManager.getCacheForType(type);
+ final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, type);
+ if (attemptDataSource(resolver, cacheUri)) {
return;
- }
- // Note: using getDeclaredLength so that our behavior is the same
- // as previous versions when the content provider is returning
- // a full file.
- if (fd.getDeclaredLength() < 0) {
- setDataSource(fd.getFileDescriptor());
+ } else if (attemptDataSource(resolver, actualUri)) {
+ return;
} else {
- setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength());
+ setDataSource(uri.toString(), headers);
}
- return;
- } catch (SecurityException | IOException ex) {
- Log.w(TAG, "Couldn't open file on client side; trying server side: " + ex);
- } finally {
- if (fd != null) {
- fd.close();
+ } else {
+ // Try requested Uri locally first, or fallback to media server
+ if (attemptDataSource(resolver, uri)) {
+ return;
+ } else {
+ setDataSource(uri.toString(), headers);
}
}
+ }
- setDataSource(uri.toString(), headers);
+ private boolean attemptDataSource(ContentResolver resolver, Uri uri) {
+ try (AssetFileDescriptor afd = resolver.openAssetFileDescriptor(uri, "r")) {
+ setDataSource(afd);
+ return true;
+ } catch (NullPointerException | SecurityException | IOException ex) {
+ Log.w(TAG, "Couldn't open " + uri + ": " + ex);
+ return false;
+ }
}
/**
@@ -1102,6 +1102,26 @@
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
/**
+ * Sets the data source (AssetFileDescriptor) to use. It is the caller's
+ * responsibility to close the file descriptor. It is safe to do so as soon
+ * as this call returns.
+ *
+ * @param afd the AssetFileDescriptor for the file you want to play
+ */
+ public void setDataSource(@NonNull AssetFileDescriptor afd)
+ throws IOException, IllegalArgumentException, IllegalStateException {
+ Preconditions.checkNotNull(afd);
+ // Note: using getDeclaredLength so that our behavior is the same
+ // as previous versions when the content provider is returning
+ // a full file.
+ if (afd.getDeclaredLength() < 0) {
+ setDataSource(afd.getFileDescriptor());
+ } else {
+ setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
+ }
+ }
+
+ /**
* Sets the data source (FileDescriptor) to use. It is the caller's responsibility
* to close the file descriptor. It is safe to do so as soon as this call returns.
*
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 025029e..06ac11b 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -18,9 +18,12 @@
import com.android.internal.database.SortCursor;
+import libcore.io.Streams;
+
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Activity;
+import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -33,6 +36,9 @@
import android.provider.Settings.System;
import android.util.Log;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
@@ -654,8 +660,19 @@
if (setting == null) return;
Settings.System.putString(context.getContentResolver(), setting,
ringtoneUri != null ? ringtoneUri.toString() : null);
+
+ // Stream selected ringtone into cache so it's available for playback
+ // when CE storage is still locked
+ final ContentResolver cr = context.getContentResolver();
+ final Uri cacheUri = getCacheForType(type);
+ try (InputStream in = cr.openInputStream(ringtoneUri);
+ OutputStream out = cr.openOutputStream(cacheUri)) {
+ Streams.copy(in, out);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to cache ringtone: " + e);
+ }
}
-
+
private static String getSettingForType(int type) {
if ((type & TYPE_RINGTONE) != 0) {
return Settings.System.RINGTONE;
@@ -667,7 +684,20 @@
return null;
}
}
-
+
+ /** {@hide} */
+ public static Uri getCacheForType(int type) {
+ if ((type & TYPE_RINGTONE) != 0) {
+ return Settings.System.RINGTONE_CACHE_URI;
+ } else if ((type & TYPE_NOTIFICATION) != 0) {
+ return Settings.System.NOTIFICATION_SOUND_CACHE_URI;
+ } else if ((type & TYPE_ALARM) != 0) {
+ return Settings.System.ALARM_ALERT_CACHE_URI;
+ } else {
+ return null;
+ }
+ }
+
/**
* Returns whether the given {@link Uri} is one of the default ringtones.
*
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 3e6aa9f..bc7913b 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -16,6 +16,7 @@
package android.media.tv;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.ComponentName;
@@ -56,6 +57,7 @@
/**
* Permission to read TV listings. This is required to read all the TV channel and program
* information available on the system.
+ * @hide
*/
public static final String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS";
@@ -310,33 +312,28 @@
}
/**
- * Returns true, if {@code uri} is a channel URI.
- * @hide
+ * Returns {@code true}, if {@code uri} is a channel URI.
*/
public static final boolean isChannelUri(Uri uri) {
return isChannelUriForTunerInput(uri) || isChannelUriForPassthroughInput(uri);
}
/**
- * Returns true, if {@code uri} is a channel URI for a tuner input.
- * @hide
+ * Returns {@code true}, if {@code uri} is a channel URI for a tuner input.
*/
public static final boolean isChannelUriForTunerInput(Uri uri) {
return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_CHANNEL);
}
/**
- * Returns true, if {@code uri} is a channel URI for a passthrough input.
- * @hide
+ * Returns {@code true}, if {@code uri} is a channel URI for a pass-through input.
*/
- @SystemApi
public static final boolean isChannelUriForPassthroughInput(Uri uri) {
return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_PASSTHROUGH);
}
/**
- * Returns true, if {@code uri} is a program URI.
- * @hide
+ * Returns {@code true}, if {@code uri} is a program URI.
*/
public static final boolean isProgramUri(Uri uri) {
return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_PROGRAM);
@@ -968,8 +965,9 @@
* The title of this TV program.
*
* <p>If this program is an episodic TV show, it is recommended that the title is the series
- * title and its related fields ({@link #COLUMN_SEASON_NUMBER},
- * {@link #COLUMN_EPISODE_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
+ * title and its related fields ({@link #COLUMN_SEASON_TITLE} and/or
+ * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, {@link #COLUMN_SEASON_DISPLAY_NUMBER},
+ * {@link #COLUMN_EPISODE_DISPLAY_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
*
* <p>Type: TEXT
*/
@@ -981,19 +979,65 @@
* <p>Can be empty.
*
* <p>Type: INTEGER
+ *
+ * @deprecated Use {@link #COLUMN_SEASON_DISPLAY_NUMBER} instead.
*/
+ @Deprecated
public static final String COLUMN_SEASON_NUMBER = "season_number";
/**
+ * The season display number of this TV program for episodic TV shows.
+ *
+ * <p>This is used to indicate the season number. (e.g. 1, 2 or 3) Note that the value
+ * does not necessarily be numeric. (e.g. 12B)
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+
+ /**
+ * The title of the season for this TV program for episodic TV shows.
+ *
+ * <p>This is an optional field supplied only when the season has a special title
+ * (e.g. The Final Season). If provided, the applications should display it instead of
+ * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, and should display it without alterations.
+ * (e.g. for "The Final Season", displayed string should be "The Final Season", not
+ * "Season The Final Season"). When displaying multiple programs, the order should be based
+ * on {@link #COLUMN_SEASON_DISPLAY_NUMBER}, even when {@link #COLUMN_SEASON_TITLE} exists.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_SEASON_TITLE = "season_title";
+
+ /**
* The episode number of this TV program for episodic TV shows.
*
* <p>Can be empty.
*
* <p>Type: INTEGER
+ *
+ * @deprecated Use {@link #COLUMN_EPISODE_DISPLAY_NUMBER} instead.
*/
+ @Deprecated
public static final String COLUMN_EPISODE_NUMBER = "episode_number";
/**
+ * The episode display number of this TV program for episodic TV shows.
+ *
+ * <p>This is used to indicate the episode number. (e.g. 1, 2 or 3) Note that the value
+ * does not necessarily be numeric. (e.g. 12B)
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+
+ /**
* The episode title of this TV program for episodic TV shows.
*
* <p>Can be empty.
@@ -1331,7 +1375,7 @@
* @return an encoded genre string that can be inserted into the
* {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
*/
- public static String encode(String... genres) {
+ public static String encode(@NonNull String... genres) {
StringBuilder sb = new StringBuilder();
String separator = "";
for (String genre : genres) {
@@ -1366,7 +1410,7 @@
* {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
* @return genre strings.
*/
- public static String[] decode(String genres) {
+ public static String[] decode(@NonNull String genres) {
if (genres.isEmpty()) {
return EMPTY_STRING_ARRAY;
}
@@ -1464,8 +1508,9 @@
* The title of this recorded TV program.
*
* <p>If this recorded program is an episodic TV show, it is recommended that the title is
- * the series title and its related fields ({@link #COLUMN_SEASON_NUMBER},
- * {@link #COLUMN_EPISODE_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
+ * the series title and its related fields ({@link #COLUMN_SEASON_TITLE} and/or
+ * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, {@link #COLUMN_EPISODE_DISPLAY_NUMBER},
+ * and {@link #COLUMN_EPISODE_TITLE}) are filled in.
*
* <p>Type: TEXT
* @see Programs#COLUMN_TITLE
@@ -1473,24 +1518,46 @@
public static final String COLUMN_TITLE = Programs.COLUMN_TITLE;
/**
- * The season number of this recorded TV program for episodic TV shows.
+ * The season display number of this recorded TV program for episodic TV shows.
+ *
+ * <p>This is used to indicate the season number. (e.g. 1, 2 or 3) Note that the value
+ * does not necessarily be numeric. (e.g. 12B)
*
* <p>Can be empty.
*
- * <p>Type: INTEGER
- * @see Programs#COLUMN_SEASON_NUMBER
+ * <p>Type: TEXT
*/
- public static final String COLUMN_SEASON_NUMBER = Programs.COLUMN_SEASON_NUMBER;
+ public static final String COLUMN_SEASON_DISPLAY_NUMBER =
+ Programs.COLUMN_SEASON_DISPLAY_NUMBER;
/**
- * The episode number of this recorded TV program for episodic TV shows.
+ * The title of the season for this recorded TV program for episodic TV shows.
+ *
+ * <p>This is an optional field supplied only when the season has a special title
+ * (e.g. The Final Season). If provided, the applications should display it instead of
+ * {@link #COLUMN_SEASON_DISPLAY_NUMBER} without alterations.
+ * (e.g. for "The Final Season", displayed string should be "The Final Season", not
+ * "Season The Final Season"). When displaying multiple programs, the order should be based
+ * on {@link #COLUMN_SEASON_DISPLAY_NUMBER}, even when {@link #COLUMN_SEASON_TITLE} exists.
*
* <p>Can be empty.
*
- * <p>Type: INTEGER
- * @see Programs#COLUMN_EPISODE_NUMBER
+ * <p>Type: TEXT
*/
- public static final String COLUMN_EPISODE_NUMBER = Programs.COLUMN_EPISODE_NUMBER;
+ public static final String COLUMN_SEASON_TITLE = Programs.COLUMN_SEASON_TITLE;
+
+ /**
+ * The episode display number of this recorded TV program for episodic TV shows.
+ *
+ * <p>This is used to indicate the episode number. (e.g. 1, 2 or 3) Note that the value
+ * does not necessarily be numeric. (e.g. 12B)
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_EPISODE_DISPLAY_NUMBER =
+ Programs.COLUMN_EPISODE_DISPLAY_NUMBER;
/**
* The episode title of this recorded TV program for episodic TV shows.
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 4ac62f5..9e90a19 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -1264,6 +1264,14 @@
int readerHalFormat = android_view_Surface_mapPublicFormatToHalFormat(
static_cast<PublicFormat>(readerFormat));
int32_t fmt = applyFormatOverrides(buffer->flexFormat, readerHalFormat);
+ // Override the image format to HAL_PIXEL_FORMAT_YCbCr_420_888 if the actual format is
+ // NV21 or YV12. This could only happen when the Gralloc HAL version is v0.1 thus doesn't
+ // support lockycbcr(), the CpuConsumer need to use the lock() method in the
+ // lockNextBuffer() call. For Gralloc HAL v0.2 or newer, this format should already be
+ // overridden to HAL_PIXEL_FORMAT_YCbCr_420_888 for the flexible YUV compatible formats.
+ if (fmt == HAL_PIXEL_FORMAT_YCrCb_420_SP || fmt == HAL_PIXEL_FORMAT_YV12) {
+ fmt = HAL_PIXEL_FORMAT_YCbCr_420_888;
+ }
PublicFormat publicFmt = android_view_Surface_mapHalFormatDataspaceToPublicFormat(
fmt, buffer->dataSpace);
return static_cast<jint>(publicFmt);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
index 7394c12..38a71ec 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
@@ -46,6 +46,7 @@
import com.android.documentsui.BaseActivity;
import com.android.documentsui.DocumentsApplication;
import com.android.documentsui.R;
+import com.android.documentsui.Shared;
import com.android.documentsui.Snackbars;
import com.android.documentsui.model.DocumentInfo;
@@ -55,6 +56,7 @@
public class RenameDocumentFragment extends DialogFragment {
private static final String TAG_RENAME_DOCUMENT = "rename_document";
private DocumentInfo mDocument;
+ private EditText mEditText;
public static void show(FragmentManager fm, DocumentInfo document) {
final RenameDocumentFragment dialog = new RenameDocumentFragment();
@@ -62,6 +64,11 @@
dialog.show(fm, TAG_RENAME_DOCUMENT);
}
+ /**
+ * Creates the dialog UI.
+ * @param savedInstanceState
+ * @return
+ */
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Context context = getActivity();
@@ -69,8 +76,7 @@
LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
View view = dialogInflater.inflate(R.layout.dialog_file_name, null, false);
- final EditText editText = (EditText) view.findViewById(android.R.id.text1);
- fillWithFileName(editText, mDocument.displayName);
+ mEditText = (EditText) view.findViewById(android.R.id.text1);
builder.setTitle(R.string.menu_rename);
builder.setView(view);
@@ -79,7 +85,7 @@
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- renameDocuments(editText.getText().toString());
+ renameDocuments(mEditText.getText().toString());
}
});
@@ -87,7 +93,7 @@
final AlertDialog dialog = builder.create();
- editText.setOnEditorActionListener(
+ mEditText.setOnEditorActionListener(
new OnEditorActionListener() {
@Override
public boolean onEditorAction(
@@ -95,18 +101,51 @@
if ((actionId == EditorInfo.IME_ACTION_DONE) || (event != null
&& event.getKeyCode() == KeyEvent.KEYCODE_ENTER
&& event.hasNoModifiers())) {
- renameDocuments(editText.getText().toString());
+ renameDocuments(mEditText.getText().toString());
dialog.dismiss();
return true;
}
return false;
}
});
-
return dialog;
}
/**
+ * Sets/Restores the data.
+ * @param savedInstanceState
+ * @return
+ */
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ if(savedInstanceState == null) {
+ // Fragment created for the first time, we set the text.
+ // mDocument value was set in show
+ mEditText.setText(mDocument.displayName);
+ }
+ else {
+ // Fragment restored, text was restored automatically.
+ // mDocument value needs to be restored.
+ mDocument = savedInstanceState.getParcelable(Shared.EXTRA_DOC);
+ }
+ // Do selection in both cases, because we cleared it.
+ selectFileName(mEditText);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ // Clear selection before storing state and restore it manually,
+ // because otherwise after rotation selection is displayed with cut/copy menu visible :/
+ clearFileNameSelection(mEditText);
+
+ super.onSaveInstanceState(outState);
+
+ outState.putParcelable(Shared.EXTRA_DOC, mDocument);
+ }
+
+ /**
* Validates if string is a proper document name.
* Checks if string is not empty. More rules might be added later.
* @param docName string representing document name
@@ -120,12 +159,21 @@
* Fills text field with the file name and selects the name without extension.
*
* @param editText text field to be filled
- * @param name full name of the file
*/
- private void fillWithFileName(EditText editText, String name) {
- editText.setText(name);
- int separatorIndex = name.indexOf(".");
- editText.setSelection(0, separatorIndex == -1 ? name.length() : separatorIndex);
+ private void selectFileName(EditText editText) {
+ String text = editText.getText().toString();
+ int separatorIndex = text.indexOf(".");
+ editText.setSelection(0,
+ (separatorIndex == -1 || mDocument.isDirectory()) ? text.length() : separatorIndex);
+ }
+
+ /**
+ * Clears selection in text field.
+ *
+ * @param editText text field to be cleared.
+ */
+ private void clearFileNameSelection(EditText editText) {
+ editText.setSelection(0, 0);
}
private void renameDocuments(String newDisplayName) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
index 34a35ee..844d07a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
@@ -376,7 +376,7 @@
if (Document.MIME_TYPE_DIR.equals(src.mimeType)) {
copyDirectoryHelper(src, dstInfo);
} else {
- copyFileHelper(src, dstInfo, dstMimeType);
+ copyFileHelper(src, dstInfo, dest, dstMimeType);
}
}
@@ -439,13 +439,14 @@
/**
* Handles copying a single file.
*
- * @param srcUriInfo Info of the file to copy from.
- * @param dstUriInfo Info of the *file* to copy to. Must be created beforehand.
+ * @param src Info of the file to copy from.
+ * @param dest Info of the *file* to copy to. Must be created beforehand.
+ * @param destParent Info of the parent of the destination.
* @param mimeType Mime type for the target. Can be different than source for virtual files.
* @throws ResourceException
*/
- private void copyFileHelper(DocumentInfo src, DocumentInfo dest, String mimeType)
- throws ResourceException {
+ private void copyFileHelper(DocumentInfo src, DocumentInfo dest, DocumentInfo destParent,
+ String mimeType) throws ResourceException {
CancellationSignal canceller = new CancellationSignal();
AssetFileDescriptor srcFileAsAsset = null;
ParcelFileDescriptor srcFile = null;
@@ -527,8 +528,8 @@
if (DEBUG) Log.d(TAG, "Cleaning up failed operation leftovers.");
canceller.cancel();
try {
- DocumentsContract.deleteDocument(getClient(dest), dest.derivedUri);
- } catch (RemoteException | RuntimeException e) {
+ deleteDocument(dest, destParent);
+ } catch (ResourceException e) {
Log.w(TAG, "Failed to cleanup after copy error: " + src.derivedUri, e);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
index 374d27b..25bca4f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
@@ -84,7 +84,7 @@
for (DocumentInfo doc : mSrcs) {
if (DEBUG) Log.d(TAG, "Deleting document @ " + doc.derivedUri);
try {
- deleteDocument(doc);
+ deleteDocument(doc, mSrcParent);
} catch (ResourceException e) {
Log.e(TAG, "Failed to delete document @ " + doc.derivedUri);
onFileFailed(doc);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
index 572c0d7..afb3374 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
@@ -184,10 +184,17 @@
return false;
}
- final void deleteDocument(DocumentInfo doc) throws ResourceException {
+ final void deleteDocument(DocumentInfo doc, DocumentInfo parent) throws ResourceException {
try {
- DocumentsContract.deleteDocument(getClient(doc), doc.derivedUri);
- } catch (Exception e) {
+ if (doc.isRemoveSupported()) {
+ DocumentsContract.removeDocument(getClient(doc), doc.derivedUri, parent.derivedUri);
+ } else if (doc.isDeleteSupported()) {
+ DocumentsContract.deleteDocument(getClient(doc), doc.derivedUri);
+ } else {
+ throw new ResourceException("Unable to delete source document as the file is " +
+ "not deletable nor removable: %s.", doc.derivedUri);
+ }
+ } catch (RemoteException | RuntimeException e) {
throw new ResourceException("Failed to delete file %s due to an exception.",
doc.derivedUri, e);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
index 8835a9f..b5826a4 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
@@ -115,6 +115,9 @@
// If we couldn't do an optimized copy...we fall back to vanilla byte copy.
byteCopyDocument(src, dest);
+
+ // Remove the source document.
+ deleteDocument(src, srcParent);
}
@Override
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
index 34ea96e..1ffef05 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
@@ -92,6 +92,8 @@
public void testCreateDirectory() throws Exception {
initTestFiles();
+ bots.roots.openRoot(ROOT_0_ID);
+
bots.main.openOverflowMenu();
bots.main.menuNewFolder().click();
bots.main.setDialogText("Kung Fu Panda");
diff --git a/packages/Keyguard/res/values-h560dp/dimens.xml b/packages/Keyguard/res/values-h560dp/dimens.xml
index 1683113..469ce52 100644
--- a/packages/Keyguard/res/values-h560dp/dimens.xml
+++ b/packages/Keyguard/res/values-h560dp/dimens.xml
@@ -16,5 +16,5 @@
-->
<resources>
- <dimen name="widget_big_font_size">96dp</dimen>
+ <dimen name="widget_big_font_size">84dp</dimen>
</resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-h650dp/dimens.xml b/packages/Keyguard/res/values-h650dp/dimens.xml
index 1cd2162..cb89cb4 100644
--- a/packages/Keyguard/res/values-h650dp/dimens.xml
+++ b/packages/Keyguard/res/values-h650dp/dimens.xml
@@ -16,5 +16,5 @@
-->
<resources>
- <dimen name="widget_big_font_size">100dp</dimen>
+ <dimen name="widget_big_font_size">88dp</dimen>
</resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw600dp-land/dimens.xml b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
index a487644..c34012d 100644
--- a/packages/Keyguard/res/values-sw600dp-land/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
@@ -20,5 +20,5 @@
<resources>
<!-- Overload default clock widget parameters -->
- <dimen name="widget_big_font_size">100dp</dimen>
+ <dimen name="widget_big_font_size">88dp</dimen>
</resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml
index b181682..a3b01b6 100644
--- a/packages/Keyguard/res/values-sw600dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp/dimens.xml
@@ -26,9 +26,9 @@
<dimen name="keyguard_security_view_margin">12dp</dimen>
<!-- Overload default clock widget parameters -->
- <dimen name="widget_big_font_size">125dp</dimen>
+ <dimen name="widget_big_font_size">110dp</dimen>
<dimen name="widget_label_font_size">16sp</dimen>
- <dimen name="bottom_text_spacing_digital">-16dp</dimen>
+ <dimen name="bottom_text_spacing_digital">-1dp</dimen>
<!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
Should be 0 on devices with plenty of room (e.g. tablets) -->
diff --git a/packages/Keyguard/res/values-sw720dp/dimens.xml b/packages/Keyguard/res/values-sw720dp/dimens.xml
index 08ab791..210c7eb 100644
--- a/packages/Keyguard/res/values-sw720dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw720dp/dimens.xml
@@ -24,5 +24,5 @@
<!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
<dimen name="keyguard_security_height">420dp</dimen>
- <dimen name="widget_big_font_size">138dp</dimen>
+ <dimen name="widget_big_font_size">122dp</dimen>
</resources>
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index 18d893a..7b952be2 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -39,9 +39,9 @@
<dimen name="eca_overlap">-10dip</dimen>
<!-- Default clock parameters -->
- <dimen name="bottom_text_spacing_digital">-10dp</dimen>
+ <dimen name="bottom_text_spacing_digital">-1dp</dimen>
<dimen name="widget_label_font_size">14sp</dimen>
- <dimen name="widget_big_font_size">88dp</dimen>
+ <dimen name="widget_big_font_size">78dp</dimen>
<!-- The y translation to apply at the start in appear animations. -->
<dimen name="appear_y_translation_start">32dp</dimen>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 1bce7f9..525d6f4 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -344,28 +344,6 @@
<item>midi</item>
</string-array>
- <!-- Possible values for user theme in Display Settings.
- Do not translate. -->
- <string-array name="night_mode_entries" translatable="false">
- <!-- Do not translate. -->
- <item>@string/night_mode_no</item>
- <!-- Do not translate. -->
- <item>@string/night_mode_yes</item>
- <!-- Do not translate. -->
- <item>@string/night_mode_auto</item>
- </string-array>
-
- <!-- These values should match up with the MODE_NIGHT constants in UiModeManager.
- Do not translate. -->
- <string-array name="night_mode_values" translatable="false">
- <!-- Do not translate. -->
- <item>1</item>
- <!-- Do not translate. -->
- <item>2</item>
- <!-- Do not translate. -->
- <item>0</item>
- </string-array>
-
<!-- Display color space adjustment modes for developers -->
<string-array name="simulate_color_space_entries" translatable="false">
<item>@string/daltonizer_mode_disabled</item>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 3c03a4ad..676bf5f 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -236,10 +236,14 @@
<string name="tts_settings">Text-to-speech settings</string>
<!-- TTS option item name in the main settings screen -->
<string name="tts_settings_title">Text-to-speech output</string>
- <!-- On main TTS Settings screen, in default settings section, setting default speech rate for synthesized voice -->
+ <!-- On main TTS Settings screen, in default settings section, setting default speech rate for synthesized voice -->
<string name="tts_default_rate_title">Speech rate</string>
<!-- On main TTS Settings screen, summary for default speech rate for synthesized voice -->
<string name="tts_default_rate_summary">Speed at which the text is spoken</string>
+ <!-- On main TTS Settings screen, in default settings section, setting default pitch for synthesized voice -->
+ <string name="tts_default_pitch_title">Pitch</string>
+ <!-- On main TTS Settings screen, summary for default pitch for synthesized voice -->
+ <string name="tts_default_pitch_summary">Affects the tone of the synthesized speech</string>
<!-- On main TTS Settings screen, in default settings section, setting default language for synthesized voice -->
<string name="tts_default_lang_title">Language</string>
<!-- Entry in the TTS engine language/locale picker, when selected will try to default to the system language [CHAR LIMIT=50] -->
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 57d495f..9842e28 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -49,6 +49,7 @@
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SELinux;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -457,8 +458,28 @@
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
- throw new FileNotFoundException("Direct file access no longer supported; "
- + "ringtone playback is available through android.media.Ringtone");
+ final String cacheName;
+ if (Settings.System.RINGTONE_CACHE_URI.equals(uri)) {
+ cacheName = Settings.System.RINGTONE_CACHE;
+ } else if (Settings.System.NOTIFICATION_SOUND_CACHE_URI.equals(uri)) {
+ cacheName = Settings.System.NOTIFICATION_SOUND_CACHE;
+ } else if (Settings.System.ALARM_ALERT_CACHE_URI.equals(uri)) {
+ cacheName = Settings.System.ALARM_ALERT_CACHE;
+ } else {
+ throw new FileNotFoundException("Direct file access no longer supported; "
+ + "ringtone playback is available through android.media.Ringtone");
+ }
+
+ final File cacheFile = new File(
+ getRingtoneCacheDir(UserHandle.getCallingUserId()), cacheName);
+ return ParcelFileDescriptor.open(cacheFile, ParcelFileDescriptor.parseMode(mode));
+ }
+
+ private File getRingtoneCacheDir(int userId) {
+ final File cacheDir = new File(Environment.getDataSystemDeDirectory(userId), "ringtones");
+ cacheDir.mkdir();
+ SELinux.restorecon(cacheDir);
+ return cacheDir;
}
@Override
@@ -901,6 +922,21 @@
return false;
}
+ // Invalidate any relevant cache files
+ String cacheName = null;
+ if (Settings.System.RINGTONE.equals(name)) {
+ cacheName = Settings.System.RINGTONE_CACHE;
+ } else if (Settings.System.NOTIFICATION_SOUND.equals(name)) {
+ cacheName = Settings.System.NOTIFICATION_SOUND_CACHE;
+ } else if (Settings.System.ALARM_ALERT.equals(name)) {
+ cacheName = Settings.System.ALARM_ALERT_CACHE;
+ }
+ if (cacheName != null) {
+ final File cacheFile = new File(
+ getRingtoneCacheDir(UserHandle.getCallingUserId()), cacheName);
+ cacheFile.delete();
+ }
+
// Mutate the value.
synchronized (mLock) {
switch (operation) {
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 9926ae5..20aca0e 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -41,6 +41,8 @@
import libcore.io.Streams;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.google.android.collect.Lists;
import android.accounts.Account;
@@ -506,6 +508,7 @@
* Cancels a bugreport upon user's request.
*/
private void cancel(int id) {
+ MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_CANCEL);
Log.v(TAG, "cancel: ID=" + id);
final BugreportInfo info = getInfo(id);
if (info != null && !info.finished) {
@@ -582,6 +585,7 @@
* change its values.
*/
private void launchBugreportInfoDialog(int id) {
+ MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_DETAILS);
// Copy values so it doesn't lock mProcesses while UI is being updated
final String name, title, description;
final BugreportInfo info = getInfo(id);
@@ -610,6 +614,7 @@
* upon receiving a {@link #INTENT_BUGREPORT_STARTED}.
*/
private void takeScreenshot(int id, boolean delayed) {
+ MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_SCREENSHOT);
if (getInfo(id) == null) {
// Most likely am killed Shell before user tapped the notification. Since system might
// be too busy anwyays, it's better to ignore the notification and switch back to the
@@ -764,6 +769,12 @@
info.renameScreenshots(mScreenshotsDir);
info.bugreportFile = bugreportFile;
+ final int max = intent.getIntExtra(EXTRA_MAX, -1);
+ if (max != -1) {
+ MetricsLogger.histogram(this, "dumpstate_duration", max);
+ info.max = max;
+ }
+
final File screenshot = getFileExtra(intent, EXTRA_SCREENSHOT);
if (screenshot != null) {
info.addScreenshot(screenshot);
@@ -859,6 +870,7 @@
* intent, but issuing a warning dialog the first time.
*/
private void shareBugreport(int id, BugreportInfo sharedInfo) {
+ MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_SHARE);
BugreportInfo info = getInfo(id);
if (info == null) {
// Service was terminated but notification persisted
@@ -1139,9 +1151,16 @@
if (info == null) {
return;
}
+ if (title != null && !title.equals(info.title)) {
+ MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_DETAILS_TITLE_CHANGED);
+ }
info.title = title;
+ if (description != null && !description.equals(info.description)) {
+ MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_DETAILS_DESCRIPTION_CHANGED);
+ }
info.description = description;
if (name != null && !name.equals(info.name)) {
+ MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_DETAILS_NAME_CHANGED);
info.name = name;
updateProgress(info);
}
@@ -1229,7 +1248,7 @@
/**
* Sets its internal state and displays the dialog.
*/
- private void initialize(Context context, BugreportInfo info) {
+ private void initialize(final Context context, BugreportInfo info) {
// First initializes singleton.
if (mDialog == null) {
@SuppressLint("InflateParams")
@@ -1263,6 +1282,8 @@
@Override
public void onClick(DialogInterface dialog, int id)
{
+ MetricsLogger.action(context,
+ MetricsEvent.ACTION_BUGREPORT_DETAILS_CANCELED);
if (!mTempName.equals(mSavedName)) {
// Must restore dumpstate's name since it was changed
// before user clicked OK.
@@ -1307,6 +1328,7 @@
@Override
public void onClick(View view) {
+ MetricsLogger.action(context, MetricsEvent.ACTION_BUGREPORT_DETAILS_SAVED);
sanitizeName();
final String name = mInfoName.getText().toString();
final String title = mInfoTitle.getText().toString();
@@ -1525,7 +1547,7 @@
return "id: " + id + ", pid: " + pid + ", name: " + name + ", finished: " + finished
+ "\n\ttitle: " + title + "\n\tdescription: " + description
+ "\n\tfile: " + bugreportFile + "\n\tscreenshots: " + screenshotFiles
- + "\n\tprogress: " + progress + "/" + max + "(" + percent + ")"
+ + "\n\tprogress: " + progress + "/" + max + " (" + percent + ")"
+ "\n\tlast_update: " + getFormattedLastUpdate()
+ "\naddingDetailsToZip: " + addingDetailsToZip
+ " addedDetailsToZip: " + addedDetailsToZip;
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 9e07c6d..c590ec7a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -337,7 +337,7 @@
android:launchMode="singleTop"
android:taskAffinity=""
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
- android:resizeable="true"
+ android:resizeableActivity="true"
android:supportsPictureInPicture="true"
androidprv:alwaysFocusable="true"
android:excludeFromRecents="true" />
@@ -348,7 +348,7 @@
android:launchMode="singleTop"
android:taskAffinity=""
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
- android:resizeable="true"
+ android:resizeableActivity="true"
android:supportsPictureInPicture="true"
android:excludeFromRecents="true" />
<activity
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index e4effd4..baec8ef 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -13,25 +13,15 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/volume_dialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/volume_dialog_margin_bottom"
android:background="@drawable/volume_dialog_background"
- android:translationZ="4dp" >
-
- <com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/volume_expand_button"
- style="@style/VolumeButtons"
- android:layout_width="@dimen/volume_button_size"
- android:layout_height="@dimen/volume_button_size"
- android:layout_alignParentLeft="true"
- android:clickable="true"
- android:soundEffectsEnabled="false"
- android:src="@drawable/ic_volume_collapse_animation"
- tools:ignore="RtlHardcoded" />
+ android:translationZ="4dp"
+ android:paddingTop="8dp">
<LinearLayout
android:id="@+id/volume_dialog_content"
@@ -39,9 +29,15 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="8dp"
- android:paddingTop="8dp" >
+ android:paddingStart="8dp">
<!-- volume rows added and removed here! :-) -->
+ <LinearLayout
+ android:id="@+id/volume_row_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/volume_button_size"
+ android:orientation="vertical"/>
<include layout="@layout/volume_zen_footer" />
@@ -49,4 +45,18 @@
<include layout="@layout/tuner_zen_mode_panel" />
</LinearLayout>
+ <com.android.keyguard.AlphaOptimizedImageButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/volume_expand_button"
+ style="@style/VolumeButtons"
+ android:layout_width="@dimen/volume_button_size"
+ android:layout_height="@dimen/volume_button_size"
+ android:clickable="true"
+ android:soundEffectsEnabled="false"
+ android:src="@drawable/ic_volume_collapse_animation"
+ tools:ignore="RtlHardcoded"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentTop="true"/>
+
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index 91e931d..57bac41 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -13,13 +13,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
- android:id="@+id/volume_dialog_row"
- android:paddingEnd="8dp"
- android:paddingStart="8dp" >
+ android:id="@+id/volume_dialog_row" >
<TextView
android:id="@+id/volume_row_header"
@@ -31,7 +30,8 @@
android:paddingBottom="0dp"
android:paddingEnd="12dp"
android:paddingStart="12dp"
- android:paddingTop="4dp" />
+ android:paddingTop="4dp"
+ android:visibility="gone" />
<com.android.keyguard.AlphaOptimizedImageButton
android:id="@+id/volume_row_icon"
@@ -55,12 +55,4 @@
android:paddingEnd="8dp"
android:paddingStart="8dp" />
- <com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/volume_settings_button"
- style="@style/VolumeButtons"
- android:layout_width="@dimen/volume_button_size"
- android:layout_height="@dimen/volume_button_size"
- android:layout_alignParentEnd="true"
- android:layout_below="@id/volume_row_header" />
-
</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_zen_footer.xml b/packages/SystemUI/res/layout/volume_zen_footer.xml
index 28447d7..f30023d 100644
--- a/packages/SystemUI/res/layout/volume_zen_footer.xml
+++ b/packages/SystemUI/res/layout/volume_zen_footer.xml
@@ -32,9 +32,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
- android:orientation="horizontal"
- android:paddingEnd="8dp"
- android:paddingStart="8dp" >
+ android:orientation="horizontal" >
<ImageView
android:id="@+id/volume_zen_icon"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ee61e00..09d830f 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -351,8 +351,8 @@
<!-- The margin between the clock and the notifications on Keyguard. See
keyguard_clock_height_fraction_* for the difference between min and max.-->
- <dimen name="keyguard_clock_notifications_margin_min">24dp</dimen>
- <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
+ <dimen name="keyguard_clock_notifications_margin_min">30dp</dimen>
+ <dimen name="keyguard_clock_notifications_margin_max">42dp</dimen>
<dimen name="heads_up_scrim_height">250dp</dimen>
<!-- The minimum amount the user needs to swipe to go to the camera / phone. -->
@@ -528,6 +528,13 @@
<dimen name="battery_margin_bottom">0dp</dimen>
+ <!-- Padding at the end of the view that displays the mobile signal icons. If the view is
+ empty, then this padding will not be added to that view. -->
+ <dimen name="mobile_signal_group_end_padding">0dp</dimen>
+
+ <!-- Padding between the mobile data type and the strength indicator. -->
+ <dimen name="mobile_data_icon_start_padding">0dp</dimen>
+
<!-- Extra padding between the mobile data type icon and the strength indicator when the data
type icon is wide. -->
<dimen name="wide_type_icon_start_padding">2dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index 33befd0..fcf758b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -103,6 +103,11 @@
mAvatar.setDisabled(disabled);
}
+ public void setEnabled(boolean enabled) {
+ mName.setEnabled(enabled);
+ mAvatar.setDisabled(!enabled);
+ }
+
@Override
protected void onFinishInflate() {
mAvatar = (UserAvatarView) findViewById(R.id.user_picture);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 2c8a478..da98762 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -82,6 +82,9 @@
}
v.setActivated(item.isCurrent);
v.setDisabledByAdmin(item.isDisabledByAdmin);
+ if (!item.isSwitchToEnabled) {
+ v.setEnabled(false);
+ }
v.setTag(item);
return v;
}
@@ -94,7 +97,7 @@
final Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(
mContext, tag.enforcedAdmin);
mController.startActivity(intent);
- } else {
+ } else if (tag.isSwitchToEnabled) {
MetricsLogger.action(mContext, MetricsEvent.QS_SWITCH_USER);
switchTo(tag);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 9aa5ea0..444916a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -90,6 +90,8 @@
View mWifiSignalSpacer;
LinearLayout mMobileSignalGroup;
+ private final int mMobileSignalGroupEndPadding;
+ private final int mMobileDataIconStartPadding;
private final int mWideTypeIconStartPadding;
private final int mSecondaryTelephonyPadding;
private final int mEndPadding;
@@ -113,6 +115,10 @@
super(context, attrs, defStyle);
Resources res = getResources();
+ mMobileSignalGroupEndPadding =
+ res.getDimensionPixelSize(R.dimen.mobile_signal_group_end_padding);
+ mMobileDataIconStartPadding =
+ res.getDimensionPixelSize(R.dimen.mobile_data_icon_start_padding);
mWideTypeIconStartPadding = res.getDimensionPixelSize(R.dimen.wide_type_icon_start_padding);
mSecondaryTelephonyPadding = res.getDimensionPixelSize(R.dimen.secondary_telephony_padding);
mEndPadding = res.getDimensionPixelSize(R.dimen.signal_cluster_battery_padding);
@@ -206,6 +212,10 @@
for (PhoneState state : mPhoneStates) {
mMobileSignalGroup.addView(state.mMobileGroup);
}
+
+ int endPadding = mMobileSignalGroup.getChildCount() > 0 ? mMobileSignalGroupEndPadding : 0;
+ mMobileSignalGroup.setPaddingRelative(0, 0, endPadding, 0);
+
TunerService.get(mContext).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
apply();
@@ -577,9 +587,11 @@
// When this isn't next to wifi, give it some extra padding between the signals.
mMobileGroup.setPaddingRelative(isSecondaryIcon ? mSecondaryTelephonyPadding : 0,
0, 0, 0);
- mMobile.setPaddingRelative(mIsMobileTypeIconWide ? mWideTypeIconStartPadding : 0,
+ mMobile.setPaddingRelative(
+ mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding,
0, 0, 0);
- mMobileDark.setPaddingRelative(mIsMobileTypeIconWide ? mWideTypeIconStartPadding : 0,
+ mMobileDark.setPaddingRelative(
+ mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding,
0, 0, 0);
if (DEBUG) Log.d(TAG, String.format("mobile: %s sig=%d typ=%d",
@@ -592,12 +604,19 @@
private void updateAnimatableIcon(ImageView view, int resId) {
maybeStopAnimatableDrawable(view);
- view.setImageResource(resId);
+ setIconForView(view, resId);
maybeStartAnimatableDrawable(view);
}
private void maybeStopAnimatableDrawable(ImageView view) {
Drawable drawable = view.getDrawable();
+
+ // Check if the icon has been scaled. If it has retrieve the actual drawable out of the
+ // wrapper.
+ if (drawable instanceof ScalingDrawableWrapper) {
+ drawable = ((ScalingDrawableWrapper) drawable).getDrawable();
+ }
+
if (drawable instanceof Animatable) {
Animatable ad = (Animatable) drawable;
if (ad.isRunning()) {
@@ -608,6 +627,13 @@
private void maybeStartAnimatableDrawable(ImageView view) {
Drawable drawable = view.getDrawable();
+
+ // Check if the icon has been scaled. If it has retrieve the actual drawable out of the
+ // wrapper.
+ if (drawable instanceof ScalingDrawableWrapper) {
+ drawable = ((ScalingDrawableWrapper) drawable).getDrawable();
+ }
+
if (drawable instanceof Animatable) {
Animatable ad = (Animatable) drawable;
if (!ad.isRunning()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 6613031..ee88b00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -79,6 +79,11 @@
}
public void show(boolean resetSecuritySelection) {
+ final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
+ if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
+ // In split system user mode, we never unlock system user.
+ return;
+ }
mFalsingManager.onBouncerShown();
ensureView();
if (resetSecuritySelection) {
@@ -91,7 +96,6 @@
}
final int activeUserId = ActivityManager.getCurrentUser();
- final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
final boolean allowDismissKeyguard =
!(UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM)
&& activeUserId == keyguardUserId;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 8381f18..05ae41b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -879,7 +879,11 @@
mQsTracking = false;
mTrackingPointer = -1;
trackMovement(event);
- flingQsWithCurrentVelocity(y, event.getActionMasked() == MotionEvent.ACTION_CANCEL);
+ float fraction = getQsExpansionFraction();
+ if (fraction != 0f || y >= mInitialTouchY) {
+ flingQsWithCurrentVelocity(y,
+ event.getActionMasked() == MotionEvent.ACTION_CANCEL);
+ }
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 867a8a3..fb310a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -21,6 +21,8 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.database.DataSetObserver;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -242,7 +244,6 @@
@Override
public View getView(int position, View convertView, ViewGroup parent) {
UserSwitcherController.UserRecord item = getItem(position);
-
if (!(convertView instanceof UserDetailItemView)
|| !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) {
convertView = LayoutInflater.from(mContext).inflate(
@@ -252,11 +253,17 @@
UserDetailItemView v = (UserDetailItemView) convertView;
String name = getName(mContext, item);
+ Drawable drawable;
if (item.picture == null) {
- v.bind(name, getDrawable(mContext, item));
+ drawable = getDrawable(mContext, item).mutate();
} else {
- v.bind(name, item.picture);
+ drawable = new BitmapDrawable(mContext.getResources(), item.picture);
}
+ // Disable the icon if switching is disabled
+ if (!item.isSwitchToEnabled) {
+ drawable.setTint(mContext.getColor(R.color.qs_tile_disabled_color));
+ }
+ v.bind(name, drawable);
convertView.setActivated(item.isCurrent);
convertView.setTag(item);
return convertView;
@@ -269,7 +276,7 @@
// Close the switcher if tapping the current user. Guest is excluded because
// tapping the guest user while it's current clears the session.
mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
- } else {
+ } else if (user.isSwitchToEnabled) {
switchTo(user);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 13369f2..53fd446 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -99,6 +99,7 @@
private boolean mSimpleUserSwitcher;
private boolean mAddUsersWhenLocked;
private boolean mPauseRefreshUsers;
+ private boolean mAllowUserSwitchingWhenSystemUserLocked;
private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor,
@@ -115,6 +116,7 @@
filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_STOPPING);
+ filter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter,
null /* permission */, null /* scheduler */);
@@ -130,6 +132,10 @@
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ADD_USERS_WHEN_LOCKED), true,
mSettingsObserver);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(
+ Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED),
+ true, mSettingsObserver);
// Fetch initial values.
mSettingsObserver.onChange(false);
@@ -180,6 +186,8 @@
}
ArrayList<UserRecord> records = new ArrayList<>(infos.size());
int currentId = ActivityManager.getCurrentUser();
+ boolean allowUserSwitching = mAllowUserSwitchingWhenSystemUserLocked
+ || mUserManager.isUserUnlocked(UserHandle.SYSTEM);
UserInfo currentUserInfo = null;
UserRecord guestRecord = null;
int avatarSize = mContext.getResources()
@@ -190,23 +198,27 @@
if (isCurrent) {
currentUserInfo = info;
}
- if (info.isGuest()) {
- guestRecord = new UserRecord(info, null /* picture */,
- true /* isGuest */, isCurrent, false /* isAddUser */,
- false /* isRestricted */);
- } else if (info.isEnabled() && info.supportsSwitchToByUser()) {
- Bitmap picture = bitmaps.get(info.id);
- if (picture == null) {
- picture = mUserManager.getUserIcon(info.id);
+ boolean switchToEnabled = allowUserSwitching || isCurrent;
+ if (info.isEnabled()) {
+ if (info.isGuest()) {
+ guestRecord = new UserRecord(info, null /* picture */,
+ true /* isGuest */, isCurrent, false /* isAddUser */,
+ false /* isRestricted */, switchToEnabled);
+ } else if (info.supportsSwitchToByUser()) {
+ Bitmap picture = bitmaps.get(info.id);
+ if (picture == null) {
+ picture = mUserManager.getUserIcon(info.id);
- if (picture != null) {
- picture = BitmapHelper.createCircularClip(
- picture, avatarSize, avatarSize);
+ if (picture != null) {
+ picture = BitmapHelper.createCircularClip(
+ picture, avatarSize, avatarSize);
+ }
}
+ int index = isCurrent ? 0 : records.size();
+ records.add(index, new UserRecord(info, picture, false /* isGuest */,
+ isCurrent, false /* isAddUser */, false /* isRestricted */,
+ switchToEnabled));
}
- int index = isCurrent ? 0 : records.size();
- records.add(index, new UserRecord(info, picture, false /* isGuest */,
- isCurrent, false /* isAddUser */, false /* isRestricted */));
}
}
@@ -228,7 +240,7 @@
if (canCreateGuest) {
guestRecord = new UserRecord(null /* info */, null /* picture */,
true /* isGuest */, false /* isCurrent */,
- false /* isAddUser */, createIsRestricted);
+ false /* isAddUser */, createIsRestricted, allowUserSwitching);
checkIfAddUserDisallowedByAdminOnly(guestRecord);
records.add(guestRecord);
}
@@ -241,7 +253,7 @@
if (!mSimpleUserSwitcher && canCreateUser) {
UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
- createIsRestricted);
+ createIsRestricted, allowUserSwitching);
checkIfAddUserDisallowedByAdminOnly(addUserRecord);
records.add(addUserRecord);
}
@@ -463,6 +475,12 @@
} else if (Intent.ACTION_USER_INFO_CHANGED.equals(intent.getAction())) {
forcePictureLoadForId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL);
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+ // Unlocking the system user may require a refresh
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId != UserHandle.USER_SYSTEM) {
+ return;
+ }
}
refreshUsers(forcePictureLoadForId);
if (unpauseRefreshUsers) {
@@ -525,6 +543,9 @@
SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
mAddUsersWhenLocked = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
+ mAllowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0;
refreshUsers(UserHandle.USER_NULL);
};
};
@@ -646,26 +667,29 @@
public final boolean isRestricted;
public boolean isDisabledByAdmin;
public EnforcedAdmin enforcedAdmin;
+ public boolean isSwitchToEnabled;
public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent,
- boolean isAddUser, boolean isRestricted) {
+ boolean isAddUser, boolean isRestricted, boolean isSwitchToEnabled) {
this.info = info;
this.picture = picture;
this.isGuest = isGuest;
this.isCurrent = isCurrent;
this.isAddUser = isAddUser;
this.isRestricted = isRestricted;
+ this.isSwitchToEnabled = isSwitchToEnabled;
}
public UserRecord copyWithIsCurrent(boolean _isCurrent) {
- return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted);
+ return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted,
+ isSwitchToEnabled);
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("UserRecord(");
if (info != null) {
- sb.append("name=\"" + info.name + "\" id=" + info.id);
+ sb.append("name=\"").append(info.name).append("\" id=").append(info.id);
} else {
if (isGuest) {
sb.append("<add guest placeholder>");
@@ -680,7 +704,10 @@
if (isRestricted) sb.append(" <isRestricted>");
if (isDisabledByAdmin) {
sb.append(" <isDisabledByAdmin>");
- sb.append(" enforcedAdmin=" + enforcedAdmin);
+ sb.append(" enforcedAdmin=").append(enforcedAdmin);
+ }
+ if (isSwitchToEnabled) {
+ sb.append(" <isSwitchToEnabled>");
}
sb.append(')');
return sb.toString();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 1810c1c..1d5ca04 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -25,6 +25,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PixelFormat;
@@ -42,6 +43,7 @@
import android.provider.Settings.Global;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseBooleanArray;
import android.view.Gravity;
import android.view.MotionEvent;
@@ -49,7 +51,6 @@
import android.view.View.AccessibilityDelegate;
import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnClickListener;
-import android.view.View.OnLayoutChangeListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
@@ -91,39 +92,40 @@
public static final String SHOW_FULL_ZEN = "sysui_show_full_zen";
private static final long USER_ATTEMPT_GRACE_PERIOD = 1000;
- private static final int WAIT_FOR_RIPPLE = 200;
private final Context mContext;
private final H mHandler = new H();
private final VolumeDialogController mController;
- private final CustomDialog mDialog;
- private final ViewGroup mDialogView;
- private final ViewGroup mDialogContentView;
- private final ImageButton mExpandButton;
- private final View mSettingsButton;
- private final List<VolumeRow> mRows = new ArrayList<VolumeRow>();
+ private CustomDialog mDialog;
+ private ViewGroup mDialogView;
+ private ViewGroup mDialogContentView;
+ private ViewGroup mVolumeRowContainer;
+ private ImageButton mExpandButton;
+ private final List<VolumeRow> mRows = new ArrayList<>();
private final SpTexts mSpTexts;
private final SparseBooleanArray mDynamic = new SparseBooleanArray();
private final KeyguardManager mKeyguard;
private final AudioManager mAudioManager;
- private final int mExpandButtonAnimationDuration;
- private final ZenFooter mZenFooter;
+ private int mExpandButtonAnimationDuration;
+ private ZenFooter mZenFooter;
private final LayoutTransition mLayoutTransition;
private final Object mSafetyWarningLock = new Object();
private final Accessibility mAccessibility = new Accessibility();
private final ColorStateList mActiveSliderTint;
private final ColorStateList mInactiveSliderTint;
- private final VolumeDialogMotion mMotion;
+ private VolumeDialogMotion mMotion;
+ private final int mWindowType;
+ private final ZenModeController mZenModeController;
private boolean mShowing;
private boolean mExpanded;
+
private int mActiveStream;
private boolean mShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE;
private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE;
private State mState;
- private int mExpandButtonRes;
private boolean mExpandButtonAnimationRunning;
private SafetyWarningDialog mSafetyWarning;
private Callback mCallback;
@@ -131,22 +133,43 @@
private boolean mPendingRecheckAll;
private long mCollapseTime;
private boolean mHovering = false;
- private int mLastActiveStream;
+ private int mDensity;
private boolean mShowFullZen;
- private final TunerZenModePanel mZenPanel;
+ private TunerZenModePanel mZenPanel;
public VolumeDialog(Context context, int windowType, VolumeDialogController controller,
ZenModeController zenModeController, Callback callback) {
mContext = context;
mController = controller;
mCallback = callback;
+ mWindowType = windowType;
+ mZenModeController = zenModeController;
mSpTexts = new SpTexts(mContext);
mKeyguard = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mActiveSliderTint = loadColorStateList(R.color.system_accent_color);
+ mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
+ mLayoutTransition = new LayoutTransition();
+ mLayoutTransition.setDuration(new ValueAnimator().getDuration() / 2);
+ initDialog();
+
+ mAccessibility.init();
+
+ controller.addCallback(mControllerCallbackH, mHandler);
+ controller.getState();
+ TunerService.get(mContext).addTunable(this, SHOW_FULL_ZEN);
+
+ final Configuration currentConfig = mContext.getResources().getConfiguration();
+ mDensity = currentConfig.densityDpi;
+ }
+
+ private void initDialog() {
mDialog = new CustomDialog(mContext);
+ mHovering = false;
+ mShowing = false;
final Window window = mDialog.getWindow();
window.requestFeature(Window.FEATURE_NO_TITLE);
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
@@ -160,7 +183,7 @@
mDialog.setCanceledOnTouchOutside(true);
final Resources res = mContext.getResources();
final WindowManager.LayoutParams lp = window.getAttributes();
- lp.type = windowType;
+ lp.type = mWindowType;
lp.format = PixelFormat.TRANSLUCENT;
lp.setTitle(VolumeDialog.class.getSimpleName());
lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
@@ -170,8 +193,7 @@
window.setAttributes(lp);
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
- mActiveSliderTint = loadColorStateList(R.color.system_accent_color);
- mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
+
mDialog.setContentView(R.layout.volume_dialog);
mDialogView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog);
mDialogView.setOnHoverListener(new View.OnHoverListener() {
@@ -185,56 +207,53 @@
}
});
mDialogContentView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog_content);
+ mVolumeRowContainer =
+ (ViewGroup) mDialogContentView.findViewById(R.id.volume_row_container);
+ mExpanded = false;
mExpandButton = (ImageButton) mDialogView.findViewById(R.id.volume_expand_button);
mExpandButton.setOnClickListener(mClickExpand);
updateWindowWidthH();
updateExpandButtonH();
- mLayoutTransition = new LayoutTransition();
- mLayoutTransition.setDuration(new ValueAnimator().getDuration() / 2);
+
mDialogContentView.setLayoutTransition(mLayoutTransition);
mMotion = new VolumeDialogMotion(mDialog, mDialogView, mDialogContentView, mExpandButton,
new VolumeDialogMotion.Callback() {
- @Override
- public void onAnimatingChanged(boolean animating) {
- if (animating) return;
- if (mPendingStateChanged) {
- mHandler.sendEmptyMessage(H.STATE_CHANGED);
- mPendingStateChanged = false;
- }
- if (mPendingRecheckAll) {
- mHandler.sendEmptyMessage(H.RECHECK_ALL);
- mPendingRecheckAll = false;
- }
- }
- });
+ @Override
+ public void onAnimatingChanged(boolean animating) {
+ if (animating) return;
+ if (mPendingStateChanged) {
+ mHandler.sendEmptyMessage(H.STATE_CHANGED);
+ mPendingStateChanged = false;
+ }
+ if (mPendingRecheckAll) {
+ mHandler.sendEmptyMessage(H.RECHECK_ALL);
+ mPendingRecheckAll = false;
+ }
+ }
+ });
- addRow(AudioManager.STREAM_RING,
- R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true);
- addRow(AudioManager.STREAM_MUSIC,
- R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true);
- addRow(AudioManager.STREAM_ALARM,
- R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, false);
- addRow(AudioManager.STREAM_VOICE_CALL,
- R.drawable.ic_volume_voice, R.drawable.ic_volume_voice, false);
- addRow(AudioManager.STREAM_BLUETOOTH_SCO,
- R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false);
- addRow(AudioManager.STREAM_SYSTEM,
- R.drawable.ic_volume_system, R.drawable.ic_volume_system_mute, false);
-
- mSettingsButton = mDialog.findViewById(R.id.volume_settings_button);
- mSettingsButton.setOnClickListener(mClickSettings);
+ if (mRows.isEmpty()) {
+ addRow(AudioManager.STREAM_RING,
+ R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true);
+ addRow(AudioManager.STREAM_MUSIC,
+ R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true);
+ addRow(AudioManager.STREAM_ALARM,
+ R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, false);
+ addRow(AudioManager.STREAM_VOICE_CALL,
+ R.drawable.ic_volume_voice, R.drawable.ic_volume_voice, false);
+ addRow(AudioManager.STREAM_BLUETOOTH_SCO,
+ R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false);
+ addRow(AudioManager.STREAM_SYSTEM,
+ R.drawable.ic_volume_system, R.drawable.ic_volume_system_mute, false);
+ } else {
+ addExistingRows();
+ }
mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration);
mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer);
- mZenFooter.init(zenModeController);
+ mZenFooter.init(mZenModeController);
mZenPanel = (TunerZenModePanel) mDialog.findViewById(R.id.tuner_zen_mode_panel);
- mZenPanel.init(zenModeController);
+ mZenPanel.init(mZenModeController);
mZenPanel.setCallback(mZenPanelCallback);
-
- mAccessibility.init();
-
- controller.addCallback(mControllerCallbackH, mHandler);
- controller.getState();
- TunerService.get(mContext).addTunable(this, SHOW_FULL_ZEN);
}
@Override
@@ -285,46 +304,38 @@
}
private void addRow(int stream, int iconRes, int iconMuteRes, boolean important) {
- final VolumeRow row = initRow(stream, iconRes, iconMuteRes, important);
+ VolumeRow row = new VolumeRow();
+ initRow(row, stream, iconRes, iconMuteRes, important);
if (!mRows.isEmpty()) {
- final View v = new View(mContext);
- v.setId(android.R.id.background);
- final int h = mContext.getResources()
- .getDimensionPixelSize(R.dimen.volume_slider_interspacing);
- final LinearLayout.LayoutParams lp =
- new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, h);
- mDialogContentView.addView(v, mDialogContentView.getChildCount() - 2, lp);
- row.space = v;
+ addSpacer(row);
}
- row.settingsButton.addOnLayoutChangeListener(new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- final boolean moved = mLastActiveStream != mActiveStream ||
- oldLeft != left || oldTop != top;
- if (D.BUG) Log.d(TAG, "onLayoutChange moved=" + moved
- + " old=" + new Rect(oldLeft, oldTop, oldRight, oldBottom).toShortString()
- + "," + mLastActiveStream
- + " new=" + new Rect(left,top,right,bottom).toShortString()
- + "," + mActiveStream);
- mLastActiveStream = mActiveStream;
- if (moved) {
- for (int i = 0; i < mDialogContentView.getChildCount(); i++) {
- final View c = mDialogContentView.getChildAt(i);
- if (!c.isShown()) continue;
- if (c == row.view) {
- repositionExpandAnim(row);
- }
- return;
- }
- }
- }
- });
- // add new row just before the footer
- mDialogContentView.addView(row.view, mDialogContentView.getChildCount() - 2);
+ mVolumeRowContainer.addView(row.view);
mRows.add(row);
}
+ private void addExistingRows() {
+ int N = mRows.size();
+ for (int i = 0; i < N; i++) {
+ final VolumeRow row = mRows.get(i);
+ initRow(row, row.stream, row.iconRes, row.iconMuteRes, row.important);
+ if (i > 0) {
+ addSpacer(row);
+ }
+ mVolumeRowContainer.addView(row.view);
+ }
+ }
+
+ private void addSpacer(VolumeRow row) {
+ final View v = new View(mContext);
+ v.setId(android.R.id.background);
+ final int h = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.volume_slider_interspacing);
+ final LinearLayout.LayoutParams lp =
+ new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, h);
+ mVolumeRowContainer.addView(v, lp);
+ row.space = v;
+ }
+
private boolean isAttached() {
return mDialogContentView != null && mDialogContentView.isAttachedToWindow();
}
@@ -345,18 +356,6 @@
return null;
}
- private void repositionExpandAnim(VolumeRow row) {
- final int[] loc = new int[2];
- row.settingsButton.getLocationInWindow(loc);
- final MarginLayoutParams mlp = (MarginLayoutParams) mDialogView.getLayoutParams();
- final int x = loc[0] - mlp.leftMargin;
- final int y = loc[1] - mlp.topMargin;
- if (D.BUG) Log.d(TAG, "repositionExpandAnim x=" + x + " y=" + y);
- mExpandButton.setTranslationX(x);
- mExpandButton.setTranslationY(y);
- mExpandButton.setTag((Integer) y);
- }
-
public void dump(PrintWriter writer) {
writer.println(VolumeDialog.class.getSimpleName() + " state:");
writer.print(" mShowing: "); writer.println(mShowing);
@@ -374,8 +373,8 @@
}
@SuppressLint("InflateParams")
- private VolumeRow initRow(final int stream, int iconRes, int iconMuteRes, boolean important) {
- final VolumeRow row = new VolumeRow();
+ private void initRow(final VolumeRow row, final int stream, int iconRes, int iconMuteRes,
+ boolean important) {
row.stream = stream;
row.iconRes = iconRes;
row.iconMuteRes = iconMuteRes;
@@ -442,9 +441,6 @@
row.userAttempt = 0; // reset the grace period, slider should update immediately
}
});
- row.settingsButton = (ImageButton) row.view.findViewById(R.id.volume_settings_button);
- row.settingsButton.setOnClickListener(mClickSettings);
- return row;
}
public void destroy() {
@@ -573,8 +569,6 @@
if (mExpandButtonAnimationRunning && isAttached()) return;
final int res = mExpanded ? R.drawable.ic_volume_collapse_animation
: R.drawable.ic_volume_expand_animation;
- if (res == mExpandButtonRes) return;
- mExpandButtonRes = res;
if (hasTouchFeature()) {
mExpandButton.setImageResource(res);
} else {
@@ -606,16 +600,6 @@
final boolean visible = isVisibleH(row, isActive);
Util.setVisOrGone(row.view, visible);
Util.setVisOrGone(row.space, visible && mExpanded);
- final int expandButtonRes = mExpanded ? R.drawable.ic_volume_settings : 0;
- if (expandButtonRes != row.cachedExpandButtonRes) {
- row.cachedExpandButtonRes = expandButtonRes;
- if (expandButtonRes == 0) {
- row.settingsButton.setImageDrawable(null);
- } else {
- row.settingsButton.setImageResource(expandButtonRes);
- }
- }
- Util.setVisOrInvis(row.settingsButton, false);
updateVolumeRowHeaderVisibleH(row);
row.header.setAlpha(mExpanded && isActive ? 1 : 0.5f);
updateVolumeRowSliderTintH(row, isActive);
@@ -629,8 +613,8 @@
if (row.ss == null || !row.ss.dynamic) continue;
if (!mDynamic.get(row.stream)) {
mRows.remove(i);
- mDialogContentView.removeView(row.view);
- mDialogContentView.removeView(row.space);
+ mVolumeRowContainer.removeView(row.view);
+ mVolumeRowContainer.removeView(row.space);
}
}
}
@@ -911,6 +895,12 @@
@Override
public void onConfigurationChanged() {
+ Configuration newConfig = mContext.getResources().getConfiguration();
+ final int density = newConfig.densityDpi;
+ if (density != mDensity) {
+ mDialog.dismiss();
+ initDialog();
+ }
updateWindowWidthH();
mSpTexts.update();
mZenFooter.onConfigurationChanged();
@@ -963,21 +953,6 @@
}
};
- private final OnClickListener mClickSettings = new OnClickListener() {
- @Override
- public void onClick(View v) {
- mSettingsButton.postDelayed(new Runnable() {
- @Override
- public void run() {
- Events.writeEvent(mContext, Events.EVENT_SETTINGS_CLICK);
- if (mCallback != null) {
- mCallback.onSettingsClicked();
- }
- }
- }, WAIT_FOR_RIPPLE);
- }
- };
-
private final class H extends Handler {
private static final int SHOW = 1;
private static final int DISMISS = 2;
@@ -1155,7 +1130,6 @@
private TextView header;
private ImageButton icon;
private SeekBar slider;
- private ImageButton settingsButton;
private int stream;
private StreamState ss;
private long userAttempt; // last user-driven slider change
@@ -1168,12 +1142,10 @@
private ColorStateList cachedSliderTint;
private int iconState; // from Events
private boolean cachedShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
- private int cachedExpandButtonRes;
private int lastAudibleLevel = 1;
}
public interface Callback {
- void onSettingsClicked();
void onZenSettingsClicked();
void onZenPrioritySettingsClicked();
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index d7635ad..3d33809 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -168,11 +168,6 @@
private final VolumeDialog.Callback mVolumeDialogCallback = new VolumeDialog.Callback() {
@Override
- public void onSettingsClicked() {
- startSettings(new Intent(Settings.ACTION_NOTIFICATION_SETTINGS));
- }
-
- @Override
public void onZenSettingsClicked() {
startSettings(ZenModePanel.ZEN_SETTINGS);
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
index 04339eb..bbb70ed 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
@@ -43,7 +43,7 @@
public static final String PREF_ADJUST_ALARMS = "pref_adjust_alarms";
public static final String PREF_ADJUST_NOTIFICATION = "pref_adjust_notification";
- public static final boolean DEFAULT_SHOW_HEADERS = true;
+ public static final boolean DEFAULT_SHOW_HEADERS = false;
public static final boolean DEFAULT_ENABLE_AUTOMUTE = true;
public static final boolean DEFAULT_ENABLE_SILENT_MODE = true;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
index a03e7f7..c06b63b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
@@ -139,9 +139,8 @@
}
public void onConfigurationChanged() {
- mEndNowButton.setText(mContext.getString(R.string.volume_zen_end_now));
- mSpTexts.update();
Util.setText(mEndNowButton, mContext.getString(R.string.volume_zen_end_now));
+ mSpTexts.update();
}
}
diff --git a/preloaded-classes b/preloaded-classes
index 9535cc2..be645d2 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -907,7 +907,7 @@
android.graphics.drawable.AnimatedVectorDrawable$1
android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState
android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState$PendingAnimator
-android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimator
+android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT
android.graphics.drawable.AnimationDrawable
android.graphics.drawable.AnimationDrawable$AnimationState
android.graphics.drawable.BitmapDrawable
diff --git a/proto/jarjar-rules.txt b/proto/jarjar-rules.txt
index 0c77c2a..50220b4 100644
--- a/proto/jarjar-rules.txt
+++ b/proto/jarjar-rules.txt
@@ -1 +1,2 @@
-rule com.google.** com.android.@1
+rule com.google.protobuf.nano.** com.android.framework.protobuf.nano.@1
+
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 3f3f851..cd31b17 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -369,5 +369,44 @@
// Logged when the user saves a modification to notification importance. Negative numbers
// indicate the user lowered the importance; positive means they increased it.
ACTION_SAVE_IMPORTANCE = 291;
+
+ // Interactive bug report initiated from power menu.
+ ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE = 292;
+
+ // Full bug report initiated from power menu.
+ ACTION_BUGREPORT_FROM_POWER_MENU_FULL = 293;
+
+ // Interactive bug report initiated from Settings.
+ ACTION_BUGREPORT_FROM_SETTINGS_INTERACTIVE = 294;
+
+ // Full bug report initiated from Settings.
+ ACTION_BUGREPORT_FROM_SETTINGS_FULL = 295;
+
+ // Bug report canceled using system notification.
+ ACTION_BUGREPORT_NOTIFICATION_ACTION_CANCEL = 296;
+
+ // Bug report details screen open using system notification.
+ ACTION_BUGREPORT_NOTIFICATION_ACTION_DETAILS = 297;
+
+ // Additional Bug report screen shot taken using system notification.
+ ACTION_BUGREPORT_NOTIFICATION_ACTION_SCREENSHOT = 298;
+
+ // Bug report shared by user using system notification.
+ ACTION_BUGREPORT_NOTIFICATION_ACTION_SHARE = 299;
+
+ // User changed bug report name using the details screen.
+ ACTION_BUGREPORT_DETAILS_NAME_CHANGED = 300;
+
+ // User changed bug report title using the details screen.
+ ACTION_BUGREPORT_DETAILS_TITLE_CHANGED = 301;
+
+ // User changed bug report description using the details screen.
+ ACTION_BUGREPORT_DETAILS_DESCRIPTION_CHANGED = 302;
+
+ // Changes made on bug report details screen were saved by user.
+ ACTION_BUGREPORT_DETAILS_SAVED = 303;
+
+ // Changes made on bug report details screen were canceled by user.
+ ACTION_BUGREPORT_DETAILS_CANCELED = 304;
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 388c8b7..0dbc5be 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -351,6 +351,7 @@
// user change and unlock
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
intentFilter.addAction(Intent.ACTION_USER_PRESENT);
intentFilter.addAction(Intent.ACTION_SETTING_RESTORED);
@@ -361,6 +362,8 @@
String action = intent.getAction();
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+ unlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
@@ -900,6 +903,13 @@
}
}
+ private void unlockUser(int userId) {
+ synchronized (mLock) {
+ UserState userState = getUserStateLocked(userId);
+ onUserStateChangedLocked(userState);
+ }
+ }
+
private void removeUser(int userId) {
synchronized (mLock) {
mUserStates.remove(userId);
@@ -1002,8 +1012,9 @@
List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
new Intent(AccessibilityService.SERVICE_INTERFACE),
PackageManager.GET_SERVICES
- | PackageManager.GET_META_DATA
- | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
+ | PackageManager.GET_META_DATA
+ | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+ | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
mCurrentUserId);
for (int i = 0, count = installedServices.size(); i < count; i++) {
@@ -1236,6 +1247,8 @@
private void manageServicesLocked(UserState userState) {
Map<ComponentName, Service> componentNameToServiceMap =
userState.mComponentNameToServiceMap;
+ boolean isUnlocked = mContext.getSystemService(UserManager.class)
+ .isUserUnlocked(userState.mUserId);
boolean isEnabled = userState.mIsAccessibilityEnabled;
for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
@@ -1244,6 +1257,12 @@
installedService.getId());
Service service = componentNameToServiceMap.get(componentName);
+ // Ignore non-encryption-aware services until user is unlocked
+ if (!isUnlocked && !installedService.isEncryptionAware()) {
+ Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName);
+ continue;
+ }
+
if (isEnabled) {
// Wait for the binding if it is in process.
if (userState.mBindingServices.contains(componentName)) {
@@ -1272,7 +1291,7 @@
// No enabled installed services => disable accessibility to avoid
// sending accessibility events with no recipient across processes.
- if (isEnabled && userState.mBoundServices.isEmpty()
+ if (isEnabled && isUnlocked && userState.mBoundServices.isEmpty()
&& userState.mBindingServices.isEmpty()) {
userState.mIsAccessibilityEnabled = false;
final long identity = Binder.clearCallingIdentity();
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 2b52799..f537d18 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -353,7 +353,10 @@
}
private void onPackageBroadcastReceived(Intent intent, int userId) {
- if (!mUserManager.isUserUnlocked(userId)) return;
+ if (!mUserManager.isUserUnlocked(userId) ||
+ isProfileWithLockedParent(userId)) {
+ return;
+ }
final String action = intent.getAction();
boolean added = false;
@@ -435,7 +438,10 @@
* due to user not being available and package suspension.
*/
private void reloadWidgetsMaskedStateForUser(int userId) {
- if (!mUserManager.isUserUnlocked(userId)) return;
+ if (!mUserManager.isUserUnlocked(userId) ||
+ isProfileWithLockedParent(userId)) {
+ return;
+ }
synchronized (mLock) {
reloadWidgetPackageSuspensionMaskedStateLocked(userId);
List<UserInfo> profiles = mUserManager.getEnabledProfiles(userId);
@@ -606,7 +612,10 @@
throw new IllegalStateException(
"User " + userId + " must be unlocked for widgets to be available");
}
-
+ if (isProfileWithLockedParent(userId)) {
+ throw new IllegalStateException(
+ "Profile " + userId + " must have unlocked parent");
+ }
final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
// Careful lad, we may have already loaded the state for some
@@ -2458,6 +2467,9 @@
}
private void onUserUnlocked(int userId) {
+ if (isProfileWithLockedParent(userId)) {
+ return;
+ }
synchronized (mLock) {
ensureGroupStateLoadedLocked(userId);
reloadWidgetsMaskedStateForUser(userId);
@@ -3306,6 +3318,23 @@
}
}
+ private boolean isProfileWithLockedParent(int userId) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ UserInfo userInfo = mUserManager.getUserInfo(userId);
+ if (userInfo != null && userInfo.isManagedProfile()) {
+ UserInfo parentInfo = mUserManager.getProfileParent(userId);
+ if (parentInfo != null
+ && !mUserManager.isUserUnlocked(parentInfo.getUserHandle())) {
+ return true;
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return false;
+ }
+
private boolean isProfileWithUnlockedParent(int userId) {
UserInfo userInfo = mUserManager.getUserInfo(userId);
if (userInfo != null && userInfo.isManagedProfile()) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 37f2425..d14364d 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -315,15 +315,15 @@
IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_REMOVED);
- userFilter.addAction(Intent.ACTION_USER_STARTED);
+ userFilter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_USER_REMOVED.equals(action)) {
onUserRemoved(intent);
- } else if (Intent.ACTION_USER_STARTED.equals(action)) {
- onUserStarted(intent);
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+ onUserUnlocked(intent);
}
}
}, UserHandle.ALL, userFilter, null, null);
@@ -513,7 +513,7 @@
}
}
- private void onUserStarted(Intent intent) {
+ private void onUserUnlocked(Intent intent) {
int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userId < 1) return;
@@ -991,13 +991,9 @@
for (UserInfo user : users) {
if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
addSharedAccountAsUser(account, user.id);
- try {
- if (ActivityManagerNative.getDefault().isUserRunning(user.id, 0)) {
- mMessageHandler.sendMessage(mMessageHandler.obtainMessage(
- MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
- }
- } catch (RemoteException re) {
- // Shouldn't happen
+ if (mUserManager.isUserUnlocked(user.id)) {
+ mMessageHandler.sendMessage(mMessageHandler.obtainMessage(
+ MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ed07707..ec0e075 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17820,36 +17820,42 @@
final long origId = Binder.clearCallingIdentity();
final ActivityStack stack = mStackSupervisor.getStack(fromStackId);
if (stack != null) {
- if (fromStackId == DOCKED_STACK_ID) {
+ mWindowManager.deferSurfaceLayout();
+ try {
+ if (fromStackId == DOCKED_STACK_ID) {
- // We are moving all tasks from the docked stack to the fullscreen stack, which
- // is dismissing the docked stack, so resize all other stacks to fullscreen here
- // already so we don't end up with resize trashing.
- for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
- if (StackId.isResizeableByDockedStack(i)) {
- ActivityStack otherStack = mStackSupervisor.getStack(i);
- if (otherStack != null) {
- mStackSupervisor.resizeStackLocked(i,
- null, null, null, PRESERVE_WINDOWS,
- true /* allowResizeInDockedMode */);
+ // We are moving all tasks from the docked stack to the fullscreen stack,
+ // which is dismissing the docked stack, so resize all other stacks to
+ // fullscreen here already so we don't end up with resize trashing.
+ for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+ if (StackId.isResizeableByDockedStack(i)) {
+ ActivityStack otherStack = mStackSupervisor.getStack(i);
+ if (otherStack != null) {
+ mStackSupervisor.resizeStackLocked(i,
+ null, null, null, PRESERVE_WINDOWS,
+ true /* allowResizeInDockedMode */);
+ }
}
}
}
- }
- final ArrayList<TaskRecord> tasks = stack.getAllTasks();
- final int size = tasks.size();
- if (onTop) {
- for (int i = 0; i < size; i++) {
- mStackSupervisor.moveTaskToStackLocked(tasks.get(i).taskId,
- FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, !FORCE_FOCUS,
- "moveTasksToFullscreenStack", ANIMATE);
+ final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ final int size = tasks.size();
+ if (onTop) {
+ for (int i = 0; i < size; i++) {
+ mStackSupervisor.moveTaskToStackLocked(tasks.get(i).taskId,
+ FULLSCREEN_WORKSPACE_STACK_ID, onTop, !FORCE_FOCUS,
+ "moveTasksToFullscreenStack", ANIMATE);
+ }
+ } else {
+ for (int i = size - 1; i >= 0; i--) {
+ mStackSupervisor.positionTaskInStackLocked(tasks.get(i).taskId,
+ FULLSCREEN_WORKSPACE_STACK_ID, 0);
+ }
}
- } else {
- for (int i = size - 1; i >= 0; i--) {
- mStackSupervisor.positionTaskInStackLocked(tasks.get(i).taskId,
- FULLSCREEN_WORKSPACE_STACK_ID, 0);
- }
+ } finally {
+ mWindowManager.continueSurfaceLayout();
}
+
}
Binder.restoreCallingIdentity(origId);
}
@@ -20505,6 +20511,10 @@
Slog.w(TAG, "No user info for user #" + targetUserId);
return false;
}
+ if (!targetUserInfo.supportsSwitchTo()) {
+ Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not supported");
+ return false;
+ }
if (targetUserInfo.isManagedProfile()) {
Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not a full user");
return false;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 257e333..2394842 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2362,6 +2362,8 @@
stack.positionTask(task, position);
// The task might have already been running and its visibility needs to be synchronized with
// the visibility of the stack / windows.
+ stack.ensureActivityConfigurationLocked(task.topRunningActivityLocked(), 0,
+ !PRESERVE_WINDOWS);
stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
resumeFocusedStackTopActivityLocked();
}
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 9b2bca0..e4b4c2d 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -98,15 +98,23 @@
mAInfo = aInfo;
mResolvedType = resolvedType;
mInTask = inTask;
- interceptQuietProfileIfNeeded();
- interceptSuspendPackageIfNeed();
+ if (interceptSuspendPackageIfNeed()) {
+ // Skip the rest of interceptions as the package is suspended by device admin so
+ // no user action can undo this.
+ return;
+ }
+ if (interceptQuietProfileIfNeeded()) {
+ // If work profile is turned off, skip the work challenge since the profile can only
+ // be unlocked when profile's user is running.
+ return;
+ }
interceptWorkProfileChallengeIfNeeded();
}
- private void interceptQuietProfileIfNeeded() {
+ private boolean interceptQuietProfileIfNeeded() {
// Do not intercept if the user has not turned off the profile
if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
- return;
+ return false;
}
mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId);
mCallingPid = mRealCallingPid;
@@ -115,15 +123,15 @@
final UserInfo parent = mUserManager.getProfileParent(mUserId);
mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
- mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
- null /*profilerInfo*/);
+ mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
+ return true;
}
- private void interceptSuspendPackageIfNeed() {
+ private boolean interceptSuspendPackageIfNeed() {
// Do not intercept if the admin did not suspend the package
if (mAInfo == null || mAInfo.applicationInfo == null ||
(mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
- return;
+ return false;
}
mIntent = UnlaunchableAppActivity.createPackageSuspendedDialogIntent(mAInfo.packageName,
mUserId);
@@ -137,15 +145,15 @@
} else {
mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
}
- mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
- null /*profilerInfo*/);
+ mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
+ return true;
}
- private void interceptWorkProfileChallengeIfNeeded() {
+ private boolean interceptWorkProfileChallengeIfNeeded() {
final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mIntent,
mResolvedType, mAInfo, mCallingPackage, mUserId);
if (interceptingIntent == null) {
- return;
+ return false;
}
mIntent = interceptingIntent;
mCallingPid = mRealCallingPid;
@@ -161,8 +169,8 @@
final UserInfo parent = mUserManager.getProfileParent(mUserId);
mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
- mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
- null /*profilerInfo*/);
+ mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
+ return true;
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 6614e63..9c7eb95 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -608,7 +608,13 @@
// app in a locked managed profile from an unlocked parent allow it to resolve
// as user will be sent via confirm credentials to unlock the profile.
UserManager userManager = UserManager.get(mService.mContext);
- UserInfo parent = userManager.getProfileParent(userId);
+ UserInfo parent = null;
+ long token = Binder.clearCallingIdentity();
+ try {
+ parent = userManager.getProfileParent(userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
if (parent != null
&& userManager.isUserUnlocked(parent.getUserHandle())
&& !userManager.isUserUnlocked(userInfo.getUserHandle())) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 4e6dc3a..addffd3 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -68,6 +68,7 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManagerInternal;
import android.os.storage.IMountService;
import android.os.storage.StorageManager;
import android.provider.Settings;
@@ -82,6 +83,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.LocalServices;
import com.android.server.pm.UserManagerService;
import java.io.PrintWriter;
@@ -561,6 +563,10 @@
continue;
}
UserInfo userInfo = getUserInfo(oldUserId);
+ if (userInfo.isEphemeral()) {
+ LocalServices.getService(UserManagerInternal.class)
+ .onEphemeralUserStop(oldUserId);
+ }
if (userInfo.isGuest() || userInfo.isEphemeral()) {
// This is a user to be stopped.
stopUsersLocked(oldUserId, true, null);
@@ -1375,6 +1381,11 @@
* intercept activity launches for work apps when the Work Challenge is present.
*/
boolean shouldConfirmCredentials(int userId) {
+ synchronized (mService) {
+ if (mStartedUsers.get(userId) == null) {
+ return false;
+ }
+ }
if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
return false;
}
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
new file mode 100644
index 0000000..f6dc9b9
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import com.android.server.SystemService;
+
+import android.content.Context;
+import android.net.ConnectivityMetricsEvent;
+import android.net.ConnectivityMetricsLogger;
+import android.net.IConnectivityMetricsLogger;
+import android.net.IConnectivityMetricsLoggerSubscriber;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** {@hide} */
+public class MetricsLoggerService extends SystemService {
+ private static String TAG = "ConnectivityMetricsLoggerService";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ public MetricsLoggerService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
+ publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE,
+ mBinder);
+ }
+ }
+
+ private final int MAX_NUMBER_OF_EVENTS = 100;
+ private final int MAX_TIME_OFFSET = 15*60*1000; // 15 minutes
+ private final List<ConnectivityMetricsEvent> mEvents = new ArrayList<>();
+ private long mLastSentEventTimeMillis = System.currentTimeMillis();
+
+ private final void enforceConnectivityInternalPermission() {
+ getContext().enforceCallingPermission(
+ android.Manifest.permission.CONNECTIVITY_INTERNAL,
+ "MetricsLoggerService");
+ }
+
+ /**
+ * Implementation of the IConnectivityMetricsLogger interface.
+ */
+ private final IConnectivityMetricsLogger.Stub mBinder = new IConnectivityMetricsLogger.Stub() {
+
+ private final ArrayMap<IConnectivityMetricsLoggerSubscriber,
+ IBinder.DeathRecipient> mSubscribers = new ArrayMap<>();
+
+
+ private ConnectivityMetricsEvent[] prepareEventsToSendIfReady() {
+ ConnectivityMetricsEvent[] eventsToSend = null;
+ final long currentTimeMillis = System.currentTimeMillis();
+ final long timeOffset = currentTimeMillis - mLastSentEventTimeMillis;
+ if (timeOffset >= MAX_TIME_OFFSET
+ || timeOffset < 0 // system time has changed
+ || mEvents.size() >= MAX_NUMBER_OF_EVENTS) {
+ // batch events
+ mLastSentEventTimeMillis = currentTimeMillis;
+ eventsToSend = new ConnectivityMetricsEvent[mEvents.size()];
+ mEvents.toArray(eventsToSend);
+ mEvents.clear();
+ }
+ return eventsToSend;
+ }
+
+ private void maybeSendEventsToSubscribers(ConnectivityMetricsEvent[] eventsToSend) {
+ if (eventsToSend == null || eventsToSend.length == 0) return;
+ synchronized (mSubscribers) {
+ for (IConnectivityMetricsLoggerSubscriber s : mSubscribers.keySet()) {
+ try {
+ s.onEvents(eventsToSend);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "RemoteException " + ex);
+ }
+ }
+ }
+ }
+
+ public void logEvent(ConnectivityMetricsEvent event) {
+ ConnectivityMetricsEvent[] events = new ConnectivityMetricsEvent[]{event};
+ logEvents(events);
+ }
+
+ public void logEvents(ConnectivityMetricsEvent[] events) {
+ enforceConnectivityInternalPermission();
+ ConnectivityMetricsEvent[] eventsToSend;
+
+ if (VDBG) {
+ for (ConnectivityMetricsEvent e : events) {
+ Log.v(TAG, "writeEvent(" + e.toString() + ")");
+ }
+ }
+
+ synchronized (mEvents) {
+ for (ConnectivityMetricsEvent e : events) {
+ mEvents.add(e);
+ }
+
+ eventsToSend = prepareEventsToSendIfReady();
+ }
+
+ maybeSendEventsToSubscribers(eventsToSend);
+ }
+
+ public boolean subscribe(IConnectivityMetricsLoggerSubscriber subscriber) {
+ enforceConnectivityInternalPermission();
+ if (VDBG) Log.v(TAG, "subscribe");
+
+ synchronized (mSubscribers) {
+ if (mSubscribers.containsKey(subscriber)) {
+ Log.e(TAG, "subscriber is already subscribed");
+ return false;
+ }
+ final IConnectivityMetricsLoggerSubscriber s = subscriber;
+ IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ if (VDBG) Log.v(TAG, "subscriber died");
+ synchronized (mSubscribers) {
+ mSubscribers.remove(s);
+ }
+ }
+ };
+
+ try {
+ subscriber.asBinder().linkToDeath(dr, 0);
+ mSubscribers.put(subscriber, dr);
+ } catch (RemoteException e) {
+ Log.e(TAG, "subscribe failed: " + e);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void unsubscribe(IConnectivityMetricsLoggerSubscriber subscriber) {
+ enforceConnectivityInternalPermission();
+ if (VDBG) Log.v(TAG, "unsubscribe");
+ synchronized (mSubscribers) {
+ IBinder.DeathRecipient dr = mSubscribers.remove(subscriber);
+ if (dr == null) {
+ Log.e(TAG, "subscriber is not subscribed");
+ return;
+ }
+ subscriber.asBinder().unlinkToDeath(dr, 0);
+ }
+ }
+ };
+}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 13e7648..e9d684a 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -62,6 +62,7 @@
import android.hardware.fingerprint.IFingerprintDaemonCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
@@ -504,6 +505,9 @@
}
public boolean hasEnrolledFingerprints(int userId) {
+ if (userId != Binder.getCallingUid()) {
+ checkPermission(INTERACT_ACROSS_USERS);
+ }
return mFingerprintUtils.getFingerprintsForUser(mContext, userId).size() > 0;
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 7fb1783..ed68abe 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -508,18 +508,18 @@
};
private void subscriptionOrSimChanged(Context context) {
- Log.d(TAG, "received SIM related action: ");
+ if (DEBUG) Log.d(TAG, "received SIM related action: ");
TelephonyManager phone = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
String mccMnc = phone.getSimOperator();
if (!TextUtils.isEmpty(mccMnc)) {
- Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
+ if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
synchronized (mLock) {
reloadGpsProperties(context, mProperties);
mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
}
} else {
- Log.d(TAG, "SIM MCC/MNC is still not available");
+ if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available");
}
}
@@ -569,7 +569,7 @@
}
private void reloadGpsProperties(Context context, Properties properties) {
- Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
+ if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
loadPropertiesFromResource(context, properties);
boolean isPropertiesLoadedFromFile = false;
final String gpsHardware = SystemProperties.get("ro.hardware.gps");
@@ -582,7 +582,7 @@
if (!isPropertiesLoadedFromFile) {
loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties);
}
- Log.d(TAG, "GPS properties reloaded, size = " + properties.size());
+ if (DEBUG) Log.d(TAG, "GPS properties reloaded, size = " + properties.size());
// TODO: we should get rid of C2K specific setting.
setSuplHostPort(properties.getProperty("SUPL_HOST"),
@@ -603,7 +603,7 @@
ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
properties.store(baos, null);
native_configuration_update(baos.toString());
- Log.d(TAG, "final config = " + baos.toString());
+ if (DEBUG) Log.d(TAG, "final config = " + baos.toString());
} catch (IOException ex) {
Log.e(TAG, "failed to dump properties contents");
}
@@ -628,7 +628,7 @@
String[] configValues = context.getResources().getStringArray(
com.android.internal.R.array.config_gpsParameters);
for (String item : configValues) {
- Log.d(TAG, "GpsParamsResource: " + item);
+ if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item);
// We need to support "KEY =", but not "=VALUE".
String[] split = item.split("=");
if (split.length == 2) {
@@ -917,11 +917,13 @@
long certainty = mNtpTime.getCacheCertainty();
long now = System.currentTimeMillis();
- Log.d(TAG, "NTP server returned: "
- + time + " (" + new Date(time)
- + ") reference: " + timeReference
- + " certainty: " + certainty
- + " system time offset: " + (time - now));
+ if (DEBUG) {
+ Log.d(TAG, "NTP server returned: "
+ + time + " (" + new Date(time)
+ + ") reference: " + timeReference
+ + " certainty: " + certainty
+ + " system time offset: " + (time - now));
+ }
native_inject_time(time, timeReference, (int) certainty);
delay = NTP_INTERVAL;
@@ -1633,7 +1635,7 @@
if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
break;
default:
- Log.d(TAG, "Received Unknown AGPS status: " + status);
+ if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index abbad21..41077d0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6829,17 +6829,37 @@
// Extract pacakges only if profile-guided compilation is enabled because
// otherwise BackgroundDexOptService will not dexopt them later.
- if (mUseJitProfiles) {
- List<PackageParser.Package> pkgs;
- synchronized (mPackages) {
- pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
+ if (!mUseJitProfiles || !isUpgrade()) {
+ return;
+ }
+
+ List<PackageParser.Package> pkgs;
+ synchronized (mPackages) {
+ pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
+ }
+
+ int curr = 0;
+ int total = pkgs.size();
+ for (PackageParser.Package pkg : pkgs) {
+ curr++;
+
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Extracting app " + curr + " of " + total + ": " + pkg.packageName);
}
- for (PackageParser.Package pkg : pkgs) {
- if (PackageDexOptimizer.canOptimizePackage(pkg)) {
- performDexOpt(pkg.packageName, null /* instructionSet */,
- false /* useProfiles */, true /* extractOnly */, false /* force */);
+
+ if (!isFirstBoot()) {
+ try {
+ ActivityManagerNative.getDefault().showBootMessage(
+ mContext.getResources().getString(R.string.android_upgrading_apk,
+ curr, total), true);
+ } catch (RemoteException e) {
}
}
+
+ if (PackageDexOptimizer.canOptimizePackage(pkg)) {
+ performDexOpt(pkg.packageName, null /* instructionSet */,
+ false /* useProfiles */, true /* extractOnly */, false /* force */);
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d5ed04a..5490260 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2982,6 +2982,22 @@
}
@Override
+ public void onEphemeralUserStop(int userId) {
+ synchronized (mUsersLock) {
+ UserInfo userInfo = getUserInfoLU(userId);
+ if (userInfo != null && userInfo.isEphemeral()) {
+ // Do not allow switching back to the ephemeral user again as the user is going
+ // to be deleted.
+ userInfo.flags |= UserInfo.FLAG_DISABLED;
+ if (userInfo.isGuest()) {
+ // Indicate that the guest will be deleted after it stops.
+ userInfo.guestToRemove = true;
+ }
+ }
+ }
+ }
+
+ @Override
public UserInfo createUserEvenWhenDisallowed(String name, int flags) {
UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL);
// Keep this in sync with UserManager.createUser
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index a0f20aa..5ef518e 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -18,6 +18,8 @@
import com.android.internal.app.AlertController;
import com.android.internal.app.AlertController.AlertParams;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.R;
@@ -388,6 +390,8 @@
public void run() {
try {
// Take an "interactive" bugreport.
+ MetricsLogger.action(mContext,
+ MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE);
ActivityManagerNative.getDefault().requestBugReport(
ActivityManager.BUGREPORT_OPTION_INTERACTIVE);
} catch (RemoteException e) {
@@ -405,6 +409,7 @@
}
try {
// Take a "full" bugreport.
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
ActivityManagerNative.getDefault().requestBugReport(
ActivityManager.BUGREPORT_OPTION_FULL);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 7378bde..77db275 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -104,7 +104,7 @@
public class WallpaperManagerService extends IWallpaperManager.Stub {
static final String TAG = "WallpaperManagerService";
- static final boolean DEBUG = true;
+ static final boolean DEBUG = false;
final Object mLock = new Object();
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index fa5ee72..a81fba0 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -153,6 +153,13 @@
} else {
mClearProlongedAnimation = true;
}
+
+ // Since we are finally starting our animation, we don't need the logic anymore to prevent
+ // the app from showing again if we just moved between stacks. See
+ // {@link WindowState#notifyMovedInStack}.
+ for (int i = mAppToken.allAppWindows.size() - 1; i >= 0; i--) {
+ mAppToken.allAppWindows.get(i).resetJustMovedInStack();
+ }
}
public void setDummyAnimation() {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 25de75a..a589f89 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -369,7 +369,12 @@
if (DEBUG_TASK_POSITIONING) Slog.d(
TAG_WM, "startMovingTask: {" + startX + "," + startY + "}");
- return mService.startMovingTask(window, startX, startY);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return mService.startMovingTask(window, startX, startY);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
public void reportDropResult(IWindow window, boolean consumed) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 325005b..00690c4 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -247,7 +247,15 @@
mStack.removeTask(this);
}
stack.positionTask(this, position, showForAllUsers());
- setBounds(bounds, config);
+ resizeLocked(bounds, config, false /* force */);
+
+ for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
+ final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
+ for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+ final WindowState win = windows.get(winNdx);
+ win.notifyMovedInStack();
+ }
+ }
}
boolean removeAppToken(AppWindowToken wtoken) {
@@ -272,7 +280,7 @@
}
/** Set the task bounds. Passing in null sets the bounds to fullscreen. */
- int setBounds(Rect bounds, Configuration config) {
+ private int setBounds(Rect bounds, Configuration config) {
if (config == null) {
config = Configuration.EMPTY;
}
@@ -598,13 +606,21 @@
void resizeWindows() {
final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
- final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
+ final AppWindowToken atoken = mAppTokens.get(activityNdx);
+
+ // Some windows won't go through the resizing process, if they don't have a surface, so
+ // destroy all saved surfaces here.
+ atoken.destroySavedSurfaces();
+ final ArrayList<WindowState> windows = atoken.allAppWindows;
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState win = windows.get(winNdx);
if (win.mHasSurface && !resizingWindows.contains(win)) {
if (DEBUG_RESIZE) Slog.d(TAG, "resizeWindows: Resizing " + win);
resizingWindows.add(win);
}
+ if (win.isGoneForLayoutLw()) {
+ win.mResizedWhileGone = true;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9d97f17..f36585e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2760,6 +2760,9 @@
winAnimator.mReportSurfaceResized = false;
result |= WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED;
}
+ if (!win.isGoneForLayoutLw()) {
+ win.mResizedWhileGone = false;
+ }
outFrame.set(win.mCompatFrame);
outOverscanInsets.set(win.mOverscanInsets);
outContentInsets.set(win.mContentInsets);
@@ -10679,6 +10682,7 @@
@Override
public void waitForAllWindowsDrawn(Runnable callback, long timeout) {
+ boolean allWindowsDrawn = false;
synchronized (mWindowMap) {
mWaitingForDrawnCallback = callback;
final WindowList windows = getDefaultWindowListLocked();
@@ -10699,13 +10703,16 @@
}
}
mWindowPlacerLocked.requestTraversal();
+ mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
+ if (mWaitingForDrawn.isEmpty()) {
+ allWindowsDrawn = true;
+ } else {
+ mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);
+ checkDrawnWindowsLocked();
+ }
}
- mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
- if (mWaitingForDrawn.isEmpty()) {
+ if (allWindowsDrawn) {
callback.run();
- } else {
- mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);
- checkDrawnWindowsLocked();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f30c8d3..9dcb404 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -448,6 +448,16 @@
final private Rect mTmpRect = new Rect();
+ /**
+ * See {@link #notifyMovedInStack}.
+ */
+ private boolean mJustMovedInStack;
+
+ /**
+ * Whether the window was resized by us while it was gone for layout.
+ */
+ boolean mResizedWhileGone = false;
+
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, final DisplayContent displayContent) {
@@ -1235,7 +1245,7 @@
return mViewVisibility == View.GONE
|| !mRelayoutCalled
|| (atoken == null && mRootToken.hidden)
- || (atoken != null && (atoken.hiddenRequested || atoken.hidden))
+ || (atoken != null && atoken.hiddenRequested)
|| mAttachedHidden
|| (mAnimatingExit && !isAnimatingLw())
|| mDestroying;
@@ -1374,6 +1384,39 @@
}
}
+ /**
+ * Notifies this window that the corresponding task has just moved in the stack.
+ * <p>
+ * This is used to fix the following: If we moved in the stack, and if the last clip rect was
+ * empty, meaning that our task was completely offscreen, we need to keep it invisible because
+ * the actual app transition that updates the visibility is delayed by a few transactions.
+ * Instead of messing around with the ordering and timing how transitions and transactions are
+ * executed, we introduce this little hack which prevents this window of getting visible again
+ * with the wrong bounds until the app transitions has started.
+ * <p>
+ * This method notifies the window about that we just moved in the stack so we can apply this
+ * logic in {@link WindowStateAnimator#updateSurfaceWindowCrop}
+ */
+ void notifyMovedInStack() {
+ mJustMovedInStack = true;
+ }
+
+ /**
+ * See {@link #notifyMovedInStack}.
+ *
+ * @return Whether we just got moved in the corresponding stack.
+ */
+ boolean hasJustMovedInStack() {
+ return mJustMovedInStack;
+ }
+
+ /**
+ * Resets that we just moved in the corresponding stack. See {@link #notifyMovedInStack}.
+ */
+ void resetJustMovedInStack() {
+ mJustMovedInStack = false;
+ }
+
private final class DeadWindowEventReceiver extends InputEventReceiver {
DeadWindowEventReceiver(InputChannel inputChannel) {
super(inputChannel, mService.mH.getLooper());
@@ -1836,6 +1879,12 @@
return false;
}
+ if (mResizedWhileGone) {
+ // Somebody resized our window while we were gone for layout, which means that the
+ // client got an old size, so we have an outdated surface here.
+ return false;
+ }
+
if (DEBUG_DISABLE_SAVING_SURFACES) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 0828417..2d8a4c9 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1191,6 +1191,11 @@
w.transformFromScreenToSurfaceSpace(clipRect);
+ // See {@link WindowState#notifyMovedInStack} for why this is necessary.
+ if (w.hasJustMovedInStack() && mLastClipRect.isEmpty() && !clipRect.isEmpty()) {
+ clipRect.setEmpty();
+ }
+
if (!clipRect.equals(mLastClipRect)) {
mLastClipRect.set(clipRect);
mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 93164de..0db6f3a 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -62,7 +62,7 @@
// However, we need to somehow handle the situation where the cropping would completely hide
// the window. We achieve this by explicitly hiding the surface and not letting it be shown.
private boolean mHiddenForCrop = false;
-
+ private boolean mHiddenForOtherReasons = false;
private final String title;
public WindowSurfaceController(SurfaceSession s,
@@ -95,6 +95,11 @@
void hideInTransaction(String reason) {
if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
+ mHiddenForOtherReasons = true;
+ updateVisibility();
+ }
+
+ private void hideSurface() {
if (mSurfaceControl != null) {
mSurfaceShown = false;
try {
@@ -152,9 +157,10 @@
if (clipRect.width() > 0 && clipRect.height() > 0) {
mSurfaceControl.setWindowCrop(clipRect);
mHiddenForCrop = false;
+ updateVisibility();
} else {
- hideInTransaction("setCrop");
mHiddenForCrop = true;
+ updateVisibility();
}
} catch (RuntimeException e) {
Slog.w(TAG, "Error setting crop surface of " + this
@@ -317,11 +323,26 @@
"SHOW (performLayout)", null);
if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + this
+ " during relayout");
+ mHiddenForOtherReasons = false;
+ return updateVisibility();
+ }
- if (mHiddenForCrop) {
+ private boolean updateVisibility() {
+ if (mHiddenForCrop || mHiddenForOtherReasons) {
+ if (mSurfaceShown) {
+ hideSurface();
+ }
return false;
+ } else {
+ if (!mSurfaceShown) {
+ return showSurface();
+ } else {
+ return true;
+ }
}
+ }
+ private boolean showSurface() {
try {
mSurfaceShown = true;
mSurfaceControl.show();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 33225eb..158d67e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -6743,57 +6743,6 @@
}
}
- @Override
- public UserHandle createUser(ComponentName who, String name) {
- Preconditions.checkNotNull(who, "ComponentName is null");
- synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
-
- long id = mInjector.binderClearCallingIdentity();
- try {
- UserInfo userInfo = mUserManager.createUser(name, 0 /* flags */);
- if (userInfo != null) {
- return userInfo.getUserHandle();
- }
- return null;
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
- }
- }
- }
-
- @Override
- public UserHandle createAndInitializeUser(ComponentName who, String name,
- String ownerName, ComponentName profileOwnerComponent, Bundle adminExtras) {
- UserHandle user = createUser(who, name);
- if (user == null) {
- return null;
- }
- long id = mInjector.binderClearCallingIdentity();
- try {
- String profileOwnerPkg = profileOwnerComponent.getPackageName();
-
- final int userHandle = user.getIdentifier();
- try {
- // Install the profile owner if not present.
- if (!mIPackageManager.isPackageAvailable(profileOwnerPkg, userHandle)) {
- mIPackageManager.installExistingPackageAsUser(profileOwnerPkg, userHandle);
- }
-
- // Start user in background.
- mInjector.getIActivityManager().startUserInBackground(userHandle);
- } catch (RemoteException e) {
- Slog.e(LOG_TAG, "Failed to make remote calls for configureUser", e);
- }
-
- setActiveAdmin(profileOwnerComponent, true, userHandle, adminExtras);
- setProfileOwner(profileOwnerComponent, ownerName, userHandle);
- return user;
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
- }
- }
-
private void sendAdminEnabledBroadcastLocked(int userHandle) {
DevicePolicyData policyData = getUserData(userHandle);
if (policyData.mAdminBroadcastPending) {
@@ -7785,9 +7734,11 @@
if (mUserSetupComplete.equals(uri)) {
updateUserSetupComplete();
} else if (mDeviceProvisioned.equals(uri)) {
- // Set PROPERTY_DEVICE_OWNER_PRESENT, for the SUW case where setting the property
- // is delayed until device is marked as provisioned.
- setDeviceOwnerSystemPropertyLocked();
+ synchronized (DevicePolicyManagerService.this) {
+ // Set PROPERTY_DEVICE_OWNER_PRESENT, for the SUW case where setting the property
+ // is delayed until device is marked as provisioned.
+ setDeviceOwnerSystemPropertyLocked();
+ }
}
}
}
@@ -8484,7 +8435,7 @@
return false;
}
- private void disableDeviceLoggingIfNotCompliant() {
+ private synchronized void disableDeviceLoggingIfNotCompliant() {
if (!isDeviceOwnerManagedSingleUserDevice()) {
mInjector.securityLogSetLoggingEnabledProperty(false);
Slog.w(LOG_TAG, "Device logging turned off as it's no longer a single user device.");
@@ -8497,6 +8448,9 @@
ensureDeviceOwnerManagingSingleUser(admin);
synchronized (this) {
+ if (enabled == mInjector.securityLogGetLoggingEnabledProperty()) {
+ return;
+ }
mInjector.securityLogSetLoggingEnabledProperty(enabled);
if (enabled) {
mSecurityLogMonitor.start();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
index f2d6180..cacc671 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
@@ -28,6 +28,8 @@
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
import android.os.Process;
@@ -42,6 +44,8 @@
class SecurityLogMonitor implements Runnable {
private final DevicePolicyManagerService mService;
+ private final Lock mLock = new ReentrantLock();
+
SecurityLogMonitor(DevicePolicyManagerService service) {
mService = service;
}
@@ -68,36 +72,50 @@
*/
private static final long POLLING_INTERVAL_MILLISECONDS = TimeUnit.MINUTES.toMillis(1);
- @GuardedBy("this")
+ @GuardedBy("mLock")
private Thread mMonitorThread = null;
- @GuardedBy("this")
+ @GuardedBy("mLock")
private ArrayList<SecurityEvent> mPendingLogs = new ArrayList<SecurityEvent>();
- @GuardedBy("this")
+ @GuardedBy("mLock")
private boolean mAllowedToRetrieve = false;
// When DO will be allowed to retrieves the log, in milliseconds.
- @GuardedBy("this")
+ @GuardedBy("mLock")
private long mNextAllowedRetrivalTimeMillis = -1;
- synchronized void start() {
- if (mMonitorThread == null) {
- mPendingLogs = new ArrayList<SecurityEvent>();
- mAllowedToRetrieve = false;
- mNextAllowedRetrivalTimeMillis = -1;
+ void start() {
+ mLock.lock();
+ try {
+ if (mMonitorThread == null) {
+ mPendingLogs = new ArrayList<SecurityEvent>();
+ mAllowedToRetrieve = false;
+ mNextAllowedRetrivalTimeMillis = -1;
- mMonitorThread = new Thread(this);
- mMonitorThread.start();
+ mMonitorThread = new Thread(this);
+ mMonitorThread.start();
+ }
+ } finally {
+ mLock.unlock();
}
}
- synchronized void stop() {
- if (mMonitorThread != null) {
- mMonitorThread.interrupt();
- try {
- mMonitorThread.join(TimeUnit.SECONDS.toMillis(5));
- } catch (InterruptedException e) {
- Log.e(TAG, "Interrupted while waiting for thread to stop", e);
+ void stop() {
+ mLock.lock();
+ try {
+ if (mMonitorThread != null) {
+ mMonitorThread.interrupt();
+ try {
+ mMonitorThread.join(TimeUnit.SECONDS.toMillis(5));
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted while waiting for thread to stop", e);
+ }
+ // Reset state and clear buffer
+ mPendingLogs = new ArrayList<SecurityEvent>();
+ mAllowedToRetrieve = false;
+ mNextAllowedRetrivalTimeMillis = -1;
+ mMonitorThread = null;
}
- mMonitorThread = null;
+ } finally {
+ mLock.unlock();
}
}
@@ -105,16 +123,21 @@
* Returns the new batch of logs since the last call to this method. Returns null if
* rate limit is exceeded.
*/
- synchronized List<SecurityEvent> retrieveLogs() {
- if (mAllowedToRetrieve) {
- mAllowedToRetrieve = false;
- mNextAllowedRetrivalTimeMillis = System.currentTimeMillis()
- + RATE_LIMIT_INTERVAL_MILLISECONDS;
- List<SecurityEvent> result = mPendingLogs;
- mPendingLogs = new ArrayList<SecurityEvent>();
- return result;
- } else {
- return null;
+ List<SecurityEvent> retrieveLogs() {
+ mLock.lock();
+ try {
+ if (mAllowedToRetrieve) {
+ mAllowedToRetrieve = false;
+ mNextAllowedRetrivalTimeMillis = System.currentTimeMillis()
+ + RATE_LIMIT_INTERVAL_MILLISECONDS;
+ List<SecurityEvent> result = mPendingLogs;
+ mPendingLogs = new ArrayList<SecurityEvent>();
+ return result;
+ } else {
+ return null;
+ }
+ } finally {
+ mLock.unlock();
}
}
@@ -141,7 +164,8 @@
}
if (!logs.isEmpty()) {
if (DEBUG) Slog.d(TAG, "processing new logs");
- synchronized (this) {
+ mLock.lockInterruptibly();
+ try {
mPendingLogs.addAll(logs);
if (mPendingLogs.size() > BUFFER_ENTRIES_MAXIMUM_LEVEL) {
// Truncate buffer down to half of BUFFER_ENTRIES_MAXIMUM_LEVEL
@@ -149,6 +173,8 @@
mPendingLogs.size() - (BUFFER_ENTRIES_MAXIMUM_LEVEL / 2),
mPendingLogs.size()));
}
+ } finally {
+ mLock.unlock();
}
lastLogTimestampNanos = logs.get(logs.size() - 1).getTimeNanos();
logs.clear();
@@ -163,18 +189,13 @@
}
}
if (DEBUG) Slog.d(TAG, "MonitorThread exit.");
- synchronized (this) {
- // Reset state and clear buffer
- mPendingLogs = new ArrayList<SecurityEvent>();
- mAllowedToRetrieve = false;
- mNextAllowedRetrivalTimeMillis = -1;
- }
}
- private void notifyDeviceOwnerIfNeeded() {
+ private void notifyDeviceOwnerIfNeeded() throws InterruptedException {
boolean shouldNotifyDO = false;
boolean allowToRetrieveNow = false;
- synchronized (this) {
+ mLock.lockInterruptibly();
+ try {
int logSize = mPendingLogs.size();
if (logSize >= BUFFER_ENTRIES_NOTIFICATION_LEVEL) {
// Allow DO to retrieve logs if too many pending logs
@@ -188,6 +209,8 @@
}
shouldNotifyDO = (!mAllowedToRetrieve) && allowToRetrieveNow;
mAllowedToRetrieve = allowToRetrieveNow;
+ } finally {
+ mLock.unlock();
}
if (shouldNotifyDO) {
if (DEBUG) Slog.d(TAG, "notify DO");
@@ -195,4 +218,4 @@
null);
}
}
-}
\ No newline at end of file
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c75f98f..d08f68a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -59,6 +59,7 @@
import com.android.server.audio.AudioService;
import com.android.server.camera.CameraService;
import com.android.server.clipboard.ClipboardService;
+import com.android.server.connectivity.MetricsLoggerService;
import com.android.server.content.ContentService;
import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
@@ -602,6 +603,10 @@
} else {
mSystemServiceManager.startService(BluetoothService.class);
}
+
+ traceBeginAndSlog("ConnectivityMetricsLoggerService");
+ mSystemServiceManager.startService(MetricsLoggerService.class);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
} catch (RuntimeException e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service", e);
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index fa7a59d..4547c6a 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -297,6 +297,24 @@
*/
public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
+ /**
+ * Connection event used to inform Telecom that it should play the on hold tone. This is used
+ * to play a tone when the peer puts the current call on hold. Sent to Telecom via
+ * {@link #sendConnectionEvent(String)}.
+ * @hide
+ */
+ public static final String EVENT_ON_HOLD_TONE_START =
+ "android.telecom.event.ON_HOLD_TONE_START";
+
+ /**
+ * Connection event used to inform Telecom that it should stop the on hold tone. This is used
+ * to stop a tone when the peer puts the current call on hold. Sent to Telecom via
+ * {@link #sendConnectionEvent(String)}.
+ * @hide
+ */
+ public static final String EVENT_ON_HOLD_TONE_END =
+ "android.telecom.event.ON_HOLD_TONE_END";
+
// Flag controlling whether PII is emitted into the logs
private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
@@ -447,6 +465,8 @@
public void onConferenceStarted() {}
public void onConferenceMergeFailed(Connection c) {}
public void onExtrasChanged(Connection c, Bundle extras) {}
+ /** @hide */
+ public void onConnectionEvent(Connection c, String event) {}
}
/**
@@ -1986,4 +2006,16 @@
l.onConferenceStarted();
}
}
+
+ /**
+ * Sends a connection event to Telecom.
+ *
+ * @param event The connection event.
+ * @hide
+ */
+ protected void sendConnectionEvent(String event) {
+ for (Listener l : mListeners) {
+ l.onConnectionEvent(this, event);
+ }
+ }
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index b4a7ce0..56d9491 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -613,6 +613,14 @@
mAdapter.setExtras(id, extras);
}
}
+
+ @Override
+ public void onConnectionEvent(Connection connection, String event) {
+ String id = mIdByConnection.get(connection);
+ if (id != null) {
+ mAdapter.onConnectionEvent(id, event);
+ }
+ }
};
/** {@inheritDoc} */
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index 4562514..30fc5ad 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -412,4 +412,20 @@
}
}
}
+
+ /**
+ * Informs Telecom of a connection level event.
+ *
+ * @param callId The unique ID of the call.
+ * @param event The event.
+ */
+ void onConnectionEvent(String callId, String event) {
+ Log.v(this, "onConnectionEvent: %s", event);
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ adapter.onConnectionEvent(callId, event);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
}
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index 293dc11..a790914 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -62,6 +62,7 @@
private static final int MSG_ON_POST_DIAL_CHAR = 22;
private static final int MSG_SET_CONFERENCE_MERGE_FAILED = 23;
private static final int MSG_SET_EXTRAS = 24;
+ private static final int MSG_ON_CONNECTION_EVENT = 25;
private final IConnectionServiceAdapter mDelegate;
@@ -240,6 +241,15 @@
args.recycle();
}
}
+
+ case MSG_ON_CONNECTION_EVENT: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ mDelegate.onConnectionEvent((String) args.arg1, (String) args.arg2);
+ } finally {
+ args.recycle();
+ }
+ }
}
}
};
@@ -419,6 +429,14 @@
args.arg2 = extras;
mHandler.obtainMessage(MSG_SET_EXTRAS, args).sendToTarget();
}
+
+ @Override
+ public final void onConnectionEvent(String connectionId, String event) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = connectionId;
+ args.arg2 = event;
+ mHandler.obtainMessage(MSG_ON_CONNECTION_EVENT, args).sendToTarget();
+ }
};
public ConnectionServiceAdapterServant(IConnectionServiceAdapter delegate) {
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index f960959..0185808 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -209,6 +209,15 @@
* @param extras The extras containing other information associated with the connection.
*/
public void onExtrasChanged(RemoteConnection connection, @Nullable Bundle extras) {}
+
+ /**
+ * Handles a connection event propagated to this {@link RemoteConnection}.
+ *
+ * @param connection The {@code RemoteConnection} invoking this method.
+ * @param event The connection event.
+ * @hide
+ */
+ public void onConnectionEvent(RemoteConnection connection, String event) {}
}
/**
@@ -1291,6 +1300,20 @@
}
}
+ /** @hide */
+ void onConnectionEvent(final String event) {
+ for (CallbackRecord record : mCallbackRecords) {
+ final RemoteConnection connection = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onConnectionEvent(connection, event);
+ }
+ });
+ }
+ }
+
/**
* Create a RemoteConnection represents a failure, and which will be in
* {@link Connection#STATE_DISCONNECTED}. Attempting to use it for anything will almost
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index dc0de0c..b85382f 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -330,6 +330,13 @@
.setExtras(extras);
}
}
+
+ @Override
+ public void onConnectionEvent(String callId, String event) {
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "onConnectionEvent").onConnectionEvent(event);
+ }
+ }
};
private final ConnectionServiceAdapterServant mServant =
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index 7647444..569c244 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -86,4 +86,6 @@
void addExistingConnection(String callId, in ParcelableConnection connection);
void setExtras(String callId, in Bundle extras);
+
+ void onConnectionEvent(String callId, String event);
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index 746ef36..7412bc2 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -284,9 +284,9 @@
}
@LayoutlibDelegate
- /*package*/ static boolean nAddFontWeightStyle(long nativeFamily,
- ByteBuffer buffer, final List<FontListParser.Axis> axes,
- final int weight, final boolean isItalic) {
+ /*package*/ static boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font,
+ int ttcIndex, List<FontListParser.Axis> listOfAxis,
+ int weight, boolean isItalic) {
assert false : "The only client of this method has been overriden.";
return false;
}
diff --git a/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java b/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
index 17cc29f..f5cad13 100644
--- a/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
+++ b/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
@@ -16,8 +16,8 @@
package android.net.wifi;
-import android.os.Parcelable;
import android.os.Parcel;
+import android.os.Parcelable;
/**
* A class representing wifi wake reason accounting.
@@ -52,6 +52,8 @@
public int ipv4RxMulticast;
public int ipv6Multicast;
public int otherRxMulticast;
+ public int[] cmdEventWakeCntArray;
+ public int[] driverFWLocalWakeCntArray;
/* {@hide} */
public WifiWakeReasonAndCounts () {
@@ -78,6 +80,13 @@
sb.append(" ipv4RxMulticast ").append(ipv4RxMulticast);
sb.append(" ipv6Multicast ").append(ipv6Multicast);
sb.append(" otherRxMulticast ").append(otherRxMulticast);
+ for (int i = 0; i < cmdEventWakeCntArray.length; i++) {
+ sb.append(" cmdEventWakeCntArray[" + i + "] " + cmdEventWakeCntArray[i]);
+ }
+ for (int i = 0; i < driverFWLocalWakeCntArray.length; i++) {
+ sb.append(" driverFWLocalWakeCntArray[" + i + "] " + driverFWLocalWakeCntArray[i]);
+ }
+
return sb.toString();
}
@@ -111,6 +120,8 @@
dest.writeInt(ipv4RxMulticast);
dest.writeInt(ipv6Multicast);
dest.writeInt(otherRxMulticast);
+ dest.writeIntArray(cmdEventWakeCntArray);
+ dest.writeIntArray(driverFWLocalWakeCntArray);
}
/* Implement the Parcelable interface
@@ -137,6 +148,8 @@
counts.ipv4RxMulticast = in.readInt();
counts.ipv6Multicast = in.readInt();
counts.otherRxMulticast = in.readInt();
+ in.readIntArray(counts.cmdEventWakeCntArray);
+ in.readIntArray(counts.driverFWLocalWakeCntArray);
return counts;
}
/* Implement the Parcelable interface