diff options
727 files changed, 11396 insertions, 3456 deletions
diff --git a/Android.bp b/Android.bp index 7bdedc79943d..9602941adc1c 100644 --- a/Android.bp +++ b/Android.bp @@ -602,6 +602,7 @@ java_defaults { "telephony/java/com/android/internal/telephony/IOnSubscriptionsChangedListener.aidl", "telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl", "telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl", + "telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl", "telephony/java/com/android/internal/telephony/ISms.aidl", "telephony/java/com/android/internal/telephony/ISub.aidl", "telephony/java/com/android/internal/telephony/IOns.aidl", @@ -741,7 +742,6 @@ java_defaults { static_libs: [ "apex_aidl_interface-java", - "networkstack-aidl-interfaces-java", "framework-protos", "game-driver-protos", "mediaplayer2-protos", @@ -804,6 +804,7 @@ filegroup { srcs: [ "core/java/android/os/IStatsCompanionService.aidl", "core/java/android/os/IStatsManager.aidl", + "core/java/android/os/IStatsPullerCallback.aidl", ], } @@ -1187,52 +1188,6 @@ packages_to_document = [ "org/apache/http/params", ] -// The since flag (-since N.xml API_LEVEL) is used to add API Level information -// to the reference documentation. Must be in order of oldest to newest. -// -// Conscrypt (com.android.org.conscrypt) is an implementation detail and should -// not be referenced in the documentation. -framework_docs_args = "-android -manifest $(location core/res/AndroidManifest.xml) " + - "-hidePackage com.android.internal " + - "-hidePackage com.android.internal.util " + - "-hidePackage com.android.okhttp " + - "-hidePackage com.android.org.conscrypt " + - "-hidePackage com.android.server " + - "-since $(location 1/public/api/android.xml) 1 " + - "-since $(location 2/public/api/android.xml) 2 " + - "-since $(location 3/public/api/android.xml) 3 " + - "-since $(location 4/public/api/android.xml) 4 " + - "-since $(location 5/public/api/android.xml) 5 " + - "-since $(location 6/public/api/android.xml) 6 " + - "-since $(location 7/public/api/android.xml) 7 " + - "-since $(location 8/public/api/android.xml) 8 " + - "-since $(location 9/public/api/android.xml) 9 " + - "-since $(location 10/public/api/android.xml) 10 " + - "-since $(location 11/public/api/android.xml) 11 " + - "-since $(location 12/public/api/android.xml) 12 " + - "-since $(location 13/public/api/android.xml) 13 " + - "-since $(location 14/public/api/android.txt) 14 " + - "-since $(location 15/public/api/android.txt) 15 " + - "-since $(location 16/public/api/android.txt) 16 " + - "-since $(location 17/public/api/android.txt) 17 " + - "-since $(location 18/public/api/android.txt) 18 " + - "-since $(location 19/public/api/android.txt) 19 " + - "-since $(location 20/public/api/android.txt) 20 " + - "-since $(location 21/public/api/android.txt) 21 " + - "-since $(location 22/public/api/android.txt) 22 " + - "-since $(location 23/public/api/android.txt) 23 " + - "-since $(location 24/public/api/android.txt) 24 " + - "-since $(location 25/public/api/android.txt) 25 " + - "-since $(location 26/public/api/android.txt) 26 " + - "-since $(location 27/public/api/android.txt) 27 " + - "-since $(location 28/public/api/android.txt) 28 " + - "-since $(location api/current.txt) Q " + - "-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " + - "-overview $(location core/java/overview.html) " + - // Federate Support Library references against local API file. - "-federate SupportLib https://developer.android.com " + - "-federationapi SupportLib $(location current/support-api.txt) " - framework_docs_only_args = " -android -manifest $(location core/res/AndroidManifest.xml) " + "-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " + "-overview $(location core/java/overview.html) " + diff --git a/Android.mk b/Android.mk index 9c65948f4838..9a91dd1c491a 100644 --- a/Android.mk +++ b/Android.mk @@ -72,6 +72,9 @@ $(OUT_DOCS)/offline-sdk-timestamp: $(OUT_DOCS)/offline-sdk-docs-docs.zip $(hide) mkdir -p $(OUT_DOCS)/offline-sdk ( unzip -qo $< -d $(OUT_DOCS)/offline-sdk && touch -f $@ ) || exit 1 +.PHONY: docs offline-sdk-docs +docs offline-sdk-docs: $(OUT_DOCS)/offline-sdk-timestamp + # Run this for checkbuild checkbuild: doc-comment-check-docs # Check comment when you are updating the API diff --git a/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java b/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java index ec46a75bd807..c506aec624d1 100644 --- a/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java +++ b/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java @@ -64,7 +64,7 @@ public class TextClassifierPerfTest { Context context = InstrumentationRegistry.getTargetContext(); TextClassificationManager textClassificationManager = context.getSystemService(TextClassificationManager.class); - mTextClassifier = textClassificationManager.getTextClassifier(); + mTextClassifier = textClassificationManager.getLocalTextClassifier(); } @Test diff --git a/api/TEST_MAPPING b/api/TEST_MAPPING new file mode 100644 index 000000000000..8a676e994081 --- /dev/null +++ b/api/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "CtsCurrentApiSignatureTestCases" + } + ] +} diff --git a/api/current.txt b/api/current.txt index abab90182b01..6f2751d58dbe 100644 --- a/api/current.txt +++ b/api/current.txt @@ -80,7 +80,6 @@ package android { field public static final String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE"; field public static final String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; field public static final String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED"; - field public static final String GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY = "android.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY"; field public static final String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE"; field @Deprecated public static final String GET_TASKS = "android.permission.GET_TASKS"; field public static final String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH"; @@ -131,6 +130,7 @@ package android { field public static final String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES"; field public static final String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; field public static final String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES"; + field public static final String REQUEST_SCREEN_LOCK_COMPLEXITY = "android.permission.REQUEST_SCREEN_LOCK_COMPLEXITY"; field @Deprecated public static final String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES"; field public static final String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE"; field public static final String SEND_SMS = "android.permission.SEND_SMS"; @@ -6646,7 +6646,7 @@ package android.app.admin { method @Nullable public CharSequence getOrganizationName(@NonNull android.content.ComponentName); method public java.util.List<android.telephony.data.ApnSetting> getOverrideApns(@NonNull android.content.ComponentName); method @NonNull public android.app.admin.DevicePolicyManager getParentProfileInstance(@NonNull android.content.ComponentName); - method @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY) public int getPasswordComplexity(); + method @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY) public int getPasswordComplexity(); method public long getPasswordExpiration(@Nullable android.content.ComponentName); method public long getPasswordExpirationTimeout(@Nullable android.content.ComponentName); method public int getPasswordHistoryLength(@Nullable android.content.ComponentName); @@ -6840,7 +6840,7 @@ package android.app.admin { field public static final String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION"; field public static final String EXTRA_DELEGATION_SCOPES = "android.app.extra.DELEGATION_SCOPES"; field public static final String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN"; - field @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY) public static final String EXTRA_PASSWORD_COMPLEXITY = "android.app.extra.PASSWORD_COMPLEXITY"; + field @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY) public static final String EXTRA_PASSWORD_COMPLEXITY = "android.app.extra.PASSWORD_COMPLEXITY"; field public static final String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE"; field public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE"; field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME"; @@ -11482,7 +11482,6 @@ package android.content.pm { method public void setOriginatingUri(@Nullable android.net.Uri); method public void setReferrerUri(@Nullable android.net.Uri); method public void setSize(long); - method public void setStaged(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionParams> CREATOR; field public static final int MODE_FULL_INSTALL = 1; // 0x1 @@ -14191,13 +14190,16 @@ package android.graphics { field public static final int YV12 = 842094169; // 0x32315659 } - public final class Insets { + public final class Insets implements android.os.Parcelable { method @NonNull public static android.graphics.Insets add(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets); + method public int describeContents(); method @NonNull public static android.graphics.Insets max(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets); method @NonNull public static android.graphics.Insets min(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets); method @NonNull public static android.graphics.Insets of(int, int, int, int); method @NonNull public static android.graphics.Insets of(@Nullable android.graphics.Rect); method @NonNull public static android.graphics.Insets subtract(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.graphics.Insets> CREATOR; field public static final android.graphics.Insets NONE; field public final int bottom; field public final int left; @@ -15406,28 +15408,38 @@ package android.graphics.drawable { method public float getGradientCenterY(); method public float getGradientRadius(); method public int getGradientType(); + method public int getInnerRadius(); + method public float getInnerRadiusRatio(); method public int getOpacity(); method public android.graphics.drawable.GradientDrawable.Orientation getOrientation(); method public int getShape(); + method public int getThickness(); + method public float getThicknessRatio(); method public boolean getUseLevel(); method public void setAlpha(int); method public void setColor(@ColorInt int); method public void setColor(@Nullable android.content.res.ColorStateList); method public void setColorFilter(@Nullable android.graphics.ColorFilter); method public void setColors(@ColorInt int[]); + method public void setColors(@ColorInt int[], @Nullable float[]); method public void setCornerRadii(@Nullable float[]); method public void setCornerRadius(float); method public void setDither(boolean); method public void setGradientCenter(float, float); method public void setGradientRadius(float); method public void setGradientType(int); + method public void setInnerRadius(int); + method public void setInnerRadiusRatio(float); method public void setOrientation(android.graphics.drawable.GradientDrawable.Orientation); + method public void setPadding(int, int, int, int); method public void setShape(int); method public void setSize(int, int); method public void setStroke(int, @ColorInt int); method public void setStroke(int, android.content.res.ColorStateList); method public void setStroke(int, @ColorInt int, float, float); method public void setStroke(int, android.content.res.ColorStateList, float, float); + method public void setThickness(int); + method public void setThicknessRatio(float); method public void setUseLevel(boolean); field public static final int LINE = 2; // 0x2 field public static final int LINEAR_GRADIENT = 0; // 0x0 @@ -16489,6 +16501,7 @@ package android.hardware.biometrics { field public static final int BIOMETRIC_ERROR_LOCKOUT = 7; // 0x7 field public static final int BIOMETRIC_ERROR_LOCKOUT_PERMANENT = 9; // 0x9 field public static final int BIOMETRIC_ERROR_NO_BIOMETRICS = 11; // 0xb + field public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14; // 0xe field public static final int BIOMETRIC_ERROR_NO_SPACE = 4; // 0x4 field public static final int BIOMETRIC_ERROR_TIMEOUT = 3; // 0x3 field public static final int BIOMETRIC_ERROR_UNABLE_TO_PROCESS = 2; // 0x2 @@ -16511,8 +16524,8 @@ package android.hardware.biometrics { public static class BiometricPrompt.Builder { ctor public BiometricPrompt.Builder(android.content.Context); method public android.hardware.biometrics.BiometricPrompt build(); + method public android.hardware.biometrics.BiometricPrompt.Builder setAllowDeviceCredential(boolean); method public android.hardware.biometrics.BiometricPrompt.Builder setDescription(@NonNull CharSequence); - method public android.hardware.biometrics.BiometricPrompt.Builder setEnableFallback(boolean); method public android.hardware.biometrics.BiometricPrompt.Builder setNegativeButton(@NonNull CharSequence, @NonNull java.util.concurrent.Executor, @NonNull android.content.DialogInterface.OnClickListener); method public android.hardware.biometrics.BiometricPrompt.Builder setRequireConfirmation(boolean); method public android.hardware.biometrics.BiometricPrompt.Builder setSubtitle(@NonNull CharSequence); @@ -24535,7 +24548,9 @@ package android.media { } public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint { + ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int); method public boolean covers(@NonNull android.media.MediaFormat); + method public boolean covers(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint); field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_100; field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_120; field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_200; @@ -24570,8 +24585,8 @@ package android.media { field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_50; field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_60; field public final int frameRate; - field public final int height; - field public final int width; + field public final long macroBlockRate; + field public final int macroBlocks; } public final class MediaCodecList { @@ -30105,10 +30120,14 @@ package android.net.wifi.aware { method public void onIdentityChanged(byte[]); } - public final class PeerHandle implements android.os.Parcelable { + public final class ParcelablePeerHandle extends android.net.wifi.aware.PeerHandle implements android.os.Parcelable { + ctor public ParcelablePeerHandle(android.net.wifi.aware.PeerHandle); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.net.wifi.aware.PeerHandle> CREATOR; + field public static final android.os.Parcelable.Creator<android.net.wifi.aware.ParcelablePeerHandle> CREATOR; + } + + public class PeerHandle { } public final class PublishConfig implements android.os.Parcelable { @@ -38340,11 +38359,7 @@ package android.provider { method @NonNull public static String getVolumeName(@NonNull android.net.Uri); method @NonNull public static android.provider.MediaStore.PendingSession openPending(@NonNull android.content.Context, @NonNull android.net.Uri); method @NonNull public static android.net.Uri setIncludePending(@NonNull android.net.Uri); - method @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri); method @NonNull public static android.net.Uri setRequireOriginal(@NonNull android.net.Uri); - method public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri); - method public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri, long); - method public static void untrash(@NonNull android.content.Context, @NonNull android.net.Uri); field public static final String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE"; field public static final String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE"; field public static final String ACTION_REVIEW = "android.provider.action.REVIEW"; @@ -38615,14 +38630,14 @@ package android.provider { public static interface MediaStore.MediaColumns extends android.provider.BaseColumns { field @Deprecated public static final String DATA = "_data"; field public static final String DATE_ADDED = "date_added"; - field public static final String DATE_EXPIRES = "date_expires"; field public static final String DATE_MODIFIED = "date_modified"; field public static final String DISPLAY_NAME = "_display_name"; - field public static final String HASH = "_hash"; + field public static final String DOCUMENT_ID = "document_id"; field public static final String HEIGHT = "height"; + field public static final String INSTANCE_ID = "instance_id"; field public static final String IS_PENDING = "is_pending"; - field public static final String IS_TRASHED = "is_trashed"; field public static final String MIME_TYPE = "mime_type"; + field public static final String ORIGINAL_DOCUMENT_ID = "original_document_id"; field public static final String OWNER_PACKAGE_NAME = "owner_package_name"; field public static final String PRIMARY_DIRECTORY = "primary_directory"; field public static final String SECONDARY_DIRECTORY = "secondary_directory"; @@ -45227,6 +45242,9 @@ package android.telephony { field public static final int PHONE_TYPE_GSM = 1; // 0x1 field public static final int PHONE_TYPE_NONE = 0; // 0x0 field public static final int PHONE_TYPE_SIP = 3; // 0x3 + field public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2; // 0x2 + field public static final int SET_OPPORTUNISTIC_SUB_SUCCESS = 0; // 0x0 + field public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1; // 0x1 field public static final int SIM_STATE_ABSENT = 1; // 0x1 field public static final int SIM_STATE_CARD_IO_ERROR = 8; // 0x8 field public static final int SIM_STATE_CARD_RESTRICTED = 9; // 0x9 @@ -45591,6 +45609,483 @@ package android.telephony.gsm { } +package android.telephony.ims { + + public class Rcs1To1Thread extends android.telephony.ims.RcsThread { + method @WorkerThread public long getFallbackThreadId() throws android.telephony.ims.RcsMessageStoreException; + method @NonNull @WorkerThread public android.telephony.ims.RcsParticipant getRecipient() throws android.telephony.ims.RcsMessageStoreException; + method public boolean isGroup(); + method @WorkerThread public void setFallbackThreadId(long) throws android.telephony.ims.RcsMessageStoreException; + } + + public abstract class RcsEvent { + ctor protected RcsEvent(long); + method public long getTimestamp(); + } + + public final class RcsEventQueryParams implements android.os.Parcelable { + method public int describeContents(); + method @android.telephony.ims.RcsEventQueryParams.EventType public int getEventType(); + method public int getLimit(); + method public boolean getSortDirection(); + method public int getSortingProperty(); + method public void writeToParcel(android.os.Parcel, int); + field public static final int ALL_EVENTS = -1; // 0xffffffff + field public static final int ALL_GROUP_THREAD_EVENTS = 0; // 0x0 + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsEventQueryParams> CREATOR; + field public static final int GROUP_THREAD_ICON_CHANGED_EVENT = 8; // 0x8 + field public static final int GROUP_THREAD_NAME_CHANGED_EVENT = 16; // 0x10 + field public static final int GROUP_THREAD_PARTICIPANT_JOINED_EVENT = 2; // 0x2 + field public static final int GROUP_THREAD_PARTICIPANT_LEFT_EVENT = 4; // 0x4 + field public static final int PARTICIPANT_ALIAS_CHANGED_EVENT = 1; // 0x1 + field public static final int SORT_BY_CREATION_ORDER = 0; // 0x0 + field public static final int SORT_BY_TIMESTAMP = 1; // 0x1 + } + + public static class RcsEventQueryParams.Builder { + ctor public RcsEventQueryParams.Builder(); + method public android.telephony.ims.RcsEventQueryParams build(); + method @CheckResult public android.telephony.ims.RcsEventQueryParams.Builder setEventType(@android.telephony.ims.RcsEventQueryParams.EventType int); + method @CheckResult public android.telephony.ims.RcsEventQueryParams.Builder setGroupThread(@NonNull android.telephony.ims.RcsGroupThread); + method @CheckResult public android.telephony.ims.RcsEventQueryParams.Builder setResultLimit(@IntRange(from=0) int) throws java.security.InvalidParameterException; + method @CheckResult public android.telephony.ims.RcsEventQueryParams.Builder setSortDirection(boolean); + method @CheckResult public android.telephony.ims.RcsEventQueryParams.Builder setSortProperty(@android.telephony.ims.RcsEventQueryParams.SortingProperty int); + } + + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.telephony.ims.RcsEventQueryParams.ALL_EVENTS, android.telephony.ims.RcsEventQueryParams.ALL_GROUP_THREAD_EVENTS, android.telephony.ims.RcsEventQueryParams.PARTICIPANT_ALIAS_CHANGED_EVENT, android.telephony.ims.RcsEventQueryParams.GROUP_THREAD_PARTICIPANT_JOINED_EVENT, android.telephony.ims.RcsEventQueryParams.GROUP_THREAD_PARTICIPANT_LEFT_EVENT, android.telephony.ims.RcsEventQueryParams.GROUP_THREAD_NAME_CHANGED_EVENT, android.telephony.ims.RcsEventQueryParams.GROUP_THREAD_ICON_CHANGED_EVENT}) public static @interface RcsEventQueryParams.EventType { + } + + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.telephony.ims.RcsEventQueryParams.SORT_BY_CREATION_ORDER, android.telephony.ims.RcsEventQueryParams.SORT_BY_TIMESTAMP}) public static @interface RcsEventQueryParams.SortingProperty { + } + + public final class RcsEventQueryResult implements android.os.Parcelable { + method public int describeContents(); + method public android.telephony.ims.RcsQueryContinuationToken getContinuationToken(); + method public java.util.List<android.telephony.ims.RcsEvent> getEvents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsEventQueryResult> CREATOR; + } + + public final class RcsFileTransferCreationParams implements android.os.Parcelable { + method public int describeContents(); + method public String getContentMimeType(); + method public android.net.Uri getContentUri(); + method public long getFileSize(); + method @android.telephony.ims.RcsFileTransferPart.RcsFileTransferStatus public int getFileTransferStatus(); + method public int getHeight(); + method public long getMediaDuration(); + method public String getPreviewMimeType(); + method public android.net.Uri getPreviewUri(); + method public String getRcsFileTransferSessionId(); + method public long getTransferOffset(); + method public int getWidth(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsFileTransferCreationParams> CREATOR; + } + + public class RcsFileTransferCreationParams.Builder { + ctor public RcsFileTransferCreationParams.Builder(); + method public android.telephony.ims.RcsFileTransferCreationParams build(); + method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setContentMimeType(String); + method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setContentUri(android.net.Uri); + method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setFileSize(long); + method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setFileTransferSessionId(String); + method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setFileTransferStatus(@android.telephony.ims.RcsFileTransferPart.RcsFileTransferStatus int); + method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setHeight(int); + method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setMediaDuration(long); + method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setPreviewMimeType(String); + method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setPreviewUri(android.net.Uri); + method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setTransferOffset(long); + method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setWidth(int); + } + + public class RcsFileTransferPart { + method @WorkerThread @Nullable public String getContentMimeType() throws android.telephony.ims.RcsMessageStoreException; + method @Nullable @WorkerThread public android.net.Uri getContentUri() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public long getFileSize() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public String getFileTransferSessionId() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @android.telephony.ims.RcsFileTransferPart.RcsFileTransferStatus public int getFileTransferStatus() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public int getHeight() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public long getLength() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public String getPreviewMimeType() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public android.net.Uri getPreviewUri() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public long getTransferOffset() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public int getWidth() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setContentMimeType(String) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setContentUri(android.net.Uri) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setFileSize(long) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setFileTransferSessionId(String) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setFileTransferStatus(@android.telephony.ims.RcsFileTransferPart.RcsFileTransferStatus int) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setHeight(int) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setLength(long) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setPreviewMimeType(String) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setPreviewUri(android.net.Uri) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setTransferOffset(long) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setWidth(int) throws android.telephony.ims.RcsMessageStoreException; + field public static final int DOWNLOADING = 6; // 0x6 + field public static final int DOWNLOADING_CANCELLED = 9; // 0x9 + field public static final int DOWNLOADING_FAILED = 8; // 0x8 + field public static final int DOWNLOADING_PAUSED = 7; // 0x7 + field public static final int DRAFT = 1; // 0x1 + field public static final int NOT_SET = 0; // 0x0 + field public static final int SENDING = 2; // 0x2 + field public static final int SENDING_CANCELLED = 5; // 0x5 + field public static final int SENDING_FAILED = 4; // 0x4 + field public static final int SENDING_PAUSED = 3; // 0x3 + field public static final int SUCCEEDED = 10; // 0xa + } + + @IntDef({android.telephony.ims.RcsFileTransferPart.DRAFT, android.telephony.ims.RcsFileTransferPart.SENDING, android.telephony.ims.RcsFileTransferPart.SENDING_PAUSED, android.telephony.ims.RcsFileTransferPart.SENDING_FAILED, android.telephony.ims.RcsFileTransferPart.SENDING_CANCELLED, android.telephony.ims.RcsFileTransferPart.DOWNLOADING, android.telephony.ims.RcsFileTransferPart.DOWNLOADING_PAUSED, android.telephony.ims.RcsFileTransferPart.DOWNLOADING_FAILED, android.telephony.ims.RcsFileTransferPart.DOWNLOADING_CANCELLED, android.telephony.ims.RcsFileTransferPart.SUCCEEDED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RcsFileTransferPart.RcsFileTransferStatus { + } + + public class RcsGroupThread extends android.telephony.ims.RcsThread { + method @WorkerThread public void addParticipant(@NonNull android.telephony.ims.RcsParticipant) throws android.telephony.ims.RcsMessageStoreException; + method @Nullable @WorkerThread public android.net.Uri getConferenceUri() throws android.telephony.ims.RcsMessageStoreException; + method @Nullable public android.net.Uri getGroupIcon() throws android.telephony.ims.RcsMessageStoreException; + method @Nullable @WorkerThread public String getGroupName() throws android.telephony.ims.RcsMessageStoreException; + method @Nullable @WorkerThread public android.telephony.ims.RcsParticipant getOwner() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public java.util.Set<android.telephony.ims.RcsParticipant> getParticipants() throws android.telephony.ims.RcsMessageStoreException; + method public boolean isGroup(); + method @WorkerThread public void removeParticipant(@NonNull android.telephony.ims.RcsParticipant) throws android.telephony.ims.RcsMessageStoreException; + method @Nullable @WorkerThread public void setConferenceUri(android.net.Uri) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setGroupIcon(@Nullable android.net.Uri) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setGroupName(String) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setOwner(@Nullable android.telephony.ims.RcsParticipant) throws android.telephony.ims.RcsMessageStoreException; + } + + public abstract class RcsGroupThreadEvent extends android.telephony.ims.RcsEvent { + method @NonNull public android.telephony.ims.RcsParticipant getOriginatingParticipant(); + method @NonNull public android.telephony.ims.RcsGroupThread getRcsGroupThread(); + } + + public final class RcsGroupThreadIconChangedEvent extends android.telephony.ims.RcsGroupThreadEvent implements android.os.Parcelable { + ctor public RcsGroupThreadIconChangedEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @Nullable android.net.Uri); + method public int describeContents(); + method @Nullable public android.net.Uri getNewIcon(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsGroupThreadIconChangedEvent> CREATOR; + } + + public final class RcsGroupThreadNameChangedEvent extends android.telephony.ims.RcsGroupThreadEvent implements android.os.Parcelable { + ctor public RcsGroupThreadNameChangedEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @Nullable String); + method public int describeContents(); + method @Nullable public String getNewName(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsGroupThreadNameChangedEvent> CREATOR; + } + + public final class RcsGroupThreadParticipantJoinedEvent extends android.telephony.ims.RcsGroupThreadEvent implements android.os.Parcelable { + ctor public RcsGroupThreadParticipantJoinedEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @NonNull android.telephony.ims.RcsParticipant); + method public int describeContents(); + method public android.telephony.ims.RcsParticipant getJoinedParticipant(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsGroupThreadParticipantJoinedEvent> CREATOR; + } + + public final class RcsGroupThreadParticipantLeftEvent extends android.telephony.ims.RcsGroupThreadEvent implements android.os.Parcelable { + ctor public RcsGroupThreadParticipantLeftEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @NonNull android.telephony.ims.RcsParticipant); + method public int describeContents(); + method @NonNull public android.telephony.ims.RcsParticipant getLeavingParticipantId(); + method public void persist() throws android.telephony.ims.RcsMessageStoreException; + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsGroupThreadParticipantLeftEvent> CREATOR; + } + + public class RcsIncomingMessage extends android.telephony.ims.RcsMessage { + method @WorkerThread public long getArrivalTimestamp() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public long getSeenTimestamp() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public android.telephony.ims.RcsParticipant getSenderParticipant() throws android.telephony.ims.RcsMessageStoreException; + method public boolean isIncoming(); + method @WorkerThread public void setArrivalTimestamp(long) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setSeenTimestamp(long) throws android.telephony.ims.RcsMessageStoreException; + } + + public final class RcsIncomingMessageCreationParams extends android.telephony.ims.RcsMessageCreationParams implements android.os.Parcelable { + method public int describeContents(); + method public long getArrivalTimestamp(); + method public long getSeenTimestamp(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsIncomingMessageCreationParams> CREATOR; + } + + public static class RcsIncomingMessageCreationParams.Builder extends android.telephony.ims.RcsMessageCreationParams.Builder { + ctor public RcsIncomingMessageCreationParams.Builder(long, long, int); + method public android.telephony.ims.RcsIncomingMessageCreationParams build(); + method @CheckResult public android.telephony.ims.RcsIncomingMessageCreationParams.Builder setArrivalTimestamp(long); + method @CheckResult public android.telephony.ims.RcsIncomingMessageCreationParams.Builder setSeenTimestamp(long); + method @CheckResult public android.telephony.ims.RcsIncomingMessageCreationParams.Builder setSenderParticipant(android.telephony.ims.RcsParticipant); + } + + public class RcsManager { + method public android.telephony.ims.RcsMessageStore getRcsMessageStore(); + } + + public abstract class RcsMessage { + method @NonNull @WorkerThread public java.util.Set<android.telephony.ims.RcsFileTransferPart> getFileTransferParts() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public double getLatitude() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public double getLongitude() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public long getOriginationTimestamp() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public String getRcsMessageId() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @android.telephony.ims.RcsMessage.RcsMessageStatus public int getStatus() throws android.telephony.ims.RcsMessageStoreException; + method public int getSubscriptionId() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public String getText() throws android.telephony.ims.RcsMessageStoreException; + method @NonNull @WorkerThread public android.telephony.ims.RcsFileTransferPart insertFileTransfer(android.telephony.ims.RcsFileTransferCreationParams) throws android.telephony.ims.RcsMessageStoreException; + method public abstract boolean isIncoming(); + method @WorkerThread public void removeFileTransferPart(@NonNull android.telephony.ims.RcsFileTransferPart) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setLatitude(double) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setLongitude(double) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setOriginationTimestamp(long) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setRcsMessageId(String) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setStatus(@android.telephony.ims.RcsMessage.RcsMessageStatus int) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setSubscriptionId(int) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setText(String) throws android.telephony.ims.RcsMessageStoreException; + field public static final int DRAFT = 1; // 0x1 + field public static final int FAILED = 6; // 0x6 + field public static final double LOCATION_NOT_SET = 4.9E-324; + field public static final int NOT_SET = 0; // 0x0 + field public static final int QUEUED = 2; // 0x2 + field public static final int RECEIVED = 7; // 0x7 + field public static final int RETRYING = 5; // 0x5 + field public static final int SEEN = 9; // 0x9 + field public static final int SENDING = 3; // 0x3 + field public static final int SENT = 4; // 0x4 + } + + @IntDef({android.telephony.ims.RcsMessage.DRAFT, android.telephony.ims.RcsMessage.QUEUED, android.telephony.ims.RcsMessage.SENDING, android.telephony.ims.RcsMessage.SENT, android.telephony.ims.RcsMessage.RETRYING, android.telephony.ims.RcsMessage.FAILED, android.telephony.ims.RcsMessage.RECEIVED, android.telephony.ims.RcsMessage.SEEN}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RcsMessage.RcsMessageStatus { + } + + public class RcsMessageCreationParams { + ctor protected RcsMessageCreationParams(android.telephony.ims.RcsMessageCreationParams.Builder); + method public double getLatitude(); + method public double getLongitude(); + method public int getMessageStatus(); + method public long getOriginationTimestamp(); + method @Nullable public String getRcsMessageGlobalId(); + method public int getSubId(); + method @Nullable public String getText(); + } + + public static class RcsMessageCreationParams.Builder { + method public android.telephony.ims.RcsMessageCreationParams build(); + method @CheckResult public android.telephony.ims.RcsMessageCreationParams.Builder setLatitude(double); + method @CheckResult public android.telephony.ims.RcsMessageCreationParams.Builder setLongitude(double); + method @CheckResult public android.telephony.ims.RcsMessageCreationParams.Builder setRcsMessageId(String); + method @CheckResult public android.telephony.ims.RcsMessageCreationParams.Builder setStatus(@android.telephony.ims.RcsMessage.RcsMessageStatus int); + method @CheckResult public android.telephony.ims.RcsMessageCreationParams.Builder setText(String); + } + + public final class RcsMessageQueryParams implements android.os.Parcelable { + method public int describeContents(); + method public int getFileTransferPresence(); + method public int getLimit(); + method public String getMessageLike(); + method public int getMessageType(); + method public boolean getSortDirection(); + method @android.telephony.ims.RcsMessageQueryParams.SortingProperty public int getSortingProperty(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsMessageQueryParams> CREATOR; + field public static final int MESSAGES_WITHOUT_FILE_TRANSFERS = 8; // 0x8 + field public static final int MESSAGES_WITH_FILE_TRANSFERS = 4; // 0x4 + field public static final int MESSAGE_TYPE_INCOMING = 1; // 0x1 + field public static final int MESSAGE_TYPE_OUTGOING = 2; // 0x2 + field public static final int SORT_BY_CREATION_ORDER = 0; // 0x0 + field public static final int SORT_BY_TIMESTAMP = 1; // 0x1 + } + + public static class RcsMessageQueryParams.Builder { + ctor public RcsMessageQueryParams.Builder(); + method public android.telephony.ims.RcsMessageQueryParams build(); + method @CheckResult public android.telephony.ims.RcsMessageQueryParams.Builder setFileTransferPresence(int); + method @CheckResult public android.telephony.ims.RcsMessageQueryParams.Builder setMessageLike(String); + method @CheckResult public android.telephony.ims.RcsMessageQueryParams.Builder setMessageType(int); + method @CheckResult public android.telephony.ims.RcsMessageQueryParams.Builder setResultLimit(@IntRange(from=0) int) throws java.security.InvalidParameterException; + method @CheckResult public android.telephony.ims.RcsMessageQueryParams.Builder setSortDirection(boolean); + method @CheckResult public android.telephony.ims.RcsMessageQueryParams.Builder setSortProperty(@android.telephony.ims.RcsMessageQueryParams.SortingProperty int); + method @CheckResult public android.telephony.ims.RcsMessageQueryParams.Builder setThread(@Nullable android.telephony.ims.RcsThread); + } + + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.telephony.ims.RcsMessageQueryParams.SORT_BY_CREATION_ORDER, android.telephony.ims.RcsMessageQueryParams.SORT_BY_TIMESTAMP}) public static @interface RcsMessageQueryParams.SortingProperty { + } + + public final class RcsMessageQueryResult implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.telephony.ims.RcsQueryContinuationToken getContinuationToken(); + method @NonNull public java.util.List<android.telephony.ims.RcsMessage> getMessages(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsMessageQueryResult> CREATOR; + } + + public final class RcsMessageSnippet implements android.os.Parcelable { + method public int describeContents(); + method @android.telephony.ims.RcsMessage.RcsMessageStatus public int getSnippetStatus(); + method @Nullable public String getSnippetText(); + method public long getSnippetTimestamp(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsMessageSnippet> CREATOR; + } + + public class RcsMessageStore { + ctor public RcsMessageStore(); + method @WorkerThread @NonNull public android.telephony.ims.RcsGroupThread createGroupThread(@Nullable java.util.List<android.telephony.ims.RcsParticipant>, @Nullable String, @Nullable android.net.Uri) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public android.telephony.ims.Rcs1To1Thread createRcs1To1Thread(@NonNull android.telephony.ims.RcsParticipant) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public android.telephony.ims.RcsParticipant createRcsParticipant(String, @Nullable String) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void deleteThread(@NonNull android.telephony.ims.RcsThread) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public android.telephony.ims.RcsEventQueryResult getRcsEvents(@Nullable android.telephony.ims.RcsEventQueryParams) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public android.telephony.ims.RcsEventQueryResult getRcsEvents(@NonNull android.telephony.ims.RcsQueryContinuationToken) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public android.telephony.ims.RcsMessageQueryResult getRcsMessages(@Nullable android.telephony.ims.RcsMessageQueryParams) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public android.telephony.ims.RcsMessageQueryResult getRcsMessages(@NonNull android.telephony.ims.RcsQueryContinuationToken) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public android.telephony.ims.RcsParticipantQueryResult getRcsParticipants(@Nullable android.telephony.ims.RcsParticipantQueryParams) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public android.telephony.ims.RcsParticipantQueryResult getRcsParticipants(@NonNull android.telephony.ims.RcsQueryContinuationToken) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public android.telephony.ims.RcsThreadQueryResult getRcsThreads(@Nullable android.telephony.ims.RcsThreadQueryParams) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public android.telephony.ims.RcsThreadQueryResult getRcsThreads(@NonNull android.telephony.ims.RcsQueryContinuationToken) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public void persistRcsEvent(android.telephony.ims.RcsEvent) throws android.telephony.ims.RcsMessageStoreException; + } + + public class RcsMessageStoreException extends java.lang.Exception { + ctor public RcsMessageStoreException(String); + } + + public class RcsOutgoingMessage extends android.telephony.ims.RcsMessage { + method @NonNull @WorkerThread public java.util.List<android.telephony.ims.RcsOutgoingMessageDelivery> getOutgoingDeliveries() throws android.telephony.ims.RcsMessageStoreException; + method public boolean isIncoming(); + } + + public final class RcsOutgoingMessageCreationParams extends android.telephony.ims.RcsMessageCreationParams implements android.os.Parcelable { + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsOutgoingMessageCreationParams> CREATOR; + } + + public static class RcsOutgoingMessageCreationParams.Builder extends android.telephony.ims.RcsMessageCreationParams.Builder { + ctor public RcsOutgoingMessageCreationParams.Builder(long, int); + method public android.telephony.ims.RcsOutgoingMessageCreationParams build(); + } + + public class RcsOutgoingMessageDelivery { + method @WorkerThread public long getDeliveredTimestamp() throws android.telephony.ims.RcsMessageStoreException; + method @NonNull public android.telephony.ims.RcsOutgoingMessage getMessage(); + method @NonNull public android.telephony.ims.RcsParticipant getRecipient(); + method @WorkerThread public long getSeenTimestamp() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @android.telephony.ims.RcsMessage.RcsMessageStatus public int getStatus() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setDeliveredTimestamp(long) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setSeenTimestamp(long) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setStatus(@android.telephony.ims.RcsMessage.RcsMessageStatus int) throws android.telephony.ims.RcsMessageStoreException; + } + + public class RcsParticipant { + method @Nullable @WorkerThread public String getAlias() throws android.telephony.ims.RcsMessageStoreException; + method @Nullable @WorkerThread public String getCanonicalAddress() throws android.telephony.ims.RcsMessageStoreException; + method @Nullable @WorkerThread public String getContactId() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setAlias(String) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void setContactId(String) throws android.telephony.ims.RcsMessageStoreException; + } + + public final class RcsParticipantAliasChangedEvent extends android.telephony.ims.RcsEvent implements android.os.Parcelable { + ctor public RcsParticipantAliasChangedEvent(long, @NonNull android.telephony.ims.RcsParticipant, @Nullable String); + method public int describeContents(); + method @Nullable public String getNewAlias(); + method @NonNull public android.telephony.ims.RcsParticipant getParticipantId(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsParticipantAliasChangedEvent> CREATOR; + } + + public final class RcsParticipantQueryParams implements android.os.Parcelable { + method public int describeContents(); + method public String getAliasLike(); + method public String getCanonicalAddressLike(); + method public int getLimit(); + method public boolean getSortDirection(); + method public int getSortingProperty(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsParticipantQueryParams> CREATOR; + field public static final int SORT_BY_ALIAS = 1; // 0x1 + field public static final int SORT_BY_CANONICAL_ADDRESS = 2; // 0x2 + field public static final int SORT_BY_CREATION_ORDER = 0; // 0x0 + } + + public static class RcsParticipantQueryParams.Builder { + ctor public RcsParticipantQueryParams.Builder(); + method public android.telephony.ims.RcsParticipantQueryParams build(); + method @CheckResult public android.telephony.ims.RcsParticipantQueryParams.Builder setAliasLike(String); + method @CheckResult public android.telephony.ims.RcsParticipantQueryParams.Builder setCanonicalAddressLike(String); + method @CheckResult public android.telephony.ims.RcsParticipantQueryParams.Builder setResultLimit(@IntRange(from=0) int) throws java.security.InvalidParameterException; + method @CheckResult public android.telephony.ims.RcsParticipantQueryParams.Builder setSortDirection(boolean); + method @CheckResult public android.telephony.ims.RcsParticipantQueryParams.Builder setSortProperty(@android.telephony.ims.RcsParticipantQueryParams.SortingProperty int); + method @CheckResult public android.telephony.ims.RcsParticipantQueryParams.Builder setThread(android.telephony.ims.RcsThread); + } + + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.telephony.ims.RcsParticipantQueryParams.SORT_BY_CREATION_ORDER, android.telephony.ims.RcsParticipantQueryParams.SORT_BY_ALIAS, android.telephony.ims.RcsParticipantQueryParams.SORT_BY_CANONICAL_ADDRESS}) public static @interface RcsParticipantQueryParams.SortingProperty { + } + + public final class RcsParticipantQueryResult implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.telephony.ims.RcsQueryContinuationToken getContinuationToken(); + method @NonNull public java.util.List<android.telephony.ims.RcsParticipant> getParticipants(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsParticipantQueryResult> CREATOR; + } + + public final class RcsQueryContinuationToken implements android.os.Parcelable { + method public int describeContents(); + method @android.telephony.ims.RcsQueryContinuationToken.ContinuationTokenType public int getQueryType(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsQueryContinuationToken> CREATOR; + field public static final int EVENT_QUERY_CONTINUATION_TOKEN_TYPE = 0; // 0x0 + field public static final int MESSAGE_QUERY_CONTINUATION_TOKEN_TYPE = 1; // 0x1 + field public static final int PARTICIPANT_QUERY_CONTINUATION_TOKEN_TYPE = 2; // 0x2 + field public static final int THREAD_QUERY_CONTINUATION_TOKEN_TYPE = 3; // 0x3 + } + + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.telephony.ims.RcsQueryContinuationToken.EVENT_QUERY_CONTINUATION_TOKEN_TYPE, android.telephony.ims.RcsQueryContinuationToken.MESSAGE_QUERY_CONTINUATION_TOKEN_TYPE, android.telephony.ims.RcsQueryContinuationToken.PARTICIPANT_QUERY_CONTINUATION_TOKEN_TYPE, android.telephony.ims.RcsQueryContinuationToken.THREAD_QUERY_CONTINUATION_TOKEN_TYPE}) public static @interface RcsQueryContinuationToken.ContinuationTokenType { + } + + public abstract class RcsThread { + method @WorkerThread @NonNull public android.telephony.ims.RcsIncomingMessage addIncomingMessage(@NonNull android.telephony.ims.RcsIncomingMessageCreationParams) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public android.telephony.ims.RcsOutgoingMessage addOutgoingMessage(@NonNull android.telephony.ims.RcsOutgoingMessageCreationParams) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread public void deleteMessage(@NonNull android.telephony.ims.RcsMessage) throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public android.telephony.ims.RcsMessageQueryResult getMessages() throws android.telephony.ims.RcsMessageStoreException; + method @WorkerThread @NonNull public android.telephony.ims.RcsMessageSnippet getSnippet() throws android.telephony.ims.RcsMessageStoreException; + method public abstract boolean isGroup(); + } + + public final class RcsThreadQueryParams implements android.os.Parcelable { + method public int describeContents(); + method public int getLimit(); + method public boolean getSortDirection(); + method @android.telephony.ims.RcsThreadQueryParams.SortingProperty public int getSortingProperty(); + method public int getThreadType(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsThreadQueryParams> CREATOR; + field public static final int SORT_BY_CREATION_ORDER = 0; // 0x0 + field public static final int SORT_BY_TIMESTAMP = 1; // 0x1 + field public static final int THREAD_TYPE_1_TO_1 = 2; // 0x2 + field public static final int THREAD_TYPE_GROUP = 1; // 0x1 + } + + public static class RcsThreadQueryParams.Builder { + ctor public RcsThreadQueryParams.Builder(); + method public android.telephony.ims.RcsThreadQueryParams build(); + method @CheckResult public android.telephony.ims.RcsThreadQueryParams.Builder setParticipant(@NonNull android.telephony.ims.RcsParticipant); + method @CheckResult public android.telephony.ims.RcsThreadQueryParams.Builder setParticipants(@NonNull java.util.List<android.telephony.ims.RcsParticipant>); + method @CheckResult public android.telephony.ims.RcsThreadQueryParams.Builder setResultLimit(@IntRange(from=0) int) throws java.security.InvalidParameterException; + method @CheckResult public android.telephony.ims.RcsThreadQueryParams.Builder setSortDirection(boolean); + method @CheckResult public android.telephony.ims.RcsThreadQueryParams.Builder setSortProperty(@android.telephony.ims.RcsThreadQueryParams.SortingProperty int); + method @CheckResult public android.telephony.ims.RcsThreadQueryParams.Builder setThreadType(int); + } + + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.telephony.ims.RcsThreadQueryParams.SORT_BY_CREATION_ORDER, android.telephony.ims.RcsThreadQueryParams.SORT_BY_TIMESTAMP}) public static @interface RcsThreadQueryParams.SortingProperty { + } + + public final class RcsThreadQueryResult implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.telephony.ims.RcsQueryContinuationToken getContinuationToken(); + method @NonNull public java.util.List<android.telephony.ims.RcsThread> getThreads(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsThreadQueryResult> CREATOR; + } + +} + package android.telephony.mbms { public class DownloadProgressListener { @@ -48995,6 +49490,7 @@ package android.view { method public boolean[] hasKeys(int...); method public boolean hasMicrophone(); method public boolean isEnabled(); + method public boolean isExternal(); method public boolean isVirtual(); method public boolean supportsSource(int); method public void writeToParcel(android.os.Parcel, int); @@ -49550,6 +50046,7 @@ package android.view { ctor protected LayoutInflater(android.view.LayoutInflater, android.content.Context); method public abstract android.view.LayoutInflater cloneInContext(android.content.Context); method public final android.view.View createView(String, String, android.util.AttributeSet) throws java.lang.ClassNotFoundException, android.view.InflateException; + method @Nullable public final android.view.View createView(@NonNull android.content.Context, @NonNull String, @Nullable String, @Nullable android.util.AttributeSet) throws java.lang.ClassNotFoundException, android.view.InflateException; method public static android.view.LayoutInflater from(android.content.Context); method public android.content.Context getContext(); method public final android.view.LayoutInflater.Factory getFactory(); @@ -49561,6 +50058,7 @@ package android.view { method public android.view.View inflate(org.xmlpull.v1.XmlPullParser, @Nullable android.view.ViewGroup, boolean); method protected android.view.View onCreateView(String, android.util.AttributeSet) throws java.lang.ClassNotFoundException; method protected android.view.View onCreateView(android.view.View, String, android.util.AttributeSet) throws java.lang.ClassNotFoundException; + method @Nullable public android.view.View onCreateView(@NonNull android.content.Context, @Nullable android.view.View, @NonNull String, @Nullable android.util.AttributeSet) throws java.lang.ClassNotFoundException; method public void setFactory(android.view.LayoutInflater.Factory); method public void setFactory2(android.view.LayoutInflater.Factory2); method public void setFilter(android.view.LayoutInflater.Filter); @@ -51111,6 +51609,7 @@ package android.view { method public int getScaledHoverSlop(); method public int getScaledMaximumDrawingCacheSize(); method public int getScaledMaximumFlingVelocity(); + method public int getScaledMinScalingSpan(); method public int getScaledMinimumFlingVelocity(); method public int getScaledOverflingDistance(); method public int getScaledOverscrollDistance(); @@ -52607,7 +53106,6 @@ package android.view.animation { public abstract class Animation implements java.lang.Cloneable { ctor public Animation(); ctor public Animation(android.content.Context, android.util.AttributeSet); - method public void addAnimationListener(android.view.animation.Animation.AnimationListener); method protected void applyTransformation(float, android.view.animation.Transformation); method public void cancel(); method protected android.view.animation.Animation clone() throws java.lang.CloneNotSupportedException; @@ -52632,7 +53130,6 @@ package android.view.animation { method public void initialize(int, int, int, int); method public boolean isFillEnabled(); method public boolean isInitialized(); - method public void removeAnimationListener(android.view.animation.Animation.AnimationListener); method public void reset(); method protected float resolveSize(int, float, int, int); method public void restrictDuration(long); @@ -55245,6 +55742,7 @@ package android.widget { method public void performCompletion(); method protected void performFiltering(CharSequence, int); method public void performValidation(); + method public final void refreshAutoCompleteResults(); method protected void replaceText(CharSequence); method public <T extends android.widget.ListAdapter & android.widget.Filterable> void setAdapter(T); method public void setCompletionHint(CharSequence); @@ -55864,11 +56362,16 @@ package android.widget { method public boolean executeKeyEvent(android.view.KeyEvent); method public void fling(int); method public boolean fullScroll(int); + method @ColorInt public int getLeftEdgeEffectColor(); method public int getMaxScrollAmount(); + method @ColorInt public int getRightEdgeEffectColor(); method public boolean isFillViewport(); method public boolean isSmoothScrollingEnabled(); method public boolean pageScroll(int); + method public void setEdgeEffectColor(@ColorInt int); method public void setFillViewport(boolean); + method public void setLeftEdgeEffectColor(@ColorInt int); + method public void setRightEdgeEffectColor(@ColorInt int); method public void setSmoothScrollingEnabled(boolean); method public final void smoothScrollBy(int, int); method public final void smoothScrollTo(int, int); @@ -56009,6 +56512,7 @@ package android.widget { method @Nullable public android.view.View getAnchorView(); method @StyleRes public int getAnimationStyle(); method @Nullable public android.graphics.drawable.Drawable getBackground(); + method @Nullable public android.graphics.Rect getEpicenterBounds(); method public int getHeight(); method public int getHorizontalOffset(); method public int getInputMethodMode(); @@ -56035,6 +56539,7 @@ package android.widget { method public void setBackgroundDrawable(@Nullable android.graphics.drawable.Drawable); method public void setContentWidth(int); method public void setDropDownGravity(int); + method public void setEpicenterBounds(@Nullable android.graphics.Rect); method public void setHeight(int); method public void setHorizontalOffset(int); method public void setInputMethodMode(int); @@ -56198,6 +56703,8 @@ package android.widget { method public int getMaxValue(); method public int getMinValue(); method public int getSelectionDividerHeight(); + method @ColorInt public int getTextColor(); + method @FloatRange(from=0.0, fromInclusive=false) public float getTextSize(); method public int getValue(); method public boolean getWrapSelectorWheel(); method public void setDisplayedValues(String[]); @@ -56208,6 +56715,8 @@ package android.widget { method public void setOnScrollListener(android.widget.NumberPicker.OnScrollListener); method public void setOnValueChangedListener(android.widget.NumberPicker.OnValueChangeListener); method public void setSelectionDividerHeight(@IntRange(from=0) @Px int); + method public void setTextColor(@ColorInt int); + method public void setTextSize(@FloatRange(from=0.0, fromInclusive=false) float); method public void setValue(int); method public void setWrapSelectorWheel(boolean); } @@ -56295,6 +56804,7 @@ package android.widget { method public android.view.View getContentView(); method public float getElevation(); method @Nullable public android.transition.Transition getEnterTransition(); + method @Nullable public android.graphics.Rect getEpicenterBounds(); method @Nullable public android.transition.Transition getExitTransition(); method public int getHeight(); method public int getInputMethodMode(); @@ -56307,30 +56817,37 @@ package android.widget { method public int getWindowLayoutType(); method public boolean isAboveAnchor(); method public boolean isAttachedInDecor(); + method public boolean isClipToScreenEnabled(); method public boolean isClippingEnabled(); method public boolean isFocusable(); + method public boolean isLayoutInScreenEnabled(); method public boolean isOutsideTouchable(); method public boolean isShowing(); method public boolean isSplitTouchEnabled(); + method public boolean isTouchModal(); method public boolean isTouchable(); method public void setAnimationStyle(int); method public void setAttachedInDecor(boolean); method public void setBackgroundDrawable(android.graphics.drawable.Drawable); + method public void setClipToScreenEnabled(boolean); method public void setClippingEnabled(boolean); method public void setContentView(android.view.View); method public void setElevation(float); method public void setEnterTransition(@Nullable android.transition.Transition); + method public void setEpicenterBounds(@Nullable android.graphics.Rect); method public void setExitTransition(@Nullable android.transition.Transition); method public void setFocusable(boolean); method public void setHeight(int); method public void setIgnoreCheekPress(); method public void setInputMethodMode(int); + method public void setLayoutInScreenEnabled(boolean); method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener); method public void setOutsideTouchable(boolean); method public void setOverlapAnchor(boolean); method public void setSoftInputMode(int); method public void setSplitTouchEnabled(boolean); method public void setTouchInterceptor(android.view.View.OnTouchListener); + method public void setTouchModal(boolean); method public void setTouchable(boolean); method public void setWidth(int); method @Deprecated public void setWindowLayoutMode(int, int); @@ -56359,6 +56876,7 @@ package android.widget { ctor public ProgressBar(android.content.Context, android.util.AttributeSet); ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int); ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int, int); + method @Nullable public android.graphics.drawable.Drawable getCurrentDrawable(); method public android.graphics.drawable.Drawable getIndeterminateDrawable(); method @Nullable public android.content.res.ColorStateList getIndeterminateTintList(); method @Nullable public android.graphics.PorterDuff.Mode getIndeterminateTintMode(); @@ -56656,13 +57174,18 @@ package android.widget { method public boolean executeKeyEvent(android.view.KeyEvent); method public void fling(int); method public boolean fullScroll(int); + method @ColorInt public int getBottomEdgeEffectColor(); method public int getMaxScrollAmount(); + method @ColorInt public int getTopEdgeEffectColor(); method public boolean isFillViewport(); method public boolean isSmoothScrollingEnabled(); method public boolean pageScroll(int); method public void scrollToDescendant(android.view.View); + method public void setBottomEdgeEffectColor(@ColorInt int); + method public void setEdgeEffectColor(@ColorInt int); method public void setFillViewport(boolean); method public void setSmoothScrollingEnabled(boolean); + method public void setTopEdgeEffectColor(@ColorInt int); method public final void smoothScrollBy(int, int); method public final void smoothScrollTo(int, int); } @@ -61183,9 +61706,9 @@ package java.lang.invoke { method public String getName(); method public int getReferenceKind(); method public default boolean isVarArgs(); - method public static boolean refKindIsField(int); - method public static boolean refKindIsValid(int); - method public static String refKindName(int); + method @Deprecated public static boolean refKindIsField(int); + method @Deprecated public static boolean refKindIsValid(int); + method @Deprecated public static String refKindName(int); method public static String referenceKindToString(int); method public <T extends java.lang.reflect.Member> T reflectAs(Class<T>, java.lang.invoke.MethodHandles.Lookup); method public static String toString(int, Class<?>, String, java.lang.invoke.MethodType); diff --git a/api/removed.txt b/api/removed.txt index 262ffec46de1..f5bd434c3cc0 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -507,6 +507,19 @@ package android.provider { field @Deprecated public static final String TIMESTAMP = "timestamp"; } + public final class MediaStore { + method @Deprecated @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri); + method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri); + method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri, long); + method @Deprecated public static void untrash(@NonNull android.content.Context, @NonNull android.net.Uri); + } + + public static interface MediaStore.MediaColumns extends android.provider.BaseColumns { + field @Deprecated public static final String DATE_EXPIRES = "date_expires"; + field @Deprecated public static final String HASH = "_hash"; + field @Deprecated public static final String IS_TRASHED = "is_trashed"; + } + public static final class Settings.Global extends android.provider.Settings.NameValueTable { field @Deprecated public static final String CONTACT_METADATA_SYNC = "contact_metadata_sync"; } diff --git a/api/system-current.txt b/api/system-current.txt index 02718cbaac07..093f9165f462 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -201,11 +201,11 @@ package android { } public static final class R.array { - field public static final int config_defaultRoleHolders = 17235974; // 0x1070006 field public static final int config_keySystemUuidMapping = 17235973; // 0x1070005 } public static final class R.attr { + field public static final int allowClearUserDataOnFailedRestore = 16844198; // 0x10105a6 field public static final int inheritShowWhenLocked = 16844194; // 0x10105a2 field public static final int isVrOnly = 16844152; // 0x1010578 field public static final int requiredSystemPropertyName = 16844133; // 0x1010565 @@ -237,6 +237,12 @@ package android { } public static final class R.string { + field public static final int config_defaultAssistant = 17039393; // 0x1040021 + field public static final int config_defaultBrowser = 17039394; // 0x1040022 + field public static final int config_defaultDialer = 17039395; // 0x1040023 + field public static final int config_defaultGallery = 17039398; // 0x1040026 + field public static final int config_defaultMusic = 17039397; // 0x1040025 + field public static final int config_defaultSms = 17039396; // 0x1040024 field public static final int config_feedbackIntentExtraKey = 17039391; // 0x104001f field public static final int config_feedbackIntentNameKey = 17039392; // 0x1040020 field public static final int config_helpIntentExtraKey = 17039389; // 0x104001d @@ -635,7 +641,7 @@ package android.app.admin { method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String); method @Deprecated @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException; method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied(); - method public void setProfileOwnerCanAccessDeviceIdsForUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle); + method @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIdsForUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle); field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED"; field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED"; field public static final String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION"; @@ -1145,7 +1151,7 @@ package android.app.usage { method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getAppStandbyBucket(String); method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public java.util.Map<java.lang.String,java.lang.Integer> getAppStandbyBuckets(); method public int getUsageSource(); - method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent); + method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, android.app.PendingIntent); method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerAppUsageObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent); method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent); method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String); @@ -1529,6 +1535,7 @@ package android.content.pm { method @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) public void setGrantedRuntimePermissions(String[]); method public void setInstallAsInstantApp(boolean); method public void setInstallAsVirtualPreload(); + method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged(); } public class PackageItemInfo { @@ -5739,10 +5746,6 @@ package android.provider { field public static final String SERVICE_ENABLED = "service_enabled"; } - public static interface DeviceConfig.ContentCapture { - field public static final String NAMESPACE = "content_capture"; - } - public static interface DeviceConfig.DexBoot { field public static final String NAMESPACE = "dex_boot"; field public static final String PRIV_APPS_OOB_ENABLED = "priv_apps_oob_enabled"; @@ -5777,6 +5780,11 @@ package android.provider { field public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled"; } + public static interface DeviceConfig.Runtime { + field public static final String NAMESPACE = "runtime"; + field public static final String USE_PRECOMPILED_LAYOUT = "view.precompiled_layout_enabled"; + } + public static interface DeviceConfig.RuntimeNative { field public static final String NAMESPACE = "runtime_native"; } @@ -5785,6 +5793,11 @@ package android.provider { field public static final String NAMESPACE = "runtime_native_boot"; } + public static interface DeviceConfig.Scheduler { + field public static final String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection"; + field public static final String NAMESPACE = "scheduler"; + } + public static interface DeviceConfig.Storage { field public static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled"; field public static final String NAMESPACE = "storage"; @@ -7017,6 +7030,7 @@ package android.telephony { method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getExcludedCarriers(); method public int getMultiSimPolicy(); method public boolean isAllCarriersAllowed(); + method public java.util.List<java.lang.Boolean> isCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>); method public void writeToParcel(android.os.Parcel, int); field public static final int CARRIER_RESTRICTION_DEFAULT_ALLOWED = 1; // 0x1 field public static final int CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED = 0; // 0x0 @@ -7746,6 +7760,7 @@ package android.telephony { method public void requestEmbeddedSubscriptionInfoListRefresh(int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultDataSubId(int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultSmsSubId(int); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPreferredDataSubscriptionId(int, boolean, @NonNull java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSubscriptionEnabled(int, boolean); field public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI; field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff @@ -7832,6 +7847,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isMultisimCarrierRestricted(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isRebootRequiredForModemConfigChange(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging(); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled(); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle); diff --git a/api/test-current.txt b/api/test-current.txt index 2c8d08c49fdb..1a7e4cb83c52 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -17,8 +17,9 @@ package android { field public static final String WRITE_OBB = "android.permission.WRITE_OBB"; } - public static final class R.array { - field public static final int config_defaultRoleHolders = 17235974; // 0x1070006 + public static final class R.string { + field public static final int config_defaultAssistant = 17039393; // 0x1040021 + field public static final int config_defaultDialer = 17039395; // 0x1040023 } } @@ -1784,8 +1785,17 @@ package android.provider { } public final class DeviceConfig { + method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener); + method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(String, String); + method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static void resetToDefaults(int, @Nullable String); method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static boolean setProperty(String, String, String, boolean); + field public static final String NAMESPACE_AUTOFILL = "autofill"; + field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; + } + + public static interface DeviceConfig.OnPropertyChangedListener { + method public void onPropertyChanged(String, String, String); } public static interface DeviceConfig.Privacy { @@ -1810,7 +1820,6 @@ package android.provider { public static final class Settings.Global extends android.provider.Settings.NameValueTable { field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages"; - field public static final String AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS = "autofill_smart_suggestion_emulation_flags"; field public static final String AUTOMATIC_POWER_SAVER_MODE = "automatic_power_saver_mode"; field public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS = "captive_portal_fallback_probe_specs"; field public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url"; @@ -1853,6 +1862,7 @@ package android.provider { field @Deprecated public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = "enabled_notification_policy_access_packages"; field public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS = "location_access_check_delay_millis"; field public static final String LOCATION_ACCESS_CHECK_INTERVAL_MILLIS = "location_access_check_interval_millis"; + field public static final String NOTIFICATION_BADGING = "notification_badging"; field public static final String NOTIFICATION_BUBBLES = "notification_bubbles"; field @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds"; field public static final String USER_SETUP_COMPLETE = "user_setup_complete"; @@ -2152,6 +2162,10 @@ package android.telecom { ctor public CallAudioState(boolean, int, int, @Nullable android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.bluetooth.BluetoothDevice>); } + public abstract class Conference extends android.telecom.Conferenceable { + method public android.telecom.Connection getPrimaryConnection(); + } + public final class PhoneAccountSuggestion implements android.os.Parcelable { ctor public PhoneAccountSuggestion(android.telecom.PhoneAccountHandle, int, boolean); } @@ -2164,6 +2178,16 @@ package android.telecom { field public static final String SERVICE_INTERFACE = "android.telecom.PhoneAccountSuggestionService"; } + public class TelecomManager { + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCurrentTtyMode(); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall(); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(android.telecom.PhoneAccountHandle); + field public static final int TTY_MODE_FULL = 1; // 0x1 + field public static final int TTY_MODE_HCO = 2; // 0x2 + field public static final int TTY_MODE_OFF = 0; // 0x0 + field public static final int TTY_MODE_VCO = 3; // 0x3 + } + } package android.telephony { @@ -2676,6 +2700,8 @@ package android.view.autofill { public final class AutofillManager { method public void setAugmentedAutofillWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>); + field public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = "smart_suggestion_supported_modes"; + field public static final int FLAG_SMART_SUGGESTION_OFF = 0; // 0x0 field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1 field public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 120000; // 0x1d4c0 } @@ -2717,6 +2743,7 @@ package android.view.contentcapture { public final class ContentCaptureManager { method public boolean isContentCaptureFeatureEnabled(); method public void setContentCaptureFeatureEnabled(boolean); + field public static final String DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED = "service_explicitly_enabled"; } public final class ViewNode extends android.app.assist.AssistStructure.ViewNode { diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp index 2fef407a8e3f..d757e4611158 100644 --- a/cmds/idmap2/Android.bp +++ b/cmds/idmap2/Android.bp @@ -56,6 +56,7 @@ cc_library { shared_libs: [ "libandroidfw", "libbase", + "libcutils", "libutils", "libziparchive", ], @@ -150,6 +151,7 @@ cc_binary { shared_libs: [ "libandroidfw", "libbase", + "libcutils", "libidmap2", "libutils", "libziparchive", diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp index 0c581f3b1a98..6703909d887e 100644 --- a/cmds/idmap2/idmap2/Create.cpp +++ b/cmds/idmap2/idmap2/Create.cpp @@ -29,6 +29,7 @@ #include "idmap2/Idmap.h" #include "idmap2/Policies.h" #include "idmap2/Result.h" +#include "idmap2/SysTrace.h" using android::ApkAssets; using android::idmap2::BinaryStreamVisitor; @@ -42,6 +43,7 @@ using android::idmap2::utils::kIdmapFilePermissionMask; using android::idmap2::utils::UidHasWriteAccessToPath; bool Create(const std::vector<std::string>& args, std::ostream& out_error) { + SYSTRACE << "Create " << args; std::string target_apk_path; std::string overlay_apk_path; std::string idmap_path; diff --git a/cmds/idmap2/idmap2/Dump.cpp b/cmds/idmap2/idmap2/Dump.cpp index c8cdcfa6d3dc..3947703fe8da 100644 --- a/cmds/idmap2/idmap2/Dump.cpp +++ b/cmds/idmap2/idmap2/Dump.cpp @@ -24,6 +24,7 @@ #include "idmap2/Idmap.h" #include "idmap2/PrettyPrintVisitor.h" #include "idmap2/RawPrintVisitor.h" +#include "idmap2/SysTrace.h" using android::idmap2::CommandLineOptions; using android::idmap2::Idmap; @@ -31,6 +32,7 @@ using android::idmap2::PrettyPrintVisitor; using android::idmap2::RawPrintVisitor; bool Dump(const std::vector<std::string>& args, std::ostream& out_error) { + SYSTRACE << "Dump " << args; std::string idmap_path; bool verbose; diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp index cfb5dd5b30a9..553d8cac99e4 100644 --- a/cmds/idmap2/idmap2/Lookup.cpp +++ b/cmds/idmap2/idmap2/Lookup.cpp @@ -37,6 +37,7 @@ #include "idmap2/CommandLineOptions.h" #include "idmap2/Idmap.h" #include "idmap2/Result.h" +#include "idmap2/SysTrace.h" #include "idmap2/Xml.h" #include "idmap2/ZipFile.h" @@ -156,6 +157,7 @@ Result<std::string> GetTargetPackageNameFromManifest(const std::string& apk_path } // namespace bool Lookup(const std::vector<std::string>& args, std::ostream& out_error) { + SYSTRACE << "Lookup " << args; std::vector<std::string> idmap_paths; std::string config_str; std::string resid_str; diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp index 445fac52f997..a0ffccb26dfe 100644 --- a/cmds/idmap2/idmap2/Main.cpp +++ b/cmds/idmap2/idmap2/Main.cpp @@ -24,6 +24,7 @@ #include <vector> #include "idmap2/CommandLineOptions.h" +#include "idmap2/SysTrace.h" #include "Commands.h" @@ -48,6 +49,7 @@ void PrintUsage(const NameToFunctionMap& commands, std::ostream& out) { } // namespace int main(int argc, char** argv) { + SYSTRACE << "main"; const NameToFunctionMap commands = { {"create", Create}, {"dump", Dump}, {"lookup", Lookup}, {"scan", Scan}, {"verify", Verify}, }; diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp index b1ed42a3e624..873779f386f5 100644 --- a/cmds/idmap2/idmap2/Scan.cpp +++ b/cmds/idmap2/idmap2/Scan.cpp @@ -30,6 +30,7 @@ #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" #include "idmap2/ResourceUtils.h" +#include "idmap2/SysTrace.h" #include "idmap2/Xml.h" #include "idmap2/ZipFile.h" @@ -67,6 +68,7 @@ bool VendorIsQOrLater() { std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs, bool recursive, std::ostream& out_error) { + SYSTRACE << "FindApkFiles " << dirs << " " << recursive; const auto predicate = [](unsigned char type, const std::string& path) -> bool { static constexpr size_t kExtLen = 4; // strlen(".apk") return type == DT_REG && path.size() > kExtLen && @@ -104,6 +106,7 @@ PolicyBitmask PolicyForPath(const std::string& apk_path) { } // namespace bool Scan(const std::vector<std::string>& args, std::ostream& out_error) { + SYSTRACE << "Scan " << args; std::vector<std::string> input_directories; std::string target_package_name; std::string target_apk_path; diff --git a/cmds/idmap2/idmap2/Verify.cpp b/cmds/idmap2/idmap2/Verify.cpp index 4d4a0e769174..d8fe7aa0ed99 100644 --- a/cmds/idmap2/idmap2/Verify.cpp +++ b/cmds/idmap2/idmap2/Verify.cpp @@ -21,11 +21,13 @@ #include "idmap2/CommandLineOptions.h" #include "idmap2/Idmap.h" +#include "idmap2/SysTrace.h" using android::idmap2::CommandLineOptions; using android::idmap2::IdmapHeader; bool Verify(const std::vector<std::string>& args, std::ostream& out_error) { + SYSTRACE << "Verify " << args; std::string idmap_path; const CommandLineOptions opts = diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index f30ce9b08d6e..0e4bd89e355c 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -29,13 +29,13 @@ #include "android-base/stringprintf.h" #include "binder/IPCThreadState.h" #include "utils/String8.h" -#include "utils/Trace.h" #include "idmap2/BinaryStreamVisitor.h" #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" #include "idmap2/Policies.h" #include "idmap2/Result.h" +#include "idmap2/SysTrace.h" #include "idmap2d/Idmap2Service.h" @@ -72,6 +72,7 @@ namespace android::os { Status Idmap2Service::getIdmapPath(const std::string& overlay_apk_path, int32_t user_id ATTRIBUTE_UNUSED, std::string* _aidl_return) { assert(_aidl_return); + SYSTRACE << "Idmap2Service::getIdmapPath " << overlay_apk_path; *_aidl_return = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path); return ok(); } @@ -79,6 +80,7 @@ Status Idmap2Service::getIdmapPath(const std::string& overlay_apk_path, Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path, int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) { assert(_aidl_return); + SYSTRACE << "Idmap2Service::removeIdmap " << overlay_apk_path; const uid_t uid = IPCThreadState::self()->getCallingUid(); const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path); if (!UidHasWriteAccessToPath(uid, idmap_path)) { @@ -98,6 +100,7 @@ Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path, int32_t fulfilled_policies ATTRIBUTE_UNUSED, bool enforce_overlayable ATTRIBUTE_UNUSED, int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) { + SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_apk_path; assert(_aidl_return); const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path); std::ifstream fin(idmap_path); @@ -113,15 +116,10 @@ Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path, Status Idmap2Service::createIdmap(const std::string& target_apk_path, const std::string& overlay_apk_path, int32_t fulfilled_policies, - bool enforce_overlayable, int32_t user_id, + bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED, std::unique_ptr<std::string>* _aidl_return) { assert(_aidl_return); - std::stringstream trace; - trace << __FUNCTION__ << " " << target_apk_path << " " << overlay_apk_path << " " - << std::to_string(user_id); - ATRACE_NAME(trace.str().c_str()); - std::cout << trace.str() << std::endl; - + SYSTRACE << "Idmap2Service::createIdmap " << target_apk_path << " " << overlay_apk_path; _aidl_return->reset(nullptr); const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies); diff --git a/cmds/idmap2/include/idmap2/SysTrace.h b/cmds/idmap2/include/idmap2/SysTrace.h new file mode 100644 index 000000000000..19b4353def18 --- /dev/null +++ b/cmds/idmap2/include/idmap2/SysTrace.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef IDMAP2_INCLUDE_IDMAP2_SYSTRACE_H_ +#define IDMAP2_INCLUDE_IDMAP2_SYSTRACE_H_ + +#define ATRACE_TAG ATRACE_TAG_RRO + +#include <sstream> +#include <vector> + +#include "cutils/trace.h" + +namespace android::idmap2::utils { +#ifdef __ANDROID__ + +class ScopedTraceNoStart { + public: + ~ScopedTraceNoStart() { + ATRACE_END(); + } +}; + +class ScopedTraceMessageHelper { + public: + ~ScopedTraceMessageHelper() { + ATRACE_BEGIN(buffer_.str().c_str()); + } + + std::ostream& stream() { + return buffer_; + } + + private: + std::ostringstream buffer_; +}; + +#define SYSTRACE \ + android::idmap2::utils::ScopedTraceNoStart _trace##__LINE__; \ + (ATRACE_ENABLED()) && android::idmap2::utils::ScopedTraceMessageHelper().stream() + +#else + +class DummyStream { + public: + std::ostream& stream() { + return buffer_; + } + + private: + std::ostringstream buffer_; +}; + +#define SYSTRACE android::idmap2::utils::DummyStream().stream() + +#endif +} // namespace android::idmap2::utils + +template <typename T> +std::ostream& operator<<(std::ostream& stream, const std::vector<T>& vector) { + bool first = true; + stream << "["; + for (const auto& item : vector) { + if (!first) { + stream << ", "; + } + stream << item; + first = false; + } + stream << "]"; + return stream; +} + +#endif // IDMAP2_INCLUDE_IDMAP2_SYSTRACE_H_ diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp index b19d7a971cb8..99b5f0ff3c2d 100644 --- a/cmds/idmap2/libidmap2/Idmap.cpp +++ b/cmds/idmap2/libidmap2/Idmap.cpp @@ -34,6 +34,7 @@ #include "idmap2/Idmap.h" #include "idmap2/ResourceUtils.h" #include "idmap2/Result.h" +#include "idmap2/SysTrace.h" #include "idmap2/ZipFile.h" namespace android::idmap2 { @@ -258,6 +259,7 @@ std::string Idmap::CanonicalIdmapPathFor(const std::string& absolute_dir, std::unique_ptr<const Idmap> Idmap::FromBinaryStream(std::istream& stream, std::ostream& out_error) { + SYSTRACE << "Idmap::FromBinaryStream"; std::unique_ptr<Idmap> idmap(new Idmap()); idmap->header_ = IdmapHeader::FromBinaryStream(stream); @@ -304,6 +306,7 @@ std::unique_ptr<const Idmap> Idmap::FromApkAssets( const std::string& target_apk_path, const ApkAssets& target_apk_assets, const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets, const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error) { + SYSTRACE << "Idmap::FromApkAssets"; AssetManager2 target_asset_manager; if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true, false)) { out_error << "error: failed to create target asset manager" << std::endl; diff --git a/cmds/incidentd/Android.bp b/cmds/incidentd/Android.bp index 40da583e4f6c..3dc10939fed7 100644 --- a/cmds/incidentd/Android.bp +++ b/cmds/incidentd/Android.bp @@ -94,8 +94,10 @@ cc_test { data: ["testdata/**/*"], - static_libs: ["libgmock"], - + static_libs: [ + "libgmock", + "libplatformprotos", + ], shared_libs: [ "libbase", "libbinder", diff --git a/cmds/incidentd/tests/Reporter_test.cpp b/cmds/incidentd/tests/Reporter_test.cpp index f54f738fb62b..b5e41d767295 100644 --- a/cmds/incidentd/tests/Reporter_test.cpp +++ b/cmds/incidentd/tests/Reporter_test.cpp @@ -35,6 +35,16 @@ using namespace std; using ::testing::StrEq; using ::testing::Test; +namespace { +void getHeaderData(const IncidentHeaderProto& headerProto, vector<uint8_t>* out) { + out->clear(); + auto serialized = headerProto.SerializeAsString(); + if (serialized.empty()) return; + out->resize(serialized.length()); + std::copy(serialized.begin(), serialized.end(), out->begin()); +} +} + class TestListener : public IIncidentReportStatusListener { public: int startInvoked; @@ -143,7 +153,10 @@ TEST_F(ReporterTest, RunReportWithHeaders) { args2.addSection(2); IncidentHeaderProto header; header.set_alert_id(12); - args2.addHeader(header); + + vector<uint8_t> out; + getHeaderData(header, &out); + args2.addHeader(out); sp<ReportRequest> r1 = new ReportRequest(args1, l, tf.fd); sp<ReportRequest> r2 = new ReportRequest(args2, l, tf.fd); @@ -169,8 +182,12 @@ TEST_F(ReporterTest, RunReportToGivenDirectory) { IncidentHeaderProto header1, header2; header1.set_alert_id(12); header2.set_reason("abcd"); - args.addHeader(header1); - args.addHeader(header2); + + vector<uint8_t> out; + getHeaderData(header1, &out); + args.addHeader(out); + getHeaderData(header2, &out); + args.addHeader(out); sp<ReportRequest> r = new ReportRequest(args, l, -1); reporter->batch.add(r); diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp index 9b684a060286..24454ed15d40 100644 --- a/cmds/incidentd/tests/Section_test.cpp +++ b/cmds/incidentd/tests/Section_test.cpp @@ -82,6 +82,16 @@ protected: virtual IBinder* onAsBinder() override { return nullptr; }; }; +namespace { +void getHeaderData(const IncidentHeaderProto& headerProto, vector<uint8_t>* out) { + out->clear(); + auto serialized = headerProto.SerializeAsString(); + if (serialized.empty()) return; + out->resize(serialized.length()); + std::copy(serialized.begin(), serialized.end(), out->begin()); +} +} + TEST_F(SectionTest, HeaderSection) { HeaderSection hs; @@ -94,9 +104,15 @@ TEST_F(SectionTest, HeaderSection) { head1.set_reason("axe"); head2.set_reason("pup"); - args1.addHeader(head1); - args1.addHeader(head2); - args2.addHeader(head2); + vector<uint8_t> out; + getHeaderData(head1, &out); + args1.addHeader(out); + + getHeaderData(head2, &out); + args1.addHeader(out); + + getHeaderData(head2, &out); + args2.addHeader(out); requests.add(new ReportRequest(args1, new SimpleListener(), -1)); requests.add(new ReportRequest(args2, new SimpleListener(), tf.fd)); diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index d6f045ea43fd..faf2053835fa 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -71,6 +71,7 @@ cc_defaults { "src/external/Perfetto.cpp", "src/external/Perfprofd.cpp", "src/external/StatsPuller.cpp", + "src/external/StatsCallbackPuller.cpp", "src/external/StatsCompanionServicePuller.cpp", "src/external/SubsystemSleepStatePuller.cpp", "src/external/PowerStatsPuller.cpp", diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index 250f5bfd0685..dd18bd4cc8ad 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -526,9 +526,10 @@ void StatsLogProcessor::WriteMetricsActivationToDisk(int64_t currentTimeNs) { proto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_ID, (long long)pair.first.GetId()); proto.write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_UID, pair.first.GetUid()); - vector<const MetricProducer*> acrtiveMetrics; - pair.second->getActiveMetrics(acrtiveMetrics); - for (const MetricProducer* metric : acrtiveMetrics) { + vector<MetricProducer*> activeMetrics; + pair.second->prepForShutDown(currentTimeNs); + pair.second->getActiveMetrics(activeMetrics); + for (MetricProducer* metric : activeMetrics) { if (metric->isActive()) { uint64_t metricToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_ACTIVE_METRIC); diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 77d9a2f5f418..caf1a713986d 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -195,6 +195,7 @@ private: FRIEND_TEST(StatsLogProcessorTest, TestRateLimitBroadcast); FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge); FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead); + FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot); FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1); FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2); diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 86bf3eca3ee6..bd21a955729d 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -1057,6 +1057,24 @@ Status StatsService::sendAppBreadcrumbAtom(int32_t label, int32_t state) { return Status::ok(); } +Status StatsService::registerPullerCallback(int32_t atomTag, + const sp<android::os::IStatsPullerCallback>& pullerCallback, + const String16& packageName) { + ENFORCE_DUMP_AND_USAGE_STATS(packageName); + + VLOG("StatsService::registerPullerCallback called."); + mPullerManager->RegisterPullerCallback(atomTag, pullerCallback); + return Status::ok(); +} + +Status StatsService::unregisterPullerCallback(int32_t atomTag, const String16& packageName) { + ENFORCE_DUMP_AND_USAGE_STATS(packageName); + + VLOG("StatsService::unregisterPullerCallback called."); + mPullerManager->UnregisterPullerCallback(atomTag); + return Status::ok(); +} + hardware::Return<void> StatsService::reportSpeakerImpedance( const SpeakerImpedance& speakerImpedance) { LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), speakerImpedance); diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index cdff50fcb62e..941ed462b303 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -173,6 +173,19 @@ public: virtual Status sendAppBreadcrumbAtom(int32_t label, int32_t state) override; /** + * Binder call to register a callback function for a vendor pulled atom. + * Note: this atom must NOT have uid as a field. + */ + virtual Status registerPullerCallback(int32_t atomTag, + const sp<android::os::IStatsPullerCallback>& pullerCallback, + const String16& packageName) override; + + /** + * Binder call to unregister any existing callback function for a vendor pulled atom. + */ + virtual Status unregisterPullerCallback(int32_t atomTag, const String16& packageName) override; + + /** * Binder call to get SpeakerImpedance atom. */ virtual Return<void> reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) override; diff --git a/cmds/statsd/src/anomaly/subscriber_util.cpp b/cmds/statsd/src/anomaly/subscriber_util.cpp index ad5eae361f1c..6b46b8b3b900 100644 --- a/cmds/statsd/src/anomaly/subscriber_util.cpp +++ b/cmds/statsd/src/anomaly/subscriber_util.cpp @@ -23,7 +23,6 @@ #include "external/Perfetto.h" #include "external/Perfprofd.h" -#include "frameworks/base/libs/incident/proto/android/os/header.pb.h" #include "subscriber/IncidentdReporter.h" #include "subscriber/SubscriberReporter.h" diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index d0974d6e3398..da7e4daaf22b 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -215,7 +215,7 @@ message Atom { SpeechDspStatReported speech_dsp_stat_reported = 145; UsbContaminantReported usb_contaminant_reported = 146; WatchdogRollbackOccurred watchdog_rollback_occurred = 147; - BiometricHalDeathReported biometric_hal_death_reported = 148; + BiometricSystemHealthIssueDetected biometric_system_health_issue_detected = 148; BubbleUIChanged bubble_ui_changed = 149; ScheduledJobConstraintChanged scheduled_job_constraint_changed = 150; BluetoothActiveDeviceChanged bluetooth_active_device_changed = 151; @@ -297,6 +297,7 @@ message Atom { NumBiometricsEnrolled num_faces_enrolled = 10048; RoleHolder role_holder = 10049; DangerousPermissionState dangerous_permission_state = 10050; + TrainInfo train_info = 10051; } // DO NOT USE field numbers above 100,000 in AOSP. @@ -2086,9 +2087,9 @@ message BluetoothSocketConnectionStateChanged { // Salt: Randomly generated 256 bit value // Hash algorithm: HMAC-SHA256 // Size: 32 byte - // Default: null or empty if the device identifier is not known + // Default: null or empty if this is a server listener socket optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES]; - // Port of this socket + // Temporary port of this socket for the current connection or session only // Default 0 when unknown or don't care optional int32 port = 2; // Socket type as mentioned in @@ -2102,6 +2103,14 @@ message BluetoothSocketConnectionStateChanged { optional int64 tx_bytes = 5; // Number of bytes received from remote device during this connection optional int64 rx_bytes = 6; + // Socket owner's UID + optional int32 uid = 7 [(is_uid) = true]; + // Server port of this socket, if any. When both |server_port| and |port| fields are populated, + // |port| must be spawned by |server_port| + // Default 0 when unknown or don't care + optional int32 server_port = 8; + // Whether this is a server listener socket + optional android.bluetooth.SocketRoleEnum is_server = 9; } /** @@ -2168,6 +2177,7 @@ message HardwareFailed { SPEAKER_SHORT = 3; FINGERPRINT_SENSOR_BROKEN = 4; FINGERPRINT_TOO_MANY_DEAD_PIXELS = 5; + DEGRADE = 6; } optional int32 failure_code = 3; } @@ -3050,13 +3060,15 @@ message BiometricErrorOccurred { } /** - * Logs when a biometric HAL has crashed. + * Logs when a system health issue is detected. * Logged from: * frameworks/base/services/core/java/com/android/server/biometrics */ -message BiometricHalDeathReported { +message BiometricSystemHealthIssueDetected { // Biometric modality. optional android.hardware.biometrics.ModalityEnum modality = 1; + // Type of issue detected. + optional android.hardware.biometrics.IssueEnum issue = 2; } message Notification { @@ -5493,3 +5505,20 @@ message DeviceIdentifierAccessDenied { // True if the package is privileged. optional bool is_priv_app = 4; } + +/** + * Potential experiment ids that goes with a train install. + */ +message TrainExperimentIds { + repeated int64 experiment_id = 1; +} + +/** + * Pulls the ongoing mainline install train version code. + * Pulled from StatsCompanionService + */ +message TrainInfo { + optional int64 train_version_code = 1; + + optional TrainExperimentIds train_experiment_id = 2; +} diff --git a/cmds/statsd/src/external/PullDataReceiver.h b/cmds/statsd/src/external/PullDataReceiver.h index b071682f8a59..d2193f41b80a 100644 --- a/cmds/statsd/src/external/PullDataReceiver.h +++ b/cmds/statsd/src/external/PullDataReceiver.h @@ -32,9 +32,10 @@ class PullDataReceiver : virtual public RefBase{ * @param data The pulled data. * @param pullSuccess Whether the pull succeeded. If the pull does not succeed, the data for the * bucket should be invalidated. + * @param originalPullTimeNs This is when all the pulls have been initiated (elapsed time). */ virtual void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data, - bool pullSuccess) = 0; + bool pullSuccess, int64_t originalPullTimeNs) = 0; }; } // namespace statsd diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp new file mode 100644 index 000000000000..d718273e9b85 --- /dev/null +++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2019 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. + */ + +#define DEBUG false // STOPSHIP if true +#include "Log.h" + +#include <android/os/IStatsPullerCallback.h> + +#include "StatsCallbackPuller.h" +#include "logd/LogEvent.h" +#include "stats_log_util.h" + +using namespace android::binder; + +namespace android { +namespace os { +namespace statsd { + +StatsCallbackPuller::StatsCallbackPuller(int tagId, const sp<IStatsPullerCallback>& callback) : + StatsPuller(tagId), mCallback(callback) { + VLOG("StatsCallbackPuller created for tag %d", tagId); +} + +bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) { + VLOG("StatsCallbackPuller called for tag %d", mTagId) + if(mCallback == nullptr) { + ALOGW("No callback registered"); + return false; + } + int64_t wallClockTimeNs = getWallClockNs(); + int64_t elapsedTimeNs = getElapsedRealtimeNs(); + vector<StatsLogEventWrapper> returned_value; + Status status = mCallback->pullData(mTagId, elapsedTimeNs, wallClockTimeNs, &returned_value); + if (!status.isOk()) { + ALOGW("StatsCallbackPuller::pull failed for %d", mTagId); + return false; + } + data->clear(); + for (const StatsLogEventWrapper& it: returned_value) { + LogEvent::createLogEvents(it, *data); + } + VLOG("StatsCallbackPuller::pull succeeded for %d", mTagId); + return true; +} + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/external/StatsCallbackPuller.h b/cmds/statsd/src/external/StatsCallbackPuller.h new file mode 100644 index 000000000000..c4bfa89ba9a7 --- /dev/null +++ b/cmds/statsd/src/external/StatsCallbackPuller.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 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 <android/os/IStatsPullerCallback.h> +#include <utils/String16.h> +#include "StatsPuller.h" + +namespace android { +namespace os { +namespace statsd { + +class StatsCallbackPuller : public StatsPuller { +public: + explicit StatsCallbackPuller(int tagId, const sp<IStatsPullerCallback>& callback); + +private: + bool PullInternal(vector<std::shared_ptr<LogEvent> >* data) override; + const sp<IStatsPullerCallback> mCallback; +}; + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp index c7c22ee85f0f..9552c0a5e35e 100644 --- a/cmds/statsd/src/external/StatsPuller.cpp +++ b/cmds/statsd/src/external/StatsPuller.cpp @@ -33,7 +33,7 @@ sp<UidMap> StatsPuller::mUidMap = nullptr; void StatsPuller::SetUidMap(const sp<UidMap>& uidMap) { mUidMap = uidMap; } StatsPuller::StatsPuller(const int tagId) - : mTagId(tagId) { + : mTagId(tagId), mLastPullTimeNs(0) { } bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) { diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 9b603d6c7957..ed72b2914a34 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -18,6 +18,7 @@ #include "Log.h" #include <android/os/IStatsCompanionService.h> +#include <android/os/IStatsPullerCallback.h> #include <cutils/log.h> #include <math.h> #include <stdint.h> @@ -29,6 +30,7 @@ #include "PowerStatsPuller.h" #include "ResourceHealthManagerPuller.h" #include "StatsCompanionServicePuller.h" +#include "StatsCallbackPuller.h" #include "StatsPullerManager.h" #include "SubsystemSleepStatePuller.h" #include "statslog.h" @@ -49,7 +51,7 @@ namespace statsd { // Values smaller than this may require to update the alarm. const int64_t NO_ALARM_UPDATE = INT64_MAX; -const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { +std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // wifi_bytes_transfer {android::util::WIFI_BYTES_TRANSFER, {.additiveFields = {2, 3, 4, 5}, @@ -174,9 +176,12 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // Size of specific categories of files. Eg. Music. {android::util::CATEGORY_SIZE, {.puller = new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}}, - // Number of fingerprints registered to each user. + // Number of fingerprints enrolled for each user. {android::util::NUM_FINGERPRINTS_ENROLLED, {.puller = new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS_ENROLLED)}}, + // Number of faces enrolled for each user. + {android::util::NUM_FACES_ENROLLED, + {.puller = new StatsCompanionServicePuller(android::util::NUM_FACES_ENROLLED)}}, // ProcStats. {android::util::PROC_STATS, {.puller = new StatsCompanionServicePuller(android::util::PROC_STATS)}}, @@ -381,7 +386,7 @@ void StatsPullerManager::OnAlarmFired(int64_t elapsedTimeNs) { for (const auto& receiverInfo : pullInfo.second) { sp<PullDataReceiver> receiverPtr = receiverInfo->receiver.promote(); if (receiverPtr != nullptr) { - receiverPtr->onDataPulled(data, pullSuccess); + receiverPtr->onDataPulled(data, pullSuccess, elapsedTimeNs); // We may have just come out of a coma, compute next pull time. int numBucketsAhead = (elapsedTimeNs - receiverInfo->nextPullTimeNs) / receiverInfo->intervalNs; @@ -417,6 +422,30 @@ int StatsPullerManager::ClearPullerCacheIfNecessary(int64_t timestampNs) { return totalCleared; } +void StatsPullerManager::RegisterPullerCallback(int32_t atomTag, + const sp<IStatsPullerCallback>& callback) { + AutoMutex _l(mLock); + // Platform pullers cannot be changed. + if (atomTag < StatsdStats::kMaxPlatformAtomTag) { + VLOG("RegisterPullerCallback: atom tag %d is less than min tag %d", + atomTag, StatsdStats::kMaxPlatformAtomTag); + return; + } + VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag); + StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true); + kAllPullAtomInfo[atomTag] = {.puller = new StatsCallbackPuller(atomTag, callback)}; +} + +void StatsPullerManager::UnregisterPullerCallback(int32_t atomTag) { + AutoMutex _l(mLock); + // Platform pullers cannot be changed. + if (atomTag < StatsdStats::kMaxPlatformAtomTag) { + return; + } + StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/false); + kAllPullAtomInfo.erase(atomTag); +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h index 807e4af03dae..45f6b3568143 100644 --- a/cmds/statsd/src/external/StatsPullerManager.h +++ b/cmds/statsd/src/external/StatsPullerManager.h @@ -17,6 +17,7 @@ #pragma once #include <android/os/IStatsCompanionService.h> +#include <android/os/IStatsPullerCallback.h> #include <binder/IServiceManager.h> #include <utils/RefBase.h> #include <utils/threads.h> @@ -91,7 +92,12 @@ public: void SetStatsCompanionService(sp<IStatsCompanionService> statsCompanionService); - const static std::map<int, PullAtomInfo> kAllPullAtomInfo; + void RegisterPullerCallback(int32_t atomTag, + const sp<IStatsPullerCallback>& callback); + + void UnregisterPullerCallback(int32_t atomTag); + + static std::map<int, PullAtomInfo> kAllPullAtomInfo; private: sp<IStatsCompanionService> mStatsCompanionService = nullptr; diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp index 37d5ba0e6801..40329b7c86ab 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.cpp +++ b/cmds/statsd/src/guardrail/StatsdStats.cpp @@ -423,41 +423,59 @@ void StatsdStats::noteEmptyData(int atomId) { mPulledAtomStats[atomId].emptyData++; } -void StatsdStats::noteHardDimensionLimitReached(int metricId) { +void StatsdStats::notePullerCallbackRegistrationChanged(int atomId, bool registered) { + lock_guard<std::mutex> lock(mLock); + if (registered) { + mPulledAtomStats[atomId].registeredCount++; + } else { + mPulledAtomStats[atomId].unregisteredCount++; + } +} + +void StatsdStats::noteHardDimensionLimitReached(int64_t metricId) { lock_guard<std::mutex> lock(mLock); getAtomMetricStats(metricId).hardDimensionLimitReached++; } -void StatsdStats::noteLateLogEventSkipped(int metricId) { +void StatsdStats::noteLateLogEventSkipped(int64_t metricId) { lock_guard<std::mutex> lock(mLock); getAtomMetricStats(metricId).lateLogEventSkipped++; } -void StatsdStats::noteSkippedForwardBuckets(int metricId) { +void StatsdStats::noteSkippedForwardBuckets(int64_t metricId) { lock_guard<std::mutex> lock(mLock); getAtomMetricStats(metricId).skippedForwardBuckets++; } -void StatsdStats::noteBadValueType(int metricId) { +void StatsdStats::noteBadValueType(int64_t metricId) { lock_guard<std::mutex> lock(mLock); getAtomMetricStats(metricId).badValueType++; } -void StatsdStats::noteBucketDropped(int metricId) { +void StatsdStats::noteBucketDropped(int64_t metricId) { lock_guard<std::mutex> lock(mLock); getAtomMetricStats(metricId).bucketDropped++; } -void StatsdStats::noteConditionChangeInNextBucket(int metricId) { +void StatsdStats::noteConditionChangeInNextBucket(int64_t metricId) { lock_guard<std::mutex> lock(mLock); getAtomMetricStats(metricId).conditionChangeInNextBucket++; } -void StatsdStats::noteInvalidatedBucket(int metricId) { +void StatsdStats::noteInvalidatedBucket(int64_t metricId) { lock_guard<std::mutex> lock(mLock); getAtomMetricStats(metricId).invalidatedBucket++; } +void StatsdStats::noteBucketBoundaryDelayNs(int64_t metricId, int64_t timeDelayNs) { + lock_guard<std::mutex> lock(mLock); + AtomMetricStats& pullStats = getAtomMetricStats(metricId); + pullStats.maxBucketBoundaryDelayNs = + std::max(pullStats.maxBucketBoundaryDelayNs, timeDelayNs); + pullStats.minBucketBoundaryDelayNs = + std::min(pullStats.minBucketBoundaryDelayNs, timeDelayNs); +} + StatsdStats::AtomMetricStats& StatsdStats::getAtomMetricStats(int metricId) { auto atomMetricStatsIter = mAtomMetricStats.find(metricId); if (atomMetricStatsIter != mAtomMetricStats.end()) { @@ -505,6 +523,8 @@ void StatsdStats::resetInternalLocked() { pullStats.second.dataError = 0; pullStats.second.pullTimeout = 0; pullStats.second.pullExceedMaxDelay = 0; + pullStats.second.registeredCount = 0; + pullStats.second.unregisteredCount = 0; } mAtomMetricStats.clear(); } @@ -616,12 +636,14 @@ void StatsdStats::dumpStats(int out) const { " (average pull time nanos)%lld, (max pull time nanos)%lld, (average pull delay " "nanos)%lld, " " (max pull delay nanos)%lld, (data error)%ld\n" - " (pull timeout)%ld, (pull exceed max delay)%ld\n", + " (pull timeout)%ld, (pull exceed max delay)%ld\n" + " (registered count) %ld, (unregistered count) %ld\n", (int)pair.first, (long)pair.second.totalPull, (long)pair.second.totalPullFromCache, (long)pair.second.minPullIntervalSec, (long long)pair.second.avgPullTimeNs, (long long)pair.second.maxPullTimeNs, (long long)pair.second.avgPullDelayNs, (long long)pair.second.maxPullDelayNs, pair.second.dataError, - pair.second.pullTimeout, pair.second.pullExceedMaxDelay); + pair.second.pullTimeout, pair.second.pullExceedMaxDelay, + pair.second.registeredCount, pair.second.unregisteredCount); } if (mAnomalyAlarmRegisteredStats > 0) { diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h index 20ea7e5df1fa..65e8a324d7d3 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -146,6 +146,10 @@ public: // Max time to do a pull. static const int64_t kPullMaxDelayNs = 10 * NS_PER_SEC; + + // Max platform atom tag number. + static const int32_t kMaxPlatformAtomTag = 100000; + /** * Report a new config has been received and report the static stats about the config. * @@ -340,39 +344,52 @@ public: void noteEmptyData(int atomId); /** + * Records that a puller callback for the given atomId was registered or unregistered. + * + * @param registered True if the callback was registered, false if was unregistered. + */ + void notePullerCallbackRegistrationChanged(int atomId, bool registered); + + /** * Hard limit was reached in the cardinality of an atom */ - void noteHardDimensionLimitReached(int atomId); + void noteHardDimensionLimitReached(int64_t metricId); /** * A log event was too late, arrived in the wrong bucket and was skipped */ - void noteLateLogEventSkipped(int atomId); + void noteLateLogEventSkipped(int64_t metricId); /** * Buckets were skipped as time elapsed without any data for them */ - void noteSkippedForwardBuckets(int atomId); + void noteSkippedForwardBuckets(int64_t metricId); /** * An unsupported value type was received */ - void noteBadValueType(int atomId); + void noteBadValueType(int64_t metricId); /** * Buckets were dropped due to reclaim memory. */ - void noteBucketDropped(int metricId); + void noteBucketDropped(int64_t metricId); /** * A condition change was too late, arrived in the wrong bucket and was skipped */ - void noteConditionChangeInNextBucket(int atomId); + void noteConditionChangeInNextBucket(int64_t metricId); /** * A bucket has been tagged as invalid. */ - void noteInvalidatedBucket(int metricId); + void noteInvalidatedBucket(int64_t metricId); + + /** + * For pulls at bucket boundaries, it represents the misalignment between the real timestamp and + * the end of the bucket. + */ + void noteBucketBoundaryDelayNs(int64_t metricId, int64_t timeDelayNs); /** * Reset the historical stats. Including all stats in icebox, and the tracked stats about @@ -410,6 +427,8 @@ public: long statsCompanionPullFailed = 0; long statsCompanionPullBinderTransactionFailed = 0; long emptyData = 0; + long registeredCount = 0; + long unregisteredCount = 0; } PulledAtomStats; typedef struct { @@ -420,6 +439,8 @@ public: long conditionChangeInNextBucket = 0; long invalidatedBucket = 0; long bucketDropped = 0; + int64_t minBucketBoundaryDelayNs = 0; + int64_t maxBucketBoundaryDelayNs = 0; } AtomMetricStats; private: @@ -503,6 +524,7 @@ private: FRIEND_TEST(StatsdStatsTest, TestAnomalyMonitor); FRIEND_TEST(StatsdStatsTest, TestSystemServerCrash); FRIEND_TEST(StatsdStatsTest, TestPullAtomStats); + FRIEND_TEST(StatsdStatsTest, TestAtomMetricsStats); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp index 2609937924ac..d56a355f15d6 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -407,7 +407,7 @@ std::shared_ptr<vector<FieldValue>> GaugeMetricProducer::getGaugeFields(const Lo } void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData, - bool pullSuccess) { + bool pullSuccess, int64_t originalPullTimeNs) { std::lock_guard<std::mutex> lock(mMutex); if (!pullSuccess || allData.size() == 0) { return; diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h index d480941ed311..64a18337481b 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.h +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h @@ -68,7 +68,7 @@ public: // Handles when the pulled data arrives. void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data, - bool pullSuccess) override; + bool pullSuccess, int64_t originalPullTimeNs) override; // GaugeMetric needs to immediately trigger another pull when we create the partial bucket. void notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk, const int uid, diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp index b362e37cd194..495138ee9b77 100644 --- a/cmds/statsd/src/metrics/MetricProducer.cpp +++ b/cmds/statsd/src/metrics/MetricProducer.cpp @@ -107,6 +107,10 @@ void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedT if (it == mEventActivationMap.end()) { return; } + if (mActivationType == MetricActivation::ACTIVATE_ON_BOOT) { + it->second.state = ActivationState::kActiveOnBoot; + return; + } it->second.activation_ns = elapsedTimestampNs; it->second.state = ActivationState::kActive; mIsActive = true; @@ -116,12 +120,19 @@ void MetricProducer::setActiveLocked(int64_t currentTimeNs, int64_t remainingTtl if (mEventActivationMap.size() == 0) { return; } - auto& activation = mEventActivationMap.begin()->second; - activation.activation_ns = currentTimeNs + remainingTtlNs - activation.ttl_ns; - activation.state = kActive; - mIsActive = true; - VLOG("setting new activation time to %lld, %lld, %lld", (long long)activation.activation_ns, - (long long)currentTimeNs, (long long)remainingTtlNs); + for (auto& pair : mEventActivationMap) { + auto& activation = pair.second; + if (activation.ttl_ns >= remainingTtlNs) { + activation.activation_ns = currentTimeNs + remainingTtlNs - activation.ttl_ns; + activation.state = kActive; + mIsActive = true; + VLOG("setting new activation time to %lld, %lld, %lld", + (long long)activation.activation_ns, (long long)currentTimeNs, + (long long)remainingTtlNs); + return; + } + } + ALOGE("Required ttl is longer than all possible activations."); } int64_t MetricProducer::getRemainingTtlNsLocked(int64_t currentTimeNs) const { @@ -135,6 +146,19 @@ int64_t MetricProducer::getRemainingTtlNsLocked(int64_t currentTimeNs) const { return maxTtl; } +void MetricProducer::prepActiveForBootIfNecessaryLocked(int64_t currentTimeNs) { + if (mActivationType != MetricActivation::ACTIVATE_ON_BOOT) { + return; + } + for (auto& activation : mEventActivationMap) { + if (activation.second.state == kActiveOnBoot) { + activation.second.state = kActive; + activation.second.activation_ns = currentTimeNs; + mIsActive = true; + } + } +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index ca37bbb73b45..849cb76ec392 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -37,12 +37,13 @@ namespace statsd { // If the metric has no activation requirement, it will be active once the metric producer is // created. // If the metric needs to be activated by atoms, the metric producer will start -// with kNotActive state, turn to kActive when the activation event arrives, become kNotActive -// when it reaches the duration limit (timebomb). If the activation event arrives again before -// or after it expires, the event producer will be re-activated and ttl will be reset. +// with kNotActive state, turn to kActive or kActiveOnBoot when the activation event arrives, become +// kNotActive when it reaches the duration limit (timebomb). If the activation event arrives again +// before or after it expires, the event producer will be re-activated and ttl will be reset. enum ActivationState { kNotActive = 0, kActive = 1, + kActiveOnBoot = 2, }; // A MetricProducer is responsible for compute one single metrics, creating stats log report, and @@ -218,8 +219,17 @@ public: return isActiveLocked(); } + void prepActiveForBootIfNecessary(int64_t currentTimeNs) { + std::lock_guard<std::mutex> lock(mMutex); + prepActiveForBootIfNecessaryLocked(currentTimeNs); + } + void addActivation(int activationTrackerIndex, int64_t ttl_seconds); + inline void setActivationType(const MetricActivation::ActivationType& activationType) { + mActivationType = activationType; + } + void flushIfExpire(int64_t elapsedTimestampNs); protected: @@ -243,6 +253,8 @@ protected: return mIsActive; } + void prepActiveForBootIfNecessaryLocked(int64_t currentTimeNs); + int64_t getRemainingTtlNsLocked(int64_t currentTimeNs) const; void setActiveLocked(int64_t currentTimeNs, int64_t remainingTtlNs); @@ -367,9 +379,12 @@ protected: bool mIsActive; + MetricActivation::ActivationType mActivationType; + FRIEND_TEST(MetricActivationE2eTest, TestCountMetric); FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead); + FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index fdc28ea7f219..cb1cefbf2063 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -132,7 +132,7 @@ public: return mIsActive; } - inline void getActiveMetrics(std::vector<const MetricProducer*>& metrics) const { + inline void getActiveMetrics(std::vector<MetricProducer*>& metrics) const { for (const auto& metric : mAllMetricProducers) { if (metric->isActive()) { metrics.push_back(metric.get()); @@ -140,6 +140,12 @@ public: } } + inline void prepForShutDown(int64_t currentTimeNs) { + for (const auto& metric : mAllMetricProducers) { + metric->prepActiveForBootIfNecessary(currentTimeNs); + } + } + void setActiveMetrics(ActiveConfig config, int64_t currentTimeNs); private: @@ -271,6 +277,7 @@ private: FRIEND_TEST(MetricActivationE2eTest, TestCountMetric); FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead); + FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index 1bd3ef20a578..851ae9962d09 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -361,34 +361,8 @@ void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) { invalidateCurrentBucket(); return; } - const int64_t pullDelayNs = getElapsedRealtimeNs() - timestampNs; - StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs); - if (pullDelayNs > mMaxPullDelayNs) { - ALOGE("Pull finish too late for atom %d, longer than %lld", mPullTagId, - (long long)mMaxPullDelayNs); - StatsdStats::getInstance().notePullExceedMaxDelay(mPullTagId); - // We are missing one pull from the bucket which means we will not have a complete view of - // what's going on. - invalidateCurrentBucket(); - return; - } - - if (timestampNs < mCurrentBucketStartTimeNs) { - // The data will be skipped in onMatchedLogEventInternalLocked, but we don't want to report - // for every event, just the pull - StatsdStats::getInstance().noteLateLogEventSkipped(mMetricId); - } - for (const auto& data : allData) { - // make a copy before doing and changes - LogEvent localCopy = data->makeCopy(); - localCopy.setElapsedTimestampNs(timestampNs); - if (mEventMatcherWizard->matchLogEvent(localCopy, mWhatMatcherIndex) == - MatchingState::kMatched) { - onMatchedLogEventLocked(mWhatMatcherIndex, localCopy); - } - } - mHasGlobalBase = true; + accumulateEvents(allData, timestampNs, timestampNs); } int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTimeNs) { @@ -396,7 +370,7 @@ int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTime } void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData, - bool pullSuccess) { + bool pullSuccess, int64_t originalPullTimeNs) { std::lock_guard<std::mutex> lock(mMutex); if (mCondition) { if (!pullSuccess) { @@ -405,11 +379,6 @@ void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven return; } - if (allData.size() == 0) { - VLOG("Data pulled is empty"); - StatsdStats::getInstance().noteEmptyData(mPullTagId); - return; - } // For scheduled pulled data, the effective event time is snap to the nearest // bucket end. In the case of waking up from a deep sleep state, we will // attribute to the previous bucket end. If the sleep was long but not very long, we @@ -417,33 +386,83 @@ void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven // we pull at a later time than real bucket end. // If the sleep was very long, we skip more than one bucket before sleep. In this case, // if the diff base will be cleared and this new data will serve as new diff base. - int64_t realEventTime = allData.at(0)->GetElapsedTimestampNs(); - int64_t bucketEndTime = calcPreviousBucketEndTime(realEventTime) - 1; - bool isEventLate = bucketEndTime < mCurrentBucketStartTimeNs; - if (isEventLate) { - VLOG("Skip bucket end pull due to late arrival: %lld vs %lld", (long long)bucketEndTime, - (long long)mCurrentBucketStartTimeNs); - StatsdStats::getInstance().noteLateLogEventSkipped(mMetricId); - } - - for (const auto& data : allData) { - LogEvent localCopy = data->makeCopy(); - if (mEventMatcherWizard->matchLogEvent(localCopy, mWhatMatcherIndex) == - MatchingState::kMatched) { - localCopy.setElapsedTimestampNs(bucketEndTime); - onMatchedLogEventLocked(mWhatMatcherIndex, localCopy); - } - } - mHasGlobalBase = true; + int64_t bucketEndTime = calcPreviousBucketEndTime(originalPullTimeNs) - 1; + StatsdStats::getInstance().noteBucketBoundaryDelayNs( + mMetricId, originalPullTimeNs - bucketEndTime); + accumulateEvents(allData, originalPullTimeNs, bucketEndTime); // We can probably flush the bucket. Since we used bucketEndTime when calling // #onMatchedLogEventInternalLocked, the current bucket will not have been flushed. - flushIfNeededLocked(realEventTime); + flushIfNeededLocked(originalPullTimeNs); + } else { VLOG("No need to commit data on condition false."); } } +void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData, + int64_t originalPullTimeNs, int64_t eventElapsedTimeNs) { + bool isEventLate = eventElapsedTimeNs < mCurrentBucketStartTimeNs; + if (isEventLate) { + VLOG("Skip bucket end pull due to late arrival: %lld vs %lld", + (long long)eventElapsedTimeNs, (long long)mCurrentBucketStartTimeNs); + StatsdStats::getInstance().noteLateLogEventSkipped(mMetricId); + invalidateCurrentBucket(); + return; + } + + const int64_t pullDelayNs = getElapsedRealtimeNs() - originalPullTimeNs; + StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs); + if (pullDelayNs > mMaxPullDelayNs) { + ALOGE("Pull finish too late for atom %d, longer than %lld", mPullTagId, + (long long)mMaxPullDelayNs); + StatsdStats::getInstance().notePullExceedMaxDelay(mPullTagId); + // We are missing one pull from the bucket which means we will not have a complete view of + // what's going on. + invalidateCurrentBucket(); + return; + } + + if (allData.size() == 0) { + VLOG("Data pulled is empty"); + StatsdStats::getInstance().noteEmptyData(mPullTagId); + } + + mMatchedMetricDimensionKeys.clear(); + for (const auto& data : allData) { + LogEvent localCopy = data->makeCopy(); + if (mEventMatcherWizard->matchLogEvent(localCopy, mWhatMatcherIndex) == + MatchingState::kMatched) { + localCopy.setElapsedTimestampNs(eventElapsedTimeNs); + onMatchedLogEventLocked(mWhatMatcherIndex, localCopy); + } + } + // If the new pulled data does not contains some keys we track in our intervals, we need to + // reset the base. + for (auto& slice : mCurrentSlicedBucket) { + bool presentInPulledData = mMatchedMetricDimensionKeys.find(slice.first) + != mMatchedMetricDimensionKeys.end(); + if (!presentInPulledData) { + for (auto& interval : slice.second) { + interval.hasBase = false; + } + } + } + mMatchedMetricDimensionKeys.clear(); + mHasGlobalBase = true; + + // If we reach the guardrail, we might have dropped some data which means the bucket is + // incomplete. + // + // The base also needs to be reset. If we do not have the full data, we might + // incorrectly compute the diff when mUseZeroDefaultBase is true since an existing key + // might be missing from mCurrentSlicedBucket. + if (hasReachedGuardRailLimit()) { + invalidateCurrentBucket(); + mCurrentSlicedBucket.clear(); + } +} + void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { if (mCurrentSlicedBucket.size() == 0) { return; @@ -463,6 +482,10 @@ void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { } } +bool ValueMetricProducer::hasReachedGuardRailLimit() const { + return mCurrentSlicedBucket.size() >= mDimensionHardLimit; +} + bool ValueMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) { // ===========GuardRail============== // 1. Report the tuple count if the tuple count > soft limit @@ -473,7 +496,7 @@ bool ValueMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) { size_t newTupleCount = mCurrentSlicedBucket.size() + 1; StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount); // 2. Don't add more tuples, we are above the allowed threshold. Drop the data. - if (newTupleCount > mDimensionHardLimit) { + if (hasReachedGuardRailLimit()) { ALOGE("ValueMetric %lld dropping data for dimension key %s", (long long)mMetricId, newKey.toString().c_str()); StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId); @@ -539,6 +562,7 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIn (long long)mCurrentBucketStartTimeNs); return; } + mMatchedMetricDimensionKeys.insert(eventKey); flushIfNeededLocked(eventTimeNs); diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index 0cfefa9e3eb4..f26ad85acf05 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -52,7 +52,7 @@ public: // Process data pulled on bucket boundary. void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data, - bool pullSuccess) override; + bool pullSuccess, int64_t originalPullTimeNs) override; // ValueMetric needs special logic if it's a pulled atom. void notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk, const int uid, @@ -116,6 +116,9 @@ private: // Value fields for matching. std::vector<Matcher> mFieldMatchers; + // Value fields for matching. + std::set<MetricDimensionKey> mMatchedMetricDimensionKeys; + // tagId for pulled data. -1 if this is not pulled const int mPullTagId; @@ -155,11 +158,15 @@ private: // Util function to check whether the specified dimension hits the guardrail. bool hitGuardRailLocked(const MetricDimensionKey& newKey); + bool hasReachedGuardRailLimit() const; bool hitFullBucketGuardRailLocked(const MetricDimensionKey& newKey); void pullAndMatchEventsLocked(const int64_t timestampNs); + void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData, + int64_t originalPullTimeNs, int64_t eventElapsedTimeNs); + ValueBucket buildPartialBucket(int64_t bucketEndTime, const std::vector<Interval>& intervals); void initCurrentSlicedBucket(); @@ -238,10 +245,15 @@ private: FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket); FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate); FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed); + FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit); FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed); FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed); FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded); FRIEND_TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange); + FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled); + FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged); + FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary); + FRIEND_TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index 180a1ae07523..463b5a097585 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -725,6 +725,8 @@ bool initMetricActivations(const ConfigKey& key, const StatsdConfig& config, ALOGE("Invalid metric tracker index."); return false; } + allMetricProducers[metricTrackerIndex]->setActivationType( + metric_activation.activation_type()); metricsWithActivation.push_back(metricTrackerIndex); for (int j = 0; j < metric_activation.event_activation_size(); ++j) { const EventActivation& activation = metric_activation.event_activation(j); diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index 73aab4847e11..863261ae1626 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -407,6 +407,8 @@ message StatsdStatsReport { optional int64 stats_companion_pull_failed = 13; optional int64 stats_companion_pull_binder_transaction_failed = 14; optional int64 empty_data = 15; + optional int64 registered_count = 16; + optional int64 unregistered_count = 17; } repeated PulledAtomStats pulled_atom_stats = 10; @@ -419,6 +421,8 @@ message StatsdStatsReport { optional int64 condition_change_in_next_bucket = 6; optional int64 invalidated_bucket = 7; optional int64 bucket_dropped = 8; + optional int64 min_bucket_boundary_delay_ns = 9; + optional int64 max_bucket_boundary_delay_ns = 10; } repeated AtomMetricStats atom_metric_stats = 17; diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp index f76a9ad78396..0ebf2ca4e035 100644 --- a/cmds/statsd/src/stats_log_util.cpp +++ b/cmds/statsd/src/stats_log_util.cpp @@ -70,6 +70,8 @@ const int FIELD_ID_PULL_FAILED = 12; const int FIELD_ID_STATS_COMPANION_FAILED = 13; const int FIELD_ID_STATS_COMPANION_BINDER_TRANSACTION_FAILED = 14; const int FIELD_ID_EMPTY_DATA = 15; +const int FIELD_ID_PULL_REGISTERED_COUNT = 16; +const int FIELD_ID_PULL_UNREGISTERED_COUNT = 17; // for AtomMetricStats proto const int FIELD_ID_ATOM_METRIC_STATS = 17; const int FIELD_ID_METRIC_ID = 1; @@ -80,6 +82,8 @@ const int FIELD_ID_BAD_VALUE_TYPE = 5; const int FIELD_ID_CONDITION_CHANGE_IN_NEXT_BUCKET = 6; const int FIELD_ID_INVALIDATED_BUCKET = 7; const int FIELD_ID_BUCKET_DROPPED = 8; +const int FIELD_ID_MIN_BUCKET_BOUNDARY_DELAY_NS = 9; +const int FIELD_ID_MAX_BUCKET_BOUNDARY_DELAY_NS = 10; namespace { @@ -478,6 +482,10 @@ void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats> (long long)pair.second.statsCompanionPullBinderTransactionFailed); protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_EMPTY_DATA, (long long)pair.second.emptyData); + protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_REGISTERED_COUNT, + (long long) pair.second.registeredCount); + protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_UNREGISTERED_COUNT, + (long long) pair.second.unregisteredCount); protoOutput->end(token); } @@ -500,6 +508,10 @@ void writeAtomMetricStatsToStream(const std::pair<int, StatsdStats::AtomMetricSt (long long)pair.second.invalidatedBucket); protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_DROPPED, (long long)pair.second.bucketDropped); + protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MIN_BUCKET_BOUNDARY_DELAY_NS, + (long long)pair.second.minBucketBoundaryDelayNs); + protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_BUCKET_BOUNDARY_DELAY_NS, + (long long)pair.second.maxBucketBoundaryDelayNs); protoOutput->end(token); } diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index 9d3a66902804..5c6d548ad13a 100644 --- a/cmds/statsd/src/statsd_config.proto +++ b/cmds/statsd/src/statsd_config.proto @@ -379,6 +379,13 @@ message EventActivation { message MetricActivation { optional int64 metric_id = 1; + enum ActivationType { + UNKNOWN = 0; + ACTIVATE_IMMEDIATELY = 1; + ACTIVATE_ON_BOOT = 2; + } + optional ActivationType activation_type = 3; + repeated EventActivation event_activation = 2; } diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp index 6e4b2c86c837..42cac0cc4122 100644 --- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp +++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp @@ -17,32 +17,67 @@ #include "Log.h" #include "IncidentdReporter.h" -#include "frameworks/base/libs/incident/proto/android/os/header.pb.h" #include <android/os/IIncidentManager.h> #include <android/os/IncidentReportArgs.h> +#include <android/util/ProtoOutputStream.h> #include <binder/IBinder.h> #include <binder/IServiceManager.h> +#include <vector> + namespace android { namespace os { namespace statsd { +using android::util::ProtoOutputStream; +using std::vector; + +using util::FIELD_TYPE_MESSAGE; +using util::FIELD_TYPE_INT32; +using util::FIELD_TYPE_INT64; + +// field ids in IncidentHeaderProto +const int FIELD_ID_ALERT_ID = 1; +const int FIELD_ID_CONFIG_KEY = 3; +const int FIELD_ID_CONFIG_KEY_UID = 1; +const int FIELD_ID_CONFIG_KEY_ID = 2; + +namespace { +void getProtoData(const int64_t& rule_id, const ConfigKey& configKey, vector<uint8_t>* protoData) { + ProtoOutputStream headerProto; + headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_ALERT_ID, (long long)rule_id); + uint64_t token = + headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY); + headerProto.write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_KEY_UID, configKey.GetUid()); + headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_KEY_ID, (long long)configKey.GetId()); + headerProto.end(token); + + protoData->resize(headerProto.size()); + size_t pos = 0; + auto iter = headerProto.data(); + while (iter.readBuffer() != NULL) { + size_t toRead = iter.currentToRead(); + std::memcpy(&((*protoData)[pos]), iter.readBuffer(), toRead); + pos += toRead; + iter.rp()->move(toRead); + } +} +} // namespace + bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_id, const ConfigKey& configKey) { if (config.section_size() == 0) { VLOG("The alert %lld contains zero section in config(%d,%lld)", (unsigned long long)rule_id, - configKey.GetUid(), (long long) configKey.GetId()); + configKey.GetUid(), (long long)configKey.GetId()); return false; } IncidentReportArgs incidentReport; - android::os::IncidentHeaderProto header; - header.set_alert_id(rule_id); - header.mutable_config_key()->set_uid(configKey.GetUid()); - header.mutable_config_key()->set_id(configKey.GetId()); - incidentReport.addHeader(header); + vector<uint8_t> protoData; + getProtoData(rule_id, configKey, &protoData); + incidentReport.addHeader(protoData); for (int i = 0; i < config.section_size(); i++) { incidentReport.addSection(config.section(i)); diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp index 64008b50b013..60df165f102c 100644 --- a/cmds/statsd/tests/StatsLogProcessor_test.cpp +++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp @@ -574,6 +574,127 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) { EXPECT_EQ(timeBase2 + ttl6 - activation1006.ttl_ns, activation1003.activation_ns); } +TEST(StatsLogProcessorTest, TestActivationOnBoot) { + int uid = 1111; + + // Setup a simple config, no activation + StatsdConfig config1; + config1.set_id(12341); + config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher(); + *config1.add_atom_matcher() = wakelockAcquireMatcher; + + long metricId1 = 1234561; + long metricId2 = 1234562; + auto countMetric1 = config1.add_count_metric(); + countMetric1->set_id(metricId1); + countMetric1->set_what(wakelockAcquireMatcher.id()); + countMetric1->set_bucket(FIVE_MINUTES); + + auto countMetric2 = config1.add_count_metric(); + countMetric2->set_id(metricId2); + countMetric2->set_what(wakelockAcquireMatcher.id()); + countMetric2->set_bucket(FIVE_MINUTES); + + auto metric1Activation = config1.add_metric_activation(); + metric1Activation->set_metric_id(metricId1); + metric1Activation->set_activation_type(MetricActivation::ACTIVATE_ON_BOOT); + auto metric1ActivationTrigger = metric1Activation->add_event_activation(); + metric1ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id()); + metric1ActivationTrigger->set_ttl_seconds(100); + + ConfigKey cfgKey1(uid, 12341); + long timeBase1 = 1; + sp<StatsLogProcessor> processor = + CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1); + + EXPECT_EQ(1, processor->mMetricsManagers.size()); + auto it = processor->mMetricsManagers.find(cfgKey1); + EXPECT_TRUE(it != processor->mMetricsManagers.end()); + auto& metricsManager1 = it->second; + EXPECT_TRUE(metricsManager1->isActive()); + + auto metricIt = metricsManager1->mAllMetricProducers.begin(); + for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId1) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end()); + auto& metricProducer1 = *metricIt; + EXPECT_FALSE(metricProducer1->isActive()); + + metricIt = metricsManager1->mAllMetricProducers.begin(); + for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId2) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end()); + auto& metricProducer2 = *metricIt; + EXPECT_TRUE(metricProducer2->isActive()); + + const auto& activation1 = metricProducer1->mEventActivationMap.begin()->second; + EXPECT_EQ(100 * NS_PER_SEC, activation1.ttl_ns); + EXPECT_EQ(0, activation1.activation_ns); + EXPECT_EQ(kNotActive, activation1.state); + + std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")}; + auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1); + processor->OnLogEvent(event.get()); + + EXPECT_FALSE(metricProducer1->isActive()); + EXPECT_EQ(0, activation1.activation_ns); + EXPECT_EQ(kActiveOnBoot, activation1.state); + + int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC; + + processor->WriteMetricsActivationToDisk(shutDownTime); + EXPECT_TRUE(metricProducer1->isActive()); + int64_t ttl1 = metricProducer1->getRemainingTtlNs(shutDownTime); + EXPECT_EQ(100 * NS_PER_SEC, ttl1); + + long timeBase2 = 1000; + sp<StatsLogProcessor> processor2 = + CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1); + + EXPECT_EQ(1, processor2->mMetricsManagers.size()); + it = processor2->mMetricsManagers.find(cfgKey1); + EXPECT_TRUE(it != processor2->mMetricsManagers.end()); + auto& metricsManager1001 = it->second; + EXPECT_TRUE(metricsManager1001->isActive()); + + metricIt = metricsManager1001->mAllMetricProducers.begin(); + for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId1) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end()); + auto& metricProducer1001 = *metricIt; + EXPECT_FALSE(metricProducer1001->isActive()); + + metricIt = metricsManager1001->mAllMetricProducers.begin(); + for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId2) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end()); + auto& metricProducer1002 = *metricIt; + EXPECT_TRUE(metricProducer1002->isActive()); + + const auto& activation1001 = metricProducer1001->mEventActivationMap.begin()->second; + EXPECT_EQ(100 * NS_PER_SEC, activation1001.ttl_ns); + EXPECT_EQ(0, activation1001.activation_ns); + EXPECT_EQ(kNotActive, activation1001.state); + + processor2->LoadMetricsActivationFromDisk(); + + EXPECT_TRUE(metricProducer1001->isActive()); + EXPECT_EQ(timeBase2 + ttl1 - activation1001.ttl_ns, activation1001.activation_ns); +} + #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp index 6069516e9666..44a88f049443 100644 --- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp +++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp @@ -259,6 +259,10 @@ TEST(StatsdStatsTest, TestPullAtomStats) { stats.notePullDelay(android::util::DISK_SPACE, 3335L); stats.notePull(android::util::DISK_SPACE); stats.notePullFromCache(android::util::DISK_SPACE); + stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, true); + stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, false); + stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, true); + vector<uint8_t> output; stats.dumpStats(&output, false); @@ -276,6 +280,41 @@ TEST(StatsdStatsTest, TestPullAtomStats) { EXPECT_EQ(3333L, report.pulled_atom_stats(0).max_pull_time_nanos()); EXPECT_EQ(2223L, report.pulled_atom_stats(0).average_pull_delay_nanos()); EXPECT_EQ(3335L, report.pulled_atom_stats(0).max_pull_delay_nanos()); + EXPECT_EQ(2L, report.pulled_atom_stats(0).registered_count()); + EXPECT_EQ(1L, report.pulled_atom_stats(0).unregistered_count()); +} + +TEST(StatsdStatsTest, TestAtomMetricsStats) { + StatsdStats stats; + time_t now = time(nullptr); + // old event, we get it from the stats buffer. should be ignored. + stats.noteBucketDropped(1000L); + + stats.noteBucketBoundaryDelayNs(1000L, -1L); + stats.noteBucketBoundaryDelayNs(1000L, -10L); + stats.noteBucketBoundaryDelayNs(1000L, 2L); + + stats.noteBucketBoundaryDelayNs(1001L, 1L); + + vector<uint8_t> output; + stats.dumpStats(&output, false); + StatsdStatsReport report; + bool good = report.ParseFromArray(&output[0], output.size()); + EXPECT_TRUE(good); + + EXPECT_EQ(2, report.atom_metric_stats().size()); + + auto atomStats = report.atom_metric_stats(0); + EXPECT_EQ(1000L, atomStats.metric_id()); + EXPECT_EQ(1L, atomStats.bucket_dropped()); + EXPECT_EQ(-10L, atomStats.min_bucket_boundary_delay_ns()); + EXPECT_EQ(2L, atomStats.max_bucket_boundary_delay_ns()); + + auto atomStats2 = report.atom_metric_stats(1); + EXPECT_EQ(1001L, atomStats2.metric_id()); + EXPECT_EQ(0L, atomStats2.bucket_dropped()); + EXPECT_EQ(0L, atomStats2.min_bucket_boundary_delay_ns()); + EXPECT_EQ(1L, atomStats2.max_bucket_boundary_delay_ns()); } TEST(StatsdStatsTest, TestAnomalyMonitor) { diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp index 1725160c00c7..62868232d8e7 100644 --- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp @@ -133,7 +133,7 @@ TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) { event->init(); allData.push_back(event); - gaugeProducer.onDataPulled(allData, /** succeed */ true); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin(); EXPECT_EQ(INT, it->mValue.getType()); @@ -151,7 +151,7 @@ TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) { event2->write(25); event2->init(); allData.push_back(event2); - gaugeProducer.onDataPulled(allData, /** succeed */ true); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin(); EXPECT_EQ(INT, it->mValue.getType()); @@ -305,7 +305,7 @@ TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) { event->write(1); event->init(); allData.push_back(event); - gaugeProducer.onDataPulled(allData, /** succeed */ true); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs); EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin() ->second.front() @@ -328,7 +328,7 @@ TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) { event->write(3); event->init(); allData.push_back(event); - gaugeProducer.onDataPulled(allData, /** succeed */ true); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs); EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin() @@ -371,7 +371,7 @@ TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) { event->write(1); event->init(); allData.push_back(event); - gaugeProducer.onDataPulled(allData, /** succeed */ true); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs); EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin() ->second.front() @@ -440,7 +440,7 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) { event->write(110); event->init(); allData.push_back(event); - gaugeProducer.onDataPulled(allData, /** succeed */ true); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin() @@ -541,7 +541,7 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) { event->write(110); event->init(); allData.push_back(event); - gaugeProducer.onDataPulled(allData, /** succeed */ true); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); @@ -590,7 +590,7 @@ TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) { event1->write(13); event1->init(); - gaugeProducer.onDataPulled({event1}, /** succeed */ true); + gaugeProducer.onDataPulled({event1}, /** succeed */ true, bucketStartTimeNs); EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin() ->second.front() @@ -604,7 +604,7 @@ TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) { event2->write(15); event2->init(); - gaugeProducer.onDataPulled({event2}, /** succeed */ true); + gaugeProducer.onDataPulled({event2}, /** succeed */ true, bucketStartTimeNs + bucketSizeNs); EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin() ->second.front() @@ -619,7 +619,7 @@ TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) { event3->write(26); event3->init(); - gaugeProducer.onDataPulled({event3}, /** succeed */ true); + gaugeProducer.onDataPulled({event3}, /** succeed */ true, bucket2StartTimeNs + 2 * bucketSizeNs); EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin() ->second.front() @@ -633,7 +633,7 @@ TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) { std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10); event4->write("some value"); event4->init(); - gaugeProducer.onDataPulled({event4}, /** succeed */ true); + gaugeProducer.onDataPulled({event4}, /** succeed */ true, bucketStartTimeNs + 3 * bucketSizeNs); EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty()); } diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index 91b98ecffa29..572b1991f426 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -160,7 +160,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) { event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; @@ -178,7 +178,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) { event->write(23); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; @@ -198,7 +198,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) { event->write(36); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; @@ -265,7 +265,7 @@ TEST(ValueMetricProducerTest, TestPartialBucketCreated) { event->write(2); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** success */ true); + valueProducer.onDataPulled(allData, /** success */ true, bucket2StartTimeNs); // Partial buckets created in 2nd bucket. valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 2, "com.foo", 10000, 1); @@ -327,7 +327,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) { event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = @@ -346,7 +346,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) { event->write(23); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); // No new data seen, so data has been cleared. EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size()); @@ -363,7 +363,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) { event->write(36); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; @@ -412,7 +412,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; @@ -428,7 +428,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { event->write(10); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; @@ -445,7 +445,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { event->write(36); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; EXPECT_EQ(true, curInterval.hasBase); @@ -493,7 +493,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) { event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; @@ -509,7 +509,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) { event->write(10); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; @@ -524,7 +524,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) { event->write(36); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; EXPECT_EQ(true, curInterval.hasBase); @@ -599,7 +599,7 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { event->write(110); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); @@ -710,7 +710,7 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) { event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1); @@ -725,7 +725,7 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) { event->write(150); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); EXPECT_EQ(bucket3StartTimeNs, valueProducer.mCurrentBucketStartTimeNs); EXPECT_EQ(20L, @@ -764,7 +764,7 @@ TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) { event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1); @@ -1068,7 +1068,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; @@ -1086,7 +1086,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { event->write(23); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; @@ -1107,7 +1107,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { event->write(36); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; // startUpdated:false sum:12 @@ -1195,7 +1195,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) { event->write(110); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; EXPECT_EQ(false, curInterval.hasBase); @@ -1291,7 +1291,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { EXPECT_EQ(20, curInterval.value.long_value); EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); - // Now the alarm is delivered, but it is considered late, it has no effect + // Now the alarm is delivered, but it is considered late, the bucket is invalidated. vector<shared_ptr<LogEvent>> allData; allData.clear(); shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 50); @@ -1299,10 +1299,10 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { event->write(110); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; - EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(false, curInterval.hasBase); EXPECT_EQ(130, curInterval.base.long_value); EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(20, curInterval.value.long_value); @@ -1752,7 +1752,7 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) { allData.push_back(event1); allData.push_back(event2); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size()); EXPECT_EQ(true, interval1.hasBase); EXPECT_EQ(11, interval1.base.long_value); @@ -1842,7 +1842,7 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) { allData.push_back(event1); allData.push_back(event2); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size()); EXPECT_EQ(true, interval1.hasBase); EXPECT_EQ(11, interval1.base.long_value); @@ -1871,7 +1871,7 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) { event1->write(5); event1->init(); allData.push_back(event1); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); EXPECT_EQ(true, interval2.hasBase); @@ -1893,7 +1893,7 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) { event2->write(5); event2->init(); allData.push_back(event2); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs); EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size()); EXPECT_EQ(true, interval2.hasBase); @@ -1968,7 +1968,7 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) { allData.push_back(event1); allData.push_back(event2); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size()); EXPECT_EQ(true, interval1.hasBase); EXPECT_EQ(11, interval1.base.long_value); @@ -2000,7 +2000,7 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) { event1->write(5); event1->init(); allData.push_back(event1); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); // Only one interval left. One was trimmed. EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); @@ -2018,7 +2018,7 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) { event1->write(14); event1->init(); allData.push_back(event1); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs); interval2 = valueProducer.mCurrentSlicedBucket.begin()->second[0]; EXPECT_EQ(true, interval2.hasBase); @@ -2078,7 +2078,7 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfB EXPECT_EQ(false, curInterval.hasValue); vector<shared_ptr<LogEvent>> allData; - valueProducer.onDataPulled(allData, /** succeed */ false); + valueProducer.onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); EXPECT_EQ(false, curInterval.hasBase); EXPECT_EQ(false, curInterval.hasValue); @@ -2179,7 +2179,7 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) { valueProducer.mCondition = true; vector<shared_ptr<LogEvent>> allData; - valueProducer.onDataPulled(allData, /** succeed */ false); + valueProducer.onDataPulled(allData, /** succeed */ false, bucketStartTimeNs); EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size()); valueProducer.onConditionChanged(false, bucketStartTimeNs + 1); @@ -2361,7 +2361,7 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed) { event->write(110); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs); // This will fail and should invalidate the whole bucket since we do not have all the data // needed to compute the metric value when the screen was on. @@ -2375,7 +2375,7 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed) { event2->write(140); event2->init(); allData.push_back(event2); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); valueProducer.flushIfNeededLocked(bucket2StartTimeNs + 1); @@ -2390,6 +2390,51 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed) { EXPECT_EQ(true, valueProducer.mHasGlobalBase); } +TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit) { + ValueMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.mutable_value_field()->set_field(tagId); + metric.mutable_value_field()->add_child()->set_field(2); + metric.mutable_dimensions_in_what()->set_field(tagId); + metric.mutable_dimensions_in_what()->add_child()->set_field(1); + metric.set_condition(StringToId("SCREEN_ON")); + metric.set_max_pull_delay_sec(INT_MAX); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); + + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + // First onConditionChanged + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + for (int i = 0; i < 2000; i++) { + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); + event->write(i); + event->write(i); + event->init(); + data->push_back(event); + } + return true; + })); + + ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex, + eventMatcherWizard, tagId, bucketStartTimeNs, + bucketStartTimeNs, pullerManager); + + valueProducer.mCondition = false; + valueProducer.onConditionChanged(true, bucket2StartTimeNs + 2); + EXPECT_EQ(true, valueProducer.mCurrentBucketIsInvalid); + EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size()); +} + TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed) { ValueMetric metric; metric.set_id(metricId); @@ -2446,7 +2491,7 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed) { event->write(110); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ false); + valueProducer.onDataPulled(allData, /** succeed */ false, bucketStartTimeNs); valueProducer.onConditionChanged(false, bucketStartTimeNs + 2); valueProducer.onConditionChanged(true, bucketStartTimeNs + 3); @@ -2458,7 +2503,7 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed) { event2->write(140); event2->init(); allData.push_back(event2); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); valueProducer.flushIfNeededLocked(bucket2StartTimeNs + 1); @@ -2529,7 +2574,7 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed) { event->write(110); event->init(); allData.push_back(event); - valueProducer.onDataPulled(allData, /** succeed */ true); + valueProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs); // This will fail and should invalidate the whole bucket since we do not have all the data // needed to compute the metric value when the screen was on. @@ -2543,7 +2588,7 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed) { event2->write(140); event2->init(); allData.push_back(event2); - valueProducer.onDataPulled(allData, /** succeed */ false); + valueProducer.onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs); valueProducer.flushIfNeededLocked(bucket2StartTimeNs + 1); @@ -2557,6 +2602,268 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed) { EXPECT_EQ(false, valueProducer.mHasGlobalBase); } +TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled) { + ValueMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.mutable_value_field()->set_field(tagId); + metric.mutable_value_field()->add_child()->set_field(2); + metric.set_max_pull_delay_sec(INT_MAX); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); + + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + // Start bucket. + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs); + event->write(tagId); + event->write(3); + event->init(); + data->push_back(event); + return true; + })); + + ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, + logEventMatcherIndex, eventMatcherWizard, tagId, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); + + // Bucket 2 start. + vector<shared_ptr<LogEvent>> allData; + allData.clear(); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); + event->write(tagId); + event->write(110); + event->init(); + allData.push_back(event); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); + EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); + EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); + + // Bucket 3 empty. + allData.clear(); + shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1); + event2->init(); + allData.push_back(event2); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); + // Data has been trimmed. + EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size()); + EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); +} + +TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) { + ValueMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.mutable_value_field()->set_field(tagId); + metric.mutable_value_field()->add_child()->set_field(2); + metric.set_condition(StringToId("SCREEN_ON")); + metric.set_max_pull_delay_sec(INT_MAX); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); + + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + // First onConditionChanged + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs); + event->write(tagId); + event->write(3); + event->init(); + data->push_back(event); + return true; + })) + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + return true; + })); + + ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex, + eventMatcherWizard, tagId, bucketStartTimeNs, + bucketStartTimeNs, pullerManager); + + valueProducer.onConditionChanged(true, bucketStartTimeNs + 10); + EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); + ValueMetricProducer::Interval& curInterval = + valueProducer.mCurrentSlicedBucket.begin()->second[0]; + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(false, curInterval.hasValue); + EXPECT_EQ(true, valueProducer.mHasGlobalBase); + + // Empty pull. + valueProducer.onConditionChanged(false, bucketStartTimeNs + 10); + EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + EXPECT_EQ(false, curInterval.hasBase); + EXPECT_EQ(false, curInterval.hasValue); + EXPECT_EQ(false, valueProducer.mHasGlobalBase); +} + +TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) { + ValueMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.mutable_value_field()->set_field(tagId); + metric.mutable_value_field()->add_child()->set_field(2); + metric.set_condition(StringToId("SCREEN_ON")); + metric.set_max_pull_delay_sec(INT_MAX); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); + + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + // First onConditionChanged + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs); + event->write(tagId); + event->write(1); + event->init(); + data->push_back(event); + return true; + })) + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs); + event->write(tagId); + event->write(2); + event->init(); + data->push_back(event); + return true; + })) + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs); + event->write(tagId); + event->write(5); + event->init(); + data->push_back(event); + return true; + })); + + ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex, + eventMatcherWizard, tagId, bucketStartTimeNs, + bucketStartTimeNs, pullerManager); + + valueProducer.onConditionChanged(true, bucketStartTimeNs + 10); + valueProducer.onConditionChanged(false, bucketStartTimeNs + 11); + valueProducer.onConditionChanged(true, bucketStartTimeNs + 12); + EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); + ValueMetricProducer::Interval& curInterval = + valueProducer.mCurrentSlicedBucket.begin()->second[0]; + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(true, valueProducer.mHasGlobalBase); + + // End of bucket + vector<shared_ptr<LogEvent>> allData; + allData.clear(); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); + EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + // Data is empty, base should be reset. + EXPECT_EQ(false, curInterval.hasBase); + EXPECT_EQ(5, curInterval.base.long_value); + EXPECT_EQ(false, curInterval.hasValue); + EXPECT_EQ(true, valueProducer.mHasGlobalBase); + + EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); + EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value); +} + + +TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) { + ValueMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.mutable_value_field()->set_field(tagId); + metric.mutable_value_field()->add_child()->set_field(2); + metric.mutable_dimensions_in_what()->set_field(tagId); + metric.mutable_dimensions_in_what()->add_child()->set_field(1); + metric.set_condition(StringToId("SCREEN_ON")); + metric.set_max_pull_delay_sec(INT_MAX); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); + + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + // First onConditionChanged + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs); + event->write(tagId); + event->write(1); + event->write(1); + event->init(); + data->push_back(event); + return true; + })); + + ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex, + eventMatcherWizard, tagId, bucketStartTimeNs, + bucketStartTimeNs, pullerManager); + + valueProducer.onConditionChanged(true, bucketStartTimeNs + 10); + EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); + + // End of bucket + vector<shared_ptr<LogEvent>> allData; + allData.clear(); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); + event->write(2); + event->write(2); + event->init(); + allData.push_back(event); + valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); + + // Key 1 should be reset since in not present in the most pull. + EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size()); + auto iterator = valueProducer.mCurrentSlicedBucket.begin(); + EXPECT_EQ(true, iterator->second[0].hasBase); + EXPECT_EQ(2, iterator->second[0].base.long_value); + EXPECT_EQ(false, iterator->second[0].hasValue); + iterator++; + EXPECT_EQ(false, iterator->second[0].hasBase); + EXPECT_EQ(1, iterator->second[0].base.long_value); + EXPECT_EQ(false, iterator->second[0].hasValue); + + EXPECT_EQ(true, valueProducer.mHasGlobalBase); +} + } // namespace statsd } // namespace os } // namespace android diff --git a/config/hiddenapi-greylist-max-p.txt b/config/hiddenapi-greylist-max-p.txt index 7840b186615f..4c643e1c6831 100644 --- a/config/hiddenapi-greylist-max-p.txt +++ b/config/hiddenapi-greylist-max-p.txt @@ -48,6 +48,8 @@ Landroid/os/WorkSource;->updateLocked(Landroid/os/WorkSource;ZZ)Z Landroid/service/carrier/ICarrierMessagingCallback$Stub;-><init>()V Landroid/service/carrier/ICarrierMessagingService;->filterSms(Landroid/service/carrier/MessagePdu;Ljava/lang/String;IILandroid/service/carrier/ICarrierMessagingCallback;)V Landroid/telephony/CarrierMessagingServiceManager;-><init>()V +Landroid/view/IGraphicsStats$Stub$Proxy;-><init>(Landroid/os/IBinder;)V +Landroid/view/IGraphicsStats$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IGraphicsStats; Landroid/view/IWindowManager;->setInTouchMode(Z)V Landroid/view/IWindowManager;->showStrictModeViolation(Z)V Lcom/android/internal/R$styleable;->AndroidManifestActivityAlias:[I diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt index a0d8a1232257..b72ce8977128 100644 --- a/config/hiddenapi-greylist.txt +++ b/config/hiddenapi-greylist.txt @@ -1474,8 +1474,6 @@ Landroid/view/autofill/IAutoFillManager$Stub$Proxy;-><init>(Landroid/os/IBinder; Landroid/view/autofill/IAutoFillManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/autofill/IAutoFillManager; Landroid/view/IAppTransitionAnimationSpecsFuture$Stub;-><init>()V Landroid/view/IDockedStackListener$Stub;-><init>()V -Landroid/view/IGraphicsStats$Stub$Proxy;-><init>(Landroid/os/IBinder;)V -Landroid/view/IGraphicsStats$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IGraphicsStats; Landroid/view/IRecentsAnimationController;->finish(Z)V Landroid/view/IRecentsAnimationController;->screenshotTask(I)Landroid/app/ActivityManager$TaskSnapshot; Landroid/view/IRecentsAnimationController;->setAnimationTargetsBehindSystemBars(Z)V @@ -2441,7 +2439,6 @@ Lcom/android/internal/telephony/cat/CatService;->isStkAppInstalled()Z Lcom/android/internal/telephony/cat/CatService;->mCmdIf:Lcom/android/internal/telephony/CommandsInterface; Lcom/android/internal/telephony/cat/CatService;->mContext:Landroid/content/Context; Lcom/android/internal/telephony/cat/CatService;->mCurrntCmd:Lcom/android/internal/telephony/cat/CatCmdMessage; -Lcom/android/internal/telephony/cat/CatService;->mHandlerThread:Landroid/os/HandlerThread; Lcom/android/internal/telephony/cat/CatService;->mMenuCmd:Lcom/android/internal/telephony/cat/CatCmdMessage; Lcom/android/internal/telephony/cat/CatService;->mMsgDecoder:Lcom/android/internal/telephony/cat/RilMessageDecoder; Lcom/android/internal/telephony/cat/CatService;->mSlotId:I diff --git a/core/java/android/accessibilityservice/OWNERS b/core/java/android/accessibilityservice/OWNERS new file mode 100644 index 000000000000..265674a74b7e --- /dev/null +++ b/core/java/android/accessibilityservice/OWNERS @@ -0,0 +1,3 @@ +svetoslavganov@google.com +pweaver@google.com +rhedjao@google.com diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index db3b720642aa..ca3c72627e3b 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2019,8 +2019,9 @@ public class ActivityManager { return getTaskService().isActivityStartAllowedOnDisplay(displayId, intent, intent.resolveTypeIfNeeded(context.getContentResolver()), context.getUserId()); } catch (RemoteException e) { - throw new RuntimeException("Failure from system", e); + e.rethrowFromSystemServer(); } + return false; } /** diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 5814e69c36a3..ce7199816726 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -26,6 +26,7 @@ import android.app.ActivityManager.StackInfo; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.graphics.Insets; import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; import android.os.RemoteException; @@ -84,6 +85,8 @@ public class ActivityView extends ViewGroup { /** The ActivityView is only allowed to contain one task. */ private final boolean mSingleTaskInstance; + private Insets mForwardedInsets; + @UnsupportedAppUsage public ActivityView(Context context) { this(context, null /* attrs */); @@ -369,11 +372,13 @@ public class ActivityView extends ViewGroup { .build(); try { + // TODO: Find a way to consolidate these calls to the server. wm.reparentDisplayContent(displayId, mRootSurfaceControl); wm.dontOverrideDisplayInfo(displayId); if (mSingleTaskInstance) { mActivityTaskManager.setDisplayToSingleTaskInstance(displayId); } + wm.setForwardedInsets(displayId, mForwardedInsets); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } @@ -454,6 +459,24 @@ public class ActivityView extends ViewGroup { } /** + * Set forwarded insets on the virtual display. + * + * @see IWindowManager#setForwardedInsets + */ + public void setForwardedInsets(Insets insets) { + mForwardedInsets = insets; + if (mVirtualDisplay == null) { + return; + } + try { + final IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); + wm.setForwardedInsets(mVirtualDisplay.getDisplay().getDisplayId(), mForwardedInsets); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** * A task change listener that detects background color change of the topmost stack on our * virtual display and updates the background of the surface view. This background will be shown * when surface view is resized, but the app hasn't drawn its content in new size yet. diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index db6ad3df17b0..2b765b2284e7 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -247,8 +247,20 @@ interface IActivityTaskManager { boolean preserveWindows, boolean animate, int animationDuration); boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop, boolean animate, in Rect initialBounds, boolean showRecents); - - + /** + * Use the offset to adjust the stack boundary with animation. + * + * @param stackId Id of the stack to adjust. + * @param compareBounds Offset is only applied if the current pinned stack bounds is equal to + * the compareBounds. + * @param xOffset The horizontal offset. + * @param yOffset The vertical offset. + * @param animationDuration The duration of the resize animation in milliseconds or -1 if the + * default animation duration should be used. + * @throws RemoteException + */ + void offsetPinnedStackBounds(int stackId, in Rect compareBounds, int xOffset, int yOffset, + int animationDuration); /** * Removes stacks in the input windowing modes from the system if they are of activity type * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index f522d71afd08..17f645dfbf23 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -125,7 +125,7 @@ public class KeyguardManager { public static final int RESULT_ALTERNATE = 1; /** - * @deprecated see {@link BiometricPrompt.Builder#setEnableFallback(boolean)} + * @deprecated see {@link BiometricPrompt.Builder#setAllowDeviceCredential(boolean)} * * Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics * if enrolled) for the current user of the device. The caller is expected to launch this diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 028e3efc9fb8..dc4f3432b6bd 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -8243,6 +8243,7 @@ public class Notification implements Parcelable private void buildIntoRemoteViewContent(RemoteViews remoteViews, RemoteViews customContent, TemplateBindResult result) { + int childIndex = -1; if (customContent != null) { // Need to clone customContent before adding, because otherwise it can no longer be // parceled independently of remoteViews. @@ -8250,7 +8251,11 @@ public class Notification implements Parcelable remoteViews.removeAllViewsExceptId(R.id.notification_main_column, R.id.progress); remoteViews.addView(R.id.notification_main_column, customContent, 0 /* index */); remoteViews.addFlags(RemoteViews.FLAG_REAPPLY_DISALLOWED); + childIndex = 0; } + remoteViews.setIntTag(R.id.notification_main_column, + com.android.internal.R.id.notification_custom_view_index_tag, + childIndex); // also update the end margin if there is an image Resources resources = mBuilder.mContext.getResources(); int endMargin = resources.getDimensionPixelSize( diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java index 3119b37a686e..7746148d325a 100644 --- a/core/java/android/app/StatsManager.java +++ b/core/java/android/app/StatsManager.java @@ -24,6 +24,7 @@ import android.annotation.SystemApi; import android.content.Context; import android.os.IBinder; import android.os.IStatsManager; +import android.os.IStatsPullerCallback; import android.os.RemoteException; import android.os.ServiceManager; import android.util.AndroidException; @@ -408,6 +409,39 @@ public final class StatsManager { } } + /** + * Registers a callback for an atom when that atom is to be pulled. The stats service will + * invoke pullData in the callback when the stats service determines that this atom needs to be + * pulled. Currently, this only works for atoms with tags above 100,000 that do not have a uid. + * + * @param atomTag The tag of the atom for this puller callback. Must be at least 100000. + * @param callback The callback to be invoked when the stats service pulls the atom. + * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service + * + * @hide + */ + @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS }) + public void setPullerCallback(int atomTag, IStatsPullerCallback callback) + throws StatsUnavailableException { + synchronized (this) { + try { + IStatsManager service = getIStatsManagerLocked(); + if (callback == null) { + service.unregisterPullerCallback(atomTag, mContext.getOpPackageName()); + } else { + service.registerPullerCallback(atomTag, callback, + mContext.getOpPackageName()); + } + + } catch (RemoteException e) { + Slog.e(TAG, "Failed to connect to statsd when registering data listener."); + throw new StatsUnavailableException("could not connect", e); + } catch (SecurityException e) { + throw new StatsUnavailableException(e.getMessage(), e); + } + } + } + private class StatsdDeathRecipient implements IBinder.DeathRecipient { @Override public void binderDied() { diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING index 78ec8a17e8e8..65859c76a42a 100644 --- a/core/java/android/app/TEST_MAPPING +++ b/core/java/android/app/TEST_MAPPING @@ -6,5 +6,13 @@ { "path": "frameworks/base/services/core/java/com/android/server/wm" } + ], + "presubmit": [ + { + "name": "CtsFragmentTestCases" + }, + { + "name": "CtsFragmentTestCasesSdk26" + } ] } diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index 077b177be930..dd00e5a74382 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -97,6 +97,12 @@ public class TaskInfo { public long lastActiveTime; /** + * The id of the display this task is associated with. + * @hide + */ + public int displayId; + + /** * The recent activity values for the highest activity in the stack to have set the values. * {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}. */ @@ -152,6 +158,7 @@ public class TaskInfo { userId = source.readInt(); stackId = source.readInt(); taskId = source.readInt(); + displayId = source.readInt(); isRunning = source.readBoolean(); baseIntent = source.readInt() != 0 ? Intent.CREATOR.createFromParcel(source) @@ -179,6 +186,7 @@ public class TaskInfo { dest.writeInt(userId); dest.writeInt(stackId); dest.writeInt(taskId); + dest.writeInt(displayId); dest.writeBoolean(isRunning); if (baseIntent != null) { @@ -209,6 +217,7 @@ public class TaskInfo { @Override public String toString() { return "TaskInfo{userId=" + userId + " stackId=" + stackId + " taskId=" + taskId + + " displayId=" + displayId + " isRunning=" + isRunning + " baseIntent=" + baseIntent + " baseActivity=" + baseActivity + " topActivity=" + topActivity + " origActivity=" + origActivity diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 3ff6973a09ff..2f70c9d24936 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1376,7 +1376,7 @@ public class DevicePolicyManager { * complexity, and use this activity with extra {@link #EXTRA_PASSWORD_COMPLEXITY} to suggest * to users how complex the app wants the new screen lock to be. Note that both {@link * #getPasswordComplexity()} and the extra {@link #EXTRA_PASSWORD_COMPLEXITY} require the - * calling app to have the permission {@link permission#GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY}. + * calling app to have the permission {@link permission#REQUEST_SCREEN_LOCK_COMPLEXITY}. * * <p>If the intent is launched from within a managed profile with a profile * owner built against {@link android.os.Build.VERSION_CODES#M} or before, @@ -1404,7 +1404,7 @@ public class DevicePolicyManager { * * <p>If an invalid value is used, it will be treated as {@link #PASSWORD_COMPLEXITY_NONE}. */ - @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY) + @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY) public static final String EXTRA_PASSWORD_COMPLEXITY = "android.app.extra.PASSWORD_COMPLEXITY"; @@ -3346,10 +3346,10 @@ public class DevicePolicyManager { * * @throws IllegalStateException if the user is not unlocked. * @throws SecurityException if the calling application does not have the permission - * {@link permission#GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY} + * {@link permission#REQUEST_SCREEN_LOCK_COMPLEXITY} */ @PasswordComplexity - @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY) + @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY) public int getPasswordComplexity() { throwIfParentInstance("getPasswordComplexity"); if (mService == null) { @@ -4618,6 +4618,10 @@ public class DevicePolicyManager { * <p>If the installer must have access to the credentials, call * {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, boolean)} instead. * + * <p>Note: If the provided {@code alias} is of an existing alias, all former grants that apps + * have been given to access the key and certificates associated with this alias will be + * revoked. + * * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or * {@code null} if calling from a delegated certificate installer. * @param privKey The private key to install. @@ -4645,6 +4649,10 @@ public class DevicePolicyManager { * immediately, without user approval. It is a best practice not to request this unless strictly * necessary since it opens up additional security vulnerabilities. * + * <p>Note: If the provided {@code alias} is of an existing alias, all former grants that apps + * have been given to access the key and certificates associated with this alias will be + * revoked. + * * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or * {@code null} if calling from a delegated certificate installer. * @param privKey The private key to install. @@ -4685,6 +4693,10 @@ public class DevicePolicyManager { * <p>Include {@link #INSTALLKEY_SET_USER_SELECTABLE} in the {@code flags} argument to allow * the user to select the key from a dialog. * + * <p>Note: If the provided {@code alias} is of an existing alias, all former grants that apps + * have been given to access the key and certificates associated with this alias will be + * revoked. + * * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or * {@code null} if calling from a delegated certificate installer. * @param privKey The private key to install. @@ -4761,6 +4773,10 @@ public class DevicePolicyManager { * <p>Because this method might take several seconds to complete, it should only be called from * a worker thread. This method returns {@code null} when called from the main thread. * + * <p>Note: If the provided {@code alias} is of an existing alias, all former grants that apps + * have been given to access the key and certificates associated with this alias will be + * revoked. + * * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or * {@code null} if calling from a delegated certificate installer. * @param algorithm The key generation algorithm, see {@link java.security.KeyPairGenerator}. @@ -9628,7 +9644,7 @@ public class DevicePolicyManager { * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param enabled {@code true} to enable the backup service, {@code false} to disable it. - * @throws SecurityException if {@code admin} is not a device owner. + * @throws SecurityException if {@code admin} is not a device owner or a profile owner. */ public void setBackupServiceEnabled(@NonNull ComponentName admin, boolean enabled) { throwIfParentInstance("setBackupServiceEnabled"); @@ -10521,6 +10537,8 @@ public class DevicePolicyManager { * @hide */ @SystemApi + @RequiresPermission(value = android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, + conditional = true) public void setProfileOwnerCanAccessDeviceIdsForUser( @NonNull ComponentName who, @NonNull UserHandle userHandle) { if (mService == null) { diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java index fa2a6a1f08e4..edd3ef983945 100644 --- a/core/java/android/app/role/RoleManager.java +++ b/core/java/android/app/role/RoleManager.java @@ -69,6 +69,22 @@ public final class RoleManager { private static final String LOG_TAG = RoleManager.class.getSimpleName(); /** + * The name of the assistant app role. + * + * @hide + */ + @SystemApi + @TestApi + public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT"; + + /** + * The name of the browser role. + * + * @see Intent#CATEGORY_APP_BROWSER + */ + public static final String ROLE_BROWSER = "android.app.role.BROWSER"; + + /** * The name of the dialer role. * * @see Intent#ACTION_DIAL @@ -83,18 +99,18 @@ public final class RoleManager { public static final String ROLE_SMS = "android.app.role.SMS"; /** - * The name of the browser role. + * The name of the emergency role * - * @see Intent#CATEGORY_APP_BROWSER + * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE */ - public static final String ROLE_BROWSER = "android.app.role.BROWSER"; + public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY"; /** - * The name of the gallery role. + * The name of the home role. * - * @see Intent#CATEGORY_APP_GALLERY + * @see Intent#CATEGORY_HOME */ - public static final String ROLE_GALLERY = "android.app.role.GALLERY"; + public static final String ROLE_HOME = "android.app.role.HOME"; /** * The name of the music player role. @@ -104,18 +120,11 @@ public final class RoleManager { public static final String ROLE_MUSIC = "android.app.role.MUSIC"; /** - * The name of the home role. - * - * @see Intent#CATEGORY_HOME - */ - public static final String ROLE_HOME = "android.app.role.HOME"; - - /** - * The name of the emergency role + * The name of the gallery role. * - * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE + * @see Intent#CATEGORY_APP_GALLERY */ - public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY"; + public static final String ROLE_GALLERY = "android.app.role.GALLERY"; /** * The name of the car mode dialer app role. @@ -131,20 +140,20 @@ public final class RoleManager { * TODO: STOPSHIP: Make name of required roles public API * @hide */ - public static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER_APP"; + public static final String ROLE_CAR_MODE_DIALER = "android.app.role.CAR_MODE_DIALER"; /** - * The name of the proxy calling role. + * The name of the call redirection role. * <p> - * A proxy calling app provides a means to re-write the phone number for an outgoing call to - * place the call through a proxy calling service. + * A call redirection app provides a means to re-write the phone number for an outgoing call to + * place the call through a call redirection service. * * @see android.telecom.CallRedirectionService * * TODO: STOPSHIP: Make name of required roles public API * @hide */ - public static final String ROLE_PROXY_CALLING_APP = "android.app.role.PROXY_CALLING_APP"; + public static final String ROLE_CALL_REDIRECTION = "android.app.role.CALL_REDIRECTION"; /** * The name of the call screening and caller id role. @@ -154,7 +163,7 @@ public final class RoleManager { * TODO: STOPSHIP: Make name of required roles public API * @hide */ - public static final String ROLE_CALL_SCREENING_APP = "android.app.role.CALL_SCREENING_APP"; + public static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING"; /** * The name of the call companion app role. @@ -170,16 +179,7 @@ public final class RoleManager { * TODO: STOPSHIP: Make name of required roles public API * @hide */ - public static final String ROLE_CALL_COMPANION_APP = "android.app.role.CALL_COMPANION_APP"; - - /** - * The name of the assistant app role. - * - * @hide - */ - @SystemApi - @TestApi - public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT"; + public static final String ROLE_CALL_COMPANION = "android.app.role.CALL_COMPANION"; /** * @hide diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 51397a243420..dc5bdc673249 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -745,7 +745,11 @@ public final class UsageStatsManager { * Registering an {@code observerId} that was already registered will override the previous one. * No more than 1000 unique {@code observerId} may be registered by a single uid * at any one time. - * A limit may be unregistered via {@link #unregisterAppUsageLimitObserver} + * A limit is not cleared when the usage time is exceeded. It needs to be unregistered via + * {@link #unregisterAppUsageLimitObserver}. + * <p> + * Note: usage limits are not persisted in the system and are cleared on reboots. Callers + * must reset any limits that they need on reboots. * <p> * This method is similar to {@link #registerAppUsageObserver}, but the usage limit set here * will be visible to the launcher so that it can report the limit to the user and how much @@ -757,12 +761,15 @@ public final class UsageStatsManager { * @param observedEntities The list of packages and token to observe for usage time. Cannot be * null and must include at least one package or token. * @param timeLimit The total time the set of apps can be in the foreground before the - * callbackIntent is delivered. Must be at least one minute. + * callbackIntent is delivered. Must be at least one minute. Note: a limit of + * 0 can be set to indicate that the user has already exhausted the limit for + * a group, in which case, the given {@code callbackIntent} will be ignored. * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null. - * @param callbackIntent The PendingIntent that will be dispatched when the usage limit is + * @param callbackIntent The PendingIntent that will be dispatched when the usage limit is * exceeded by the group of apps. The delivered Intent will also contain * the extras {@link #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and - * {@link #EXTRA_TIME_USED}. Cannot be null. + * {@link #EXTRA_TIME_USED}. Cannot be {@code null} unless the observer is + * being registered with a {@code timeLimit} of 0. * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE * permissions. * @hide @@ -772,7 +779,7 @@ public final class UsageStatsManager { android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities, - long timeLimit, @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) { + long timeLimit, @NonNull TimeUnit timeUnit, PendingIntent callbackIntent) { try { mService.registerAppUsageLimitObserver(observerId, observedEntities, timeUnit.toMillis(timeLimit), callbackIntent, mContext.getOpPackageName()); diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 47034a6df8a7..7cc439138527 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -1029,10 +1029,18 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { } /** + * Returns true if the activity has maximum or minimum aspect ratio. + * @hide + */ + public boolean hasFixedAspectRatio() { + return maxAspectRatio != 0 || minAspectRatio != 0; + } + + /** * Returns true if the activity's orientation is fixed. * @hide */ - boolean isFixedOrientation() { + public boolean isFixedOrientation() { return isFixedOrientationLandscape() || isFixedOrientationPortrait() || screenOrientation == SCREEN_ORIENTATION_LOCKED; } diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index b27c5dc1b457..6c6fcb2ea558 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -650,6 +650,18 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int PRIVATE_FLAG_USE_EMBEDDED_DEX = 1 << 25; + /** + * Value for {@link #privateFlags}: indicates whether this application's data will be cleared + * on a failed restore. + * + * <p>Comes from the + * android.R.styleable#AndroidManifestApplication_allowClearUserDataOnFailedRestore attribute + * of the <application> tag. + * + * @hide + */ + public static final int PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE = 1 << 26; + /** @hide */ @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = { PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE, @@ -676,6 +688,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { PRIVATE_FLAG_VENDOR, PRIVATE_FLAG_VIRTUAL_PRELOAD, PRIVATE_FLAG_HAS_FRAGILE_USER_DATA, + PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE }) @Retention(RetentionPolicy.SOURCE) public @interface ApplicationInfoPrivateFlags {} diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 0ac4f6481fc4..80954731bffb 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -791,11 +791,6 @@ public class PackageInstaller { * individual session IDs can be added with {@link #addChildSessionId(int)} * and commit of the multi-package session will result in all child sessions * being committed atomically. - * <p> - * If a package requires to be installed only at reboot, the session should - * be marked as a staged session by calling {@link SessionParams#setStaged()} - * with {@code true}. This can also apply to a multi-package session, in - * which case all the packages in the session will be applied at reboot. */ public static class Session implements Closeable { /** {@hide} */ @@ -1539,7 +1534,11 @@ public class PackageInstaller { * Staged sessions are scheduled to be installed at next reboot. Staged sessions can also be * multi-package. In that case, if any of the children sessions fail to install at reboot, * all the other children sessions are aborted as well. + * + * {@hide} */ + @SystemApi + @RequiresPermission(Manifest.permission.INSTALL_PACKAGES) public void setStaged() { this.isStaged = true; } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 6e52b33692c8..eaf6c5a9d1cc 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -715,7 +715,6 @@ public abstract class PackageManager { INSTALL_FORCE_PERMISSION_PROMPT, INSTALL_INSTANT_APP, INSTALL_DONT_KILL_APP, - INSTALL_FORCE_SDK, INSTALL_FULL_APP, INSTALL_ALLOCATE_AGGRESSIVE, INSTALL_VIRTUAL_PRELOAD, @@ -816,15 +815,6 @@ public abstract class PackageManager { public static final int INSTALL_DONT_KILL_APP = 0x00001000; /** - * Flag parameter for {@link #installPackage} to indicate that this package is an - * upgrade to a package that refers to the SDK via release letter or is targeting an SDK via - * release letter that the current build does not support. - * - * @hide - */ - public static final int INSTALL_FORCE_SDK = 0x00002000; - - /** * Flag parameter for {@link #installPackage} to indicate that this package is * to be installed as a heavy weight app. This is fundamentally the opposite of * {@link #INSTALL_INSTANT_APP}. diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 5020a94c3469..0abd5eaaf2aa 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -839,7 +839,6 @@ public class PackageParser { public static final int PARSE_IS_SYSTEM_DIR = 1 << 4; public static final int PARSE_COLLECT_CERTIFICATES = 1 << 5; public static final int PARSE_ENFORCE_CODE = 1 << 6; - public static final int PARSE_FORCE_SDK = 1 << 7; public static final int PARSE_CHATTY = 1 << 31; @IntDef(flag = true, prefix = { "PARSE_" }, value = { @@ -847,7 +846,6 @@ public class PackageParser { PARSE_COLLECT_CERTIFICATES, PARSE_ENFORCE_CODE, PARSE_EXTERNAL_STORAGE, - PARSE_FORCE_SDK, PARSE_IGNORE_PROCESSES, PARSE_IS_SYSTEM_DIR, PARSE_MUST_BE_APK, @@ -2684,8 +2682,6 @@ public class PackageParser { * @param platformSdkCodenames array of allowed pre-release SDK codenames * for this platform * @param outError output array to populate with error, if applicable - * @param forceCurrentDev if development target code is not available, use the current - * development version by default. * @return the targetSdkVersion to use at runtime, or -1 if the package is * not compatible with this platform * @hide Exposed for unit testing only. @@ -2693,7 +2689,7 @@ public class PackageParser { @TestApi public static int computeTargetSdkVersion(@IntRange(from = 0) int targetVers, @Nullable String targetCode, @NonNull String[] platformSdkCodenames, - @NonNull String[] outError, boolean forceCurrentDev) { + @NonNull String[] outError) { // If it's a release SDK, return the version number unmodified. if (targetCode == null) { return targetVers; @@ -2701,7 +2697,7 @@ public class PackageParser { // If it's a pre-release SDK and the codename matches this platform, it // definitely targets this SDK. - if (matchTargetCode(platformSdkCodenames, targetCode) || forceCurrentDev) { + if (matchTargetCode(platformSdkCodenames, targetCode)) { return Build.VERSION_CODES.CUR_DEVELOPMENT; } @@ -2768,9 +2764,8 @@ public class PackageParser { return null; } - boolean defaultToCurrentDevBranch = (flags & PARSE_FORCE_SDK) != 0; final int targetSdkVersion = computeTargetSdkVersion(targetVers, - targetCode, SDK_CODENAMES, outError, defaultToCurrentDevBranch); + targetCode, SDK_CODENAMES, outError); if (targetSdkVersion < 0) { return null; } @@ -3752,6 +3747,13 @@ public class PackageParser { ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; } + if (sa.getBoolean( + com.android.internal.R.styleable + .AndroidManifestApplication_allowClearUserDataOnFailedRestore, + true)) { + ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE; + } + ai.maxAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0); ai.minAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_minAspectRatio, 0); diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index faf17e011b23..49b4cb01c6a6 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -47,6 +47,7 @@ import java.nio.channels.FileLock; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.Map; /** * Provides access to an application's raw asset files; see {@link Resources} @@ -1345,6 +1346,17 @@ public final class AssetManager implements AutoCloseable { } } + /** + * @hide + */ + @GuardedBy("this") + public @Nullable Map<String, String> getOverlayableMap(String packageName) { + synchronized (this) { + ensureValidLocked(); + return nativeGetOverlayableMap(mObject, packageName); + } + } + @GuardedBy("this") private void incRefsLocked(long id) { if (DEBUG_REFS) { @@ -1462,6 +1474,8 @@ public final class AssetManager implements AutoCloseable { private static native void nativeVerifySystemIdmaps(); private static native String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid(); + private static native @Nullable Map nativeGetOverlayableMap(long ptr, + @NonNull String packageName); // Global debug native methods. /** diff --git a/core/java/android/debug/AdbManagerInternal.java b/core/java/android/debug/AdbManagerInternal.java index 4469f0f965c3..51eb7fc2d804 100644 --- a/core/java/android/debug/AdbManagerInternal.java +++ b/core/java/android/debug/AdbManagerInternal.java @@ -16,6 +16,8 @@ package android.debug; +import java.io.File; + /** * This class allows the control of ADB-related functions that should only be called from the system * server. @@ -41,4 +43,14 @@ public abstract class AdbManagerInternal { * Returns {@code true} if ADB debugging is enabled. */ public abstract boolean isAdbEnabled(); + + /** + * Returns the file that contains all of the ADB keys used by the device. + */ + public abstract File getAdbKeysFile(); + + /** + * Returns the file that contains all of the ADB keys and their last used time. + */ + public abstract File getAdbTempKeysFile(); } diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java index c814b7c67817..1cb7eb0d1256 100644 --- a/core/java/android/hardware/biometrics/BiometricConstants.java +++ b/core/java/android/hardware/biometrics/BiometricConstants.java @@ -17,6 +17,7 @@ package android.hardware.biometrics; import android.annotation.UnsupportedAppUsage; +import android.app.KeyguardManager; /** @@ -126,6 +127,13 @@ public interface BiometricConstants { int BIOMETRIC_ERROR_NEGATIVE_BUTTON = 13; /** + * The device does not have pin, pattern, or password set up. See + * {@link BiometricPrompt.Builder#setAllowDeviceCredential(boolean)} and + * {@link KeyguardManager#isDeviceSecure()} + */ + int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14; + + /** * @hide */ @UnsupportedAppUsage diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java index b708ef12b210..459ec62d4135 100644 --- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java +++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java @@ -16,6 +16,7 @@ package android.hardware.biometrics; +import android.app.KeyguardManager; import android.hardware.face.FaceManager; /** @@ -134,6 +135,13 @@ public interface BiometricFaceConstants { public static final int FACE_ERROR_NEGATIVE_BUTTON = 13; /** + * The device does not have pin, pattern, or password set up. See + * {@link BiometricPrompt.Builder#setAllowDeviceCredential(boolean)} and + * {@link KeyguardManager#isDeviceSecure()} + */ + public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14; + + /** * @hide */ public static final int FACE_ERROR_VENDOR_BASE = 1000; diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java index 041b2e673b96..6cbab471ce23 100644 --- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java +++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java @@ -17,6 +17,7 @@ package android.hardware.biometrics; import android.annotation.UnsupportedAppUsage; +import android.app.KeyguardManager; import android.hardware.fingerprint.FingerprintManager; /** @@ -119,6 +120,14 @@ public interface BiometricFingerprintConstants { public static final int FINGERPRINT_ERROR_NEGATIVE_BUTTON = 13; /** + * The device does not have pin, pattern, or password set up. See + * {@link BiometricPrompt.Builder#setAllowDeviceCredential(boolean)} and + * {@link KeyguardManager#isDeviceSecure()} + * @hide + */ + public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14; + + /** * @hide */ @UnsupportedAppUsage diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index d569a7800c37..baf972b26573 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -23,6 +23,7 @@ import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.app.KeyguardManager; import android.content.Context; import android.content.DialogInterface; import android.os.Binder; @@ -80,7 +81,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan /** * @hide */ - public static final String KEY_ENABLE_FALLBACK = "enable_fallback"; + public static final String KEY_ALLOW_DEVICE_CREDENTIAL = "allow_device_credential"; /** * Error/help message will show for this amount of time. @@ -203,7 +204,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * "Cancel" button, but may be also used to show an alternative method for authentication, * such as screen that asks for a backup password. * - * Note that this should not be set if {@link #setEnableFallback(boolean)} is set to true. + * Note that this should not be set if {@link #setAllowDeviceCredential(boolean) + * is set to true. * * @param text * @return @@ -250,7 +252,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan /** * The user will first be prompted to authenticate with biometrics, but also given the - * option to authenticate with their device PIN, pattern, or password. + * option to authenticate with their device PIN, pattern, or password. Developers should + * first check {@link KeyguardManager#isDeviceSecure()} before enabling this. If the device + * is not secure, {@link BiometricPrompt#BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL} will be + * returned in {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)}} * * Note that {@link #setNegativeButton(CharSequence, Executor, * DialogInterface.OnClickListener)} should not be set if this is set to true. @@ -259,8 +264,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * credentials (PIN, pattern, or password). * @return */ - public Builder setEnableFallback(boolean enable) { - mBundle.putBoolean(KEY_ENABLE_FALLBACK, enable); + public Builder setAllowDeviceCredential(boolean enable) { + mBundle.putBoolean(KEY_ALLOW_DEVICE_CREDENTIAL, enable); return this; } @@ -273,7 +278,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan final CharSequence title = mBundle.getCharSequence(KEY_TITLE); final CharSequence negative = mBundle.getCharSequence(KEY_NEGATIVE_TEXT); final boolean useDefaultTitle = mBundle.getBoolean(KEY_USE_DEFAULT_TITLE); - final boolean enableFallback = mBundle.getBoolean(KEY_ENABLE_FALLBACK); + final boolean enableFallback = mBundle.getBoolean(KEY_ALLOW_DEVICE_CREDENTIAL); if (TextUtils.isEmpty(title) && !useDefaultTitle) { throw new IllegalArgumentException("Title must be set and non-empty"); @@ -281,7 +286,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan throw new IllegalArgumentException("Negative text must be set and non-empty"); } else if (!TextUtils.isEmpty(negative) && enableFallback) { throw new IllegalArgumentException("Can't have both negative button behavior" - + " and fallback enabled"); + + " and device credential enabled"); } return new BiometricPrompt(mContext, mBundle, mPositiveButtonInfo, mNegativeButtonInfo); } @@ -541,8 +546,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan if (callback == null) { throw new IllegalArgumentException("Must supply a callback"); } - if (mBundle.getBoolean(KEY_ENABLE_FALLBACK)) { - throw new IllegalArgumentException("Fallback not supported with crypto"); + if (mBundle.getBoolean(KEY_ALLOW_DEVICE_CREDENTIAL)) { + throw new IllegalArgumentException("Device credential not supported with crypto"); } authenticateInternal(crypto, cancel, executor, callback, mContext.getUserId()); } diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl index e4336d171ab6..a20e2bf3d067 100644 --- a/core/java/android/hardware/biometrics/IBiometricService.aidl +++ b/core/java/android/hardware/biometrics/IBiometricService.aidl @@ -54,7 +54,7 @@ interface IBiometricService { // TODO(b/123378871): Remove when moved. // CDCA needs to send results to BiometricService if it was invoked using BiometricPrompt's - // setEnableFallback method, since there's no way for us to intercept onActivityResult. + // setAllowDeviceCredential method, since there's no way for us to intercept onActivityResult. // CDCA is launched from BiometricService (startActivityAsUser) instead of *ForResult. void onConfirmDeviceCredentialSuccess(); // TODO(b/123378871): Remove when moved. diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java index 27f0b0425ec3..f413d7cc92af 100644 --- a/core/java/android/hardware/display/ColorDisplayManager.java +++ b/core/java/android/hardware/display/ColorDisplayManager.java @@ -365,6 +365,17 @@ public final class ColorDisplayManager { } /** + * Gets whether or not a non-default saturation level is currently applied to the display. + * + * @return {@code true} if the display is not at full saturation + * @hide + */ + @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) + public boolean isSaturationActivated() { + return mManager.isSaturationActivated(); + } + + /** * Set the level of color saturation to apply to a specific app. * * @param packageName the package name of the app whose windows should be desaturated @@ -588,6 +599,14 @@ public final class ColorDisplayManager { } } + boolean isSaturationActivated() { + try { + return mCdm.isSaturationActivated(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + boolean setAppSaturationLevel(String packageName, int saturationLevel) { try { return mCdm.setAppSaturationLevel(packageName, saturationLevel); diff --git a/core/java/android/hardware/display/IColorDisplayManager.aidl b/core/java/android/hardware/display/IColorDisplayManager.aidl index 30e76cfe2787..88b59a6eb8db 100644 --- a/core/java/android/hardware/display/IColorDisplayManager.aidl +++ b/core/java/android/hardware/display/IColorDisplayManager.aidl @@ -24,6 +24,7 @@ interface IColorDisplayManager { boolean setSaturationLevel(int saturationLevel); boolean setAppSaturationLevel(String packageName, int saturationLevel); + boolean isSaturationActivated(); int getTransformCapabilities(); diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index c9a7830d50f5..efe24e50272a 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -565,16 +565,16 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan */ public static String getErrorString(Context context, int errMsg, int vendorCode) { switch (errMsg) { - case FACE_ERROR_UNABLE_TO_PROCESS: - return context.getString( - com.android.internal.R.string.face_error_unable_to_process); case FACE_ERROR_HW_UNAVAILABLE: return context.getString( com.android.internal.R.string.face_error_hw_not_available); - case FACE_ERROR_NO_SPACE: - return context.getString(com.android.internal.R.string.face_error_no_space); + case FACE_ERROR_UNABLE_TO_PROCESS: + return context.getString( + com.android.internal.R.string.face_error_unable_to_process); case FACE_ERROR_TIMEOUT: return context.getString(com.android.internal.R.string.face_error_timeout); + case FACE_ERROR_NO_SPACE: + return context.getString(com.android.internal.R.string.face_error_no_space); case FACE_ERROR_CANCELED: return context.getString(com.android.internal.R.string.face_error_canceled); case FACE_ERROR_LOCKOUT: @@ -629,6 +629,24 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan return context.getString(R.string.face_acquired_poor_gaze); case FACE_ACQUIRED_NOT_DETECTED: return context.getString(R.string.face_acquired_not_detected); + case FACE_ACQUIRED_TOO_MUCH_MOTION: + return context.getString(R.string.face_acquired_too_much_motion); + case FACE_ACQUIRED_RECALIBRATE: + return context.getString(R.string.face_acquired_recalibrate); + case FACE_ACQUIRED_TOO_DIFFERENT: + return context.getString(R.string.face_acquired_too_different); + case FACE_ACQUIRED_TOO_SIMILAR: + return context.getString(R.string.face_acquired_too_similar); + case FACE_ACQUIRED_PAN_TOO_EXTREME: + return context.getString(R.string.face_acquired_pan_too_extreme); + case FACE_ACQUIRED_TILT_TOO_EXTREME: + return context.getString(R.string.face_acquired_tilt_too_extreme); + case FACE_ACQUIRED_ROLL_TOO_EXTREME: + return context.getString(R.string.face_acquired_roll_too_extreme); + case FACE_ACQUIRED_FACE_OBSCURED: + return context.getString(R.string.face_acquired_obscured); + case FACE_ACQUIRED_START: + return null; case FACE_ACQUIRED_VENDOR: { String[] msgArray = context.getResources().getStringArray( R.array.face_acquired_vendor); diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index bb9821169a54..80d404d03c75 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -949,17 +949,17 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing */ public static String getErrorString(Context context, int errMsg, int vendorCode) { switch (errMsg) { + case FINGERPRINT_ERROR_HW_UNAVAILABLE: + return context.getString( + com.android.internal.R.string.fingerprint_error_hw_not_available); case FINGERPRINT_ERROR_UNABLE_TO_PROCESS: return context.getString( com.android.internal.R.string.fingerprint_error_unable_to_process); - case FINGERPRINT_ERROR_HW_UNAVAILABLE: - return context.getString( - com.android.internal.R.string.fingerprint_error_hw_not_available); + case FINGERPRINT_ERROR_TIMEOUT: + return context.getString(com.android.internal.R.string.fingerprint_error_timeout); case FINGERPRINT_ERROR_NO_SPACE: return context.getString( com.android.internal.R.string.fingerprint_error_no_space); - case FINGERPRINT_ERROR_TIMEOUT: - return context.getString(com.android.internal.R.string.fingerprint_error_timeout); case FINGERPRINT_ERROR_CANCELED: return context.getString(com.android.internal.R.string.fingerprint_error_canceled); case FINGERPRINT_ERROR_LOCKOUT: diff --git a/core/java/android/net/INetworkMonitorCallbacks.aidl b/core/java/android/net/INetworkMonitorCallbacks.aidl index a8682f9ddd3b..514658549651 100644 --- a/core/java/android/net/INetworkMonitorCallbacks.aidl +++ b/core/java/android/net/INetworkMonitorCallbacks.aidl @@ -24,7 +24,7 @@ oneway interface INetworkMonitorCallbacks { void onNetworkMonitorCreated(in INetworkMonitor networkMonitor); void notifyNetworkTested(int testResult, @nullable String redirectUrl); void notifyPrivateDnsConfigResolved(in PrivateDnsConfigParcel config); - void showProvisioningNotification(String action); + void showProvisioningNotification(String action, String packageName); void hideProvisioningNotification(); void logCaptivePortalLoginEvent(int eventId, String packageName); }
\ No newline at end of file diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java index b6cd6359384a..7a4c9bc16ac7 100644 --- a/core/java/android/net/NetworkStack.java +++ b/core/java/android/net/NetworkStack.java @@ -63,9 +63,6 @@ public class NetworkStack { public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK"; - /** @hide */ - public static final String NETWORKSTACK_PACKAGE_NAME = "com.android.mainline.networkstack"; - private static final int NETWORKSTACK_TIMEOUT_MS = 10_000; @NonNull diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 629289bb7a45..0384faa88be5 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -1093,6 +1093,12 @@ public class FileUtils { return buildUniqueFileWithExtension(parent, parts[0], parts[1]); } + /** {@hide} */ + public static File buildNonUniqueFile(File parent, String mimeType, String displayName) { + final String[] parts = splitFileName(mimeType, displayName); + return buildFile(parent, parts[0], parts[1]); + } + /** * Generates a unique file name under the given parent directory, keeping * any extension intact. diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl index 93d6f4c12128..f1bba1ab2977 100644 --- a/core/java/android/os/IStatsManager.aidl +++ b/core/java/android/os/IStatsManager.aidl @@ -16,6 +16,8 @@ package android.os; +import android.os.IStatsPullerCallback; + /** * Binder interface to communicate with the statistics management service. * {@hide} @@ -178,4 +180,20 @@ interface IStatsManager { * this label. This allows building custom metrics and predicates. */ void sendAppBreadcrumbAtom(int label, int state); + + /** + * Registers a puller callback function that, when invoked, pulls the data + * for the specified vendor atom tag. + * + * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS + */ + oneway void registerPullerCallback(int atomTag, IStatsPullerCallback pullerCallback, + String packageName); + + /** + * Unregisters a puller callback function for the given vendor atom. + * + * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS + */ + oneway void unregisterPullerCallback(int atomTag, String packageName); } diff --git a/core/java/android/os/IStatsPullerCallback.aidl b/core/java/android/os/IStatsPullerCallback.aidl new file mode 100644 index 000000000000..1684aeb0d666 --- /dev/null +++ b/core/java/android/os/IStatsPullerCallback.aidl @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.os.StatsLogEventWrapper; + +/** + * Binder interface to pull atoms for the stats service. + * {@hide} + */ +interface IStatsPullerCallback { + /** + * Pull data for the specified atom tag. Returns an array of StatsLogEventWrapper containing + * the data. + * + * Note: These pulled atoms should not have uid/attribution chain. Additionally, the event + * timestamps will be truncated to the nearest 5 minutes. + */ + StatsLogEventWrapper[] pullData(int atomTag, long elapsedNanos, long wallClocknanos); + +} diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index d2ab053eb4e6..9e97e375753c 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -526,11 +526,12 @@ public class Process { @Nullable String packageName, @Nullable String[] packagesForUid, @Nullable String[] visibleVols, + @Nullable String sandboxId, @Nullable String[] zygoteArgs) { return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packageName, - packagesForUid, visibleVols, /*useBlastulaPool=*/ true, zygoteArgs); + packagesForUid, visibleVols, sandboxId, /*useBlastulaPool=*/ true, zygoteArgs); } /** @hide */ @@ -547,11 +548,12 @@ public class Process { @Nullable String packageName, @Nullable String[] packagesForUid, @Nullable String[] visibleVols, + @Nullable String sandboxId, @Nullable String[] zygoteArgs) { return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packageName, - packagesForUid, visibleVols, /*useBlastulaPool=*/ false, zygoteArgs); + packagesForUid, visibleVols, sandboxId, /*useBlastulaPool=*/ false, zygoteArgs); } /** diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java index acb9eac3572c..23342426693a 100644 --- a/core/java/android/os/StatsLogEventWrapper.java +++ b/core/java/android/os/StatsLogEventWrapper.java @@ -57,20 +57,18 @@ public final class StatsLogEventWrapper implements Parcelable { public static final Parcelable.Creator<StatsLogEventWrapper> CREATOR = new Parcelable.Creator<StatsLogEventWrapper>() { public StatsLogEventWrapper createFromParcel(Parcel in) { - android.util.EventLog.writeEvent(0x534e4554, "112550251", - android.os.Binder.getCallingUid(), ""); - // Purposefully leaving this method not implemented. - throw new RuntimeException("Not implemented"); + return new StatsLogEventWrapper(in); } public StatsLogEventWrapper[] newArray(int size) { - android.util.EventLog.writeEvent(0x534e4554, "112550251", - android.os.Binder.getCallingUid(), ""); - // Purposefully leaving this method not implemented. - throw new RuntimeException("Not implemented"); + return new StatsLogEventWrapper[size]; } }; + private StatsLogEventWrapper(Parcel in) { + readFromParcel(in); + } + /** * Set work source if any. */ @@ -197,6 +195,70 @@ public final class StatsLogEventWrapper implements Parcelable { } /** + * Reads from parcel and appropriately fills member fields. + */ + public void readFromParcel(Parcel in) { + mTypes = new ArrayList<>(); + mValues = new ArrayList<>(); + mWorkSource = null; + + mTag = in.readInt(); + mElapsedTimeNs = in.readLong(); + mWallClockTimeNs = in.readLong(); + + // Clear any data. + if (DEBUG) { + Slog.d(TAG, "Reading " + mTag + " " + mElapsedTimeNs + " " + mWallClockTimeNs); + } + // Set up worksource if present. + int numWorkChains = in.readInt(); + if (numWorkChains > 0) { + mWorkSource = new WorkSource(); + for (int i = 0; i < numWorkChains; i++) { + android.os.WorkSource.WorkChain workChain = mWorkSource.createWorkChain(); + int workChainSize = in.readInt(); + for (int j = 0; j < workChainSize; j++) { + int uid = in.readInt(); + String tag = in.readString(); + workChain.addNode(uid, tag); + } + } + } + + // Do the rest of the types. + int numTypes = in.readInt(); + if (DEBUG) { + Slog.d(TAG, "Reading " + numTypes + " elements"); + } + for (int i = 0; i < numTypes; i++) { + int type = in.readInt(); + mTypes.add(type); + switch (type) { + case EVENT_TYPE_INT: + mValues.add(in.readInt()); + break; + case EVENT_TYPE_LONG: + mValues.add(in.readLong()); + break; + case EVENT_TYPE_FLOAT: + mValues.add(in.readFloat()); + break; + case EVENT_TYPE_DOUBLE: + mValues.add(in.readDouble()); + break; + case EVENT_TYPE_STRING: + mValues.add(in.readString()); + break; + case EVENT_TYPE_STORAGE: + mValues.add(in.createByteArray()); + break; + default: + break; + } + } + } + + /** * Boilerplate for Parcel. */ public int describeContents() { diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index e94ad2b8989e..ee3d35427b29 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -324,13 +324,15 @@ public class ZygoteProcess { @Nullable String packageName, @Nullable String[] packagesForUid, @Nullable String[] visibleVols, + @Nullable String sandboxId, boolean useBlastulaPool, @Nullable String[] zygoteArgs) { try { return startViaZygote(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/false, - packageName, packagesForUid, visibleVols, useBlastulaPool, zygoteArgs); + packageName, packagesForUid, visibleVols, sandboxId, + useBlastulaPool, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); @@ -541,6 +543,7 @@ public class ZygoteProcess { @Nullable String packageName, @Nullable String[] packagesForUid, @Nullable String[] visibleVols, + @Nullable String sandboxId, boolean useBlastulaPool, @Nullable String[] extraArgs) throws ZygoteStartFailedEx { @@ -639,6 +642,10 @@ public class ZygoteProcess { argsForZygote.add(sb.toString()); } + if (sandboxId != null) { + argsForZygote.add("--sandbox-id=" + sandboxId); + } + argsForZygote.add(processClass); if (extraArgs != null) { @@ -1014,7 +1021,7 @@ public class ZygoteProcess { gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo, abi, instructionSet, null /* appDataDir */, null /* invokeWith */, true /* startChildZygote */, null /* packageName */, - null /* packagesForUid */, null /* visibleVolumes */, + null /* packagesForUid */, null /* visibleVolumes */, null /* sandboxId */, false /* useBlastulaPool */, extraArgs); } catch (ZygoteStartFailedEx ex) { throw new RuntimeException("Starting child-zygote through Zygote failed", ex); diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index f521c683896e..03b2c2c4c6f2 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -132,4 +132,9 @@ public abstract class StorageManagerInternal { * @param listener The listener that will be notified on reset events. */ public abstract void addResetListener(ResetListener listener); + + /** + * Return the sandboxId for the given package on external storage. + */ + public abstract String getSandboxId(String packageName); } diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 8e7906eb3c06..18e1f5902a31 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -69,48 +69,17 @@ public final class DeviceConfig { * @hide */ @SystemApi + @TestApi public static final String NAMESPACE_AUTOFILL = "autofill"; /** - * ContentCapture-related properties definitions. - * - * @hide - */ - @SystemApi - public interface ContentCapture { - String NAMESPACE = "content_capture"; - - /** - * Property used by {@code com.android.server.SystemServer} on start to decide whether - * the Content Capture service should be created or not. - * - * <p>Possible values are: - * - * <ul> - * <li>If set to {@code default}, it will only be set if the OEM provides and defines the - * service name by overlaying {@code config_defaultContentCaptureService} (this is the - * "default" mode) - * <li>If set to {@code always}, it will always be enabled, even when the resource is not - * overlaid (this is useful during development and to run the CTS tests on AOSP builds). - * <li>Otherwise, it's explicitly disabled (this could work as a "kill switch" so OEMs - * can disable it remotely in case of emergency by setting to something else (like - * {@code "false"}); notice that it's also disabled if the OEM doesn't explicitly set one - * of the values above). - * </ul> - * - * @hide - */ - // TODO(b/121153631): revert back to SERVICE_EXPLICITLY_ENABLED approach - String PROPERTY_CONTENTCAPTURE_ENABLED = "enable_contentcapture"; - } - - /** * Namespace for content capture feature used by on-device machine intelligence * to provide suggestions in a privacy-safe manner. * * @hide */ @SystemApi + @TestApi public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; /** @@ -154,6 +123,21 @@ public final class DeviceConfig { } /** + * Namespace for all runtime related features. + * + * @hide + */ + @SystemApi + public interface Runtime { + String NAMESPACE = "runtime"; + + /** + * Whether or not we use the precompiled layout. + */ + String USE_PRECOMPILED_LAYOUT = "view.precompiled_layout_enabled"; + } + + /** * Namespace for all runtime native related features. * * @hide @@ -340,6 +324,25 @@ public final class DeviceConfig { String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled"; } + /** + * Namespace for system scheduler related features. These features will be applied + * immediately upon change. + * + * @hide + */ + @SystemApi + public interface Scheduler { + String NAMESPACE = "scheduler"; + + /** + * Flag for enabling fast metrics collection in system scheduler. + * A flag value of '' or '0' means the fast metrics collection is not + * enabled. Otherwise fast metrics collection is enabled and flag value + * is the order id. + */ + String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection"; + } + private static final Object sLock = new Object(); @GuardedBy("sLock") private static Map<OnPropertyChangedListener, Pair<String, Executor>> sListeners = @@ -360,6 +363,7 @@ public final class DeviceConfig { * @hide */ @SystemApi + @TestApi @RequiresPermission(READ_DEVICE_CONFIG) public static String getProperty(String namespace, String name) { ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver(); @@ -430,6 +434,7 @@ public final class DeviceConfig { * @see #removeOnPropertyChangedListener(OnPropertyChangedListener) */ @SystemApi + @TestApi @RequiresPermission(READ_DEVICE_CONFIG) public static void addOnPropertyChangedListener( @NonNull String namespace, @@ -463,6 +468,7 @@ public final class DeviceConfig { * @see #addOnPropertyChangedListener(String, Executor, OnPropertyChangedListener) */ @SystemApi + @TestApi public static void removeOnPropertyChangedListener( OnPropertyChangedListener onPropertyChangedListener) { synchronized (sLock) { @@ -559,6 +565,7 @@ public final class DeviceConfig { * @hide */ @SystemApi + @TestApi public interface OnPropertyChangedListener { /** * Called when a property has changed. diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 67c840006948..0b3842080a75 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -157,10 +157,6 @@ public final class MediaStore { public static final String PARAM_DELETE_DATA = "deletedata"; /** {@hide} */ - public static final String PARAM_PRIMARY = "primary"; - /** {@hide} */ - public static final String PARAM_SECONDARY = "secondary"; - /** {@hide} */ public static final String PARAM_INCLUDE_PENDING = "includePending"; /** {@hide} */ public static final String PARAM_INCLUDE_TRASHED = "includeTrashed"; @@ -543,7 +539,9 @@ public final class MediaStore { * @see MediaStore#setIncludeTrashed(Uri) * @see MediaStore#trash(Context, Uri) * @see MediaStore#untrash(Context, Uri) + * @removed */ + @Deprecated public static @NonNull Uri setIncludeTrashed(@NonNull Uri uri) { return uri.buildUpon().appendQueryParameter(PARAM_INCLUDE_TRASHED, "1").build(); } @@ -580,14 +578,7 @@ public final class MediaStore { */ public static @NonNull Uri createPending(@NonNull Context context, @NonNull PendingParams params) { - final Uri.Builder builder = params.insertUri.buildUpon(); - if (!TextUtils.isEmpty(params.primaryDirectory)) { - builder.appendQueryParameter(PARAM_PRIMARY, params.primaryDirectory); - } - if (!TextUtils.isEmpty(params.secondaryDirectory)) { - builder.appendQueryParameter(PARAM_SECONDARY, params.secondaryDirectory); - } - return context.getContentResolver().insert(builder.build(), params.insertValues); + return context.getContentResolver().insert(params.insertUri, params.insertValues); } /** @@ -610,10 +601,6 @@ public final class MediaStore { public final Uri insertUri; /** {@hide} */ public final ContentValues insertValues; - /** {@hide} */ - public String primaryDirectory; - /** {@hide} */ - public String secondaryDirectory; /** * Create parameters that describe a pending media item. @@ -655,7 +642,11 @@ public final class MediaStore { * @see MediaColumns#PRIMARY_DIRECTORY */ public void setPrimaryDirectory(@Nullable String primaryDirectory) { - this.primaryDirectory = primaryDirectory; + if (primaryDirectory == null) { + this.insertValues.remove(MediaColumns.PRIMARY_DIRECTORY); + } else { + this.insertValues.put(MediaColumns.PRIMARY_DIRECTORY, primaryDirectory); + } } /** @@ -668,7 +659,11 @@ public final class MediaStore { * @see MediaColumns#SECONDARY_DIRECTORY */ public void setSecondaryDirectory(@Nullable String secondaryDirectory) { - this.secondaryDirectory = secondaryDirectory; + if (secondaryDirectory == null) { + this.insertValues.remove(MediaColumns.SECONDARY_DIRECTORY); + } else { + this.insertValues.put(MediaColumns.SECONDARY_DIRECTORY, secondaryDirectory); + } } /** @@ -797,7 +792,9 @@ public final class MediaStore { * @see MediaStore#setIncludeTrashed(Uri) * @see MediaStore#trash(Context, Uri) * @see MediaStore#untrash(Context, Uri) + * @removed */ + @Deprecated public static void trash(@NonNull Context context, @NonNull Uri uri) { trash(context, uri, 48 * DateUtils.HOUR_IN_MILLIS); } @@ -815,7 +812,9 @@ public final class MediaStore { * @see MediaStore#setIncludeTrashed(Uri) * @see MediaStore#trash(Context, Uri) * @see MediaStore#untrash(Context, Uri) + * @removed */ + @Deprecated public static void trash(@NonNull Context context, @NonNull Uri uri, @DurationMillisLong long timeoutMillis) { if (timeoutMillis < 0) { @@ -837,7 +836,9 @@ public final class MediaStore { * @see MediaStore#setIncludeTrashed(Uri) * @see MediaStore#trash(Context, Uri) * @see MediaStore#untrash(Context, Uri) + * @removed */ + @Deprecated public static void untrash(@NonNull Context context, @NonNull Uri uri) { final ContentValues values = new ContentValues(); values.put(MediaColumns.IS_TRASHED, 0); @@ -884,7 +885,9 @@ public final class MediaStore { * hash is calculated. * <p> * Type: BLOB + * @removed */ + @Deprecated public static final String HASH = "_hash"; /** @@ -921,8 +924,22 @@ public final class MediaStore { public static final String DATE_MODIFIED = "date_modified"; /** - * The MIME type of the file - * <P>Type: TEXT</P> + * The MIME type of the media item. + * <p> + * This is typically defined based on the file extension of the media + * item. However, it may be the value of the {@code format} attribute + * defined by the <em>Dublin Core Media Initiative</em> standard, + * extracted from any XMP metadata contained within this media item. + * <p class="note"> + * Note: the {@code format} attribute may be ignored if the top-level + * MIME type disagrees with the file extension. For example, it's + * reasonable for an {@code image/jpeg} file to declare a {@code format} + * of {@code image/vnd.google.panorama360+jpg}, but declaring a + * {@code format} of {@code audio/ogg} would be ignored. + * <p> + * This is a read-only column that is automatically computed. + * <p> + * Type: TEXT */ public static final String MIME_TYPE = "mime_type"; @@ -965,7 +982,9 @@ public final class MediaStore { * @see MediaStore#setIncludeTrashed(Uri) * @see MediaStore#trash(Context, Uri) * @see MediaStore#untrash(Context, Uri) + * @removed */ + @Deprecated public static final String IS_TRASHED = "is_trashed"; /** @@ -974,7 +993,9 @@ public final class MediaStore { * {@link #IS_PENDING} or {@link #IS_TRASHED}. * <p> * Type: INTEGER + * @removed */ + @Deprecated public static final String DATE_EXPIRES = "date_expires"; /** @@ -991,6 +1012,8 @@ public final class MediaStore { * Package name that contributed this media. The value may be * {@code NULL} if ownership cannot be reliably determined. * <p> + * This is a read-only column that is automatically computed. + * <p> * Type: TEXT */ public static final String OWNER_PACKAGE_NAME = "owner_package_name"; @@ -1014,6 +1037,52 @@ public final class MediaStore { * @see PendingParams#setSecondaryDirectory(String) */ public static final String SECONDARY_DIRECTORY = "secondary_directory"; + + /** + * The "document ID" GUID as defined by the <em>XMP Media + * Management</em> standard, extracted from any XMP metadata contained + * within this media item. The value is {@code null} when no metadata + * was found. + * <p> + * Each "document ID" is created once for each new resource. Different + * renditions of that resource are expected to have different IDs. + * <p> + * This is a read-only column that is automatically computed. + * <p> + * Type: TEXT + */ + public static final String DOCUMENT_ID = "document_id"; + + /** + * The "instance ID" GUID as defined by the <em>XMP Media + * Management</em> standard, extracted from any XMP metadata contained + * within this media item. The value is {@code null} when no metadata + * was found. + * <p> + * This "instance ID" changes with each save operation of a specific + * "document ID". + * <p> + * This is a read-only column that is automatically computed. + * <p> + * Type: TEXT + */ + public static final String INSTANCE_ID = "instance_id"; + + /** + * The "original document ID" GUID as defined by the <em>XMP Media + * Management</em> standard, extracted from any XMP metadata contained + * within this media item. + * <p> + * This "original document ID" links a resource to its original source. + * For example, when you save a PSD document as a JPEG, then convert the + * JPEG to GIF format, the "original document ID" of both the JPEG and + * GIF files is the "document ID" of the original PSD file. + * <p> + * This is a read-only column that is automatically computed. + * <p> + * Type: TEXT + */ + public static final String ORIGINAL_DOCUMENT_ID = "original_document_id"; } /** @@ -3097,20 +3166,29 @@ public final class MediaStore { final ArrayList<File> res = new ArrayList<>(); if (VOLUME_INTERNAL.equals(volumeName)) { - res.add(new File(Environment.getRootDirectory(), "media")); - res.add(new File(Environment.getOemDirectory(), "media")); - res.add(new File(Environment.getProductDirectory(), "media")); + addCanoncialFile(res, new File(Environment.getRootDirectory(), "media")); + addCanoncialFile(res, new File(Environment.getOemDirectory(), "media")); + addCanoncialFile(res, new File(Environment.getProductDirectory(), "media")); } else { - res.add(getVolumePath(volumeName)); + addCanoncialFile(res, getVolumePath(volumeName)); final UserManager um = AppGlobals.getInitialApplication() .getSystemService(UserManager.class); if (VOLUME_EXTERNAL.equals(volumeName) && um.isDemoUser()) { - res.add(Environment.getDataPreloadsMediaDirectory()); + addCanoncialFile(res, Environment.getDataPreloadsMediaDirectory()); } } return res; } + private static void addCanoncialFile(List<File> list, File file) { + try { + list.add(file.getCanonicalFile()); + } catch (IOException e) { + Log.w(TAG, "Failed to resolve " + file + ": " + e); + list.add(file); + } + } + /** * Uri for querying the state of the media scanner. */ diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index e95d60465371..c4019adb5d85 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8289,6 +8289,7 @@ public final class Settings { * The value is boolean (1 or 0). * @hide */ + @TestApi public static final String NOTIFICATION_BADGING = "notification_badging"; private static final Validator NOTIFICATION_BADGING_VALIDATOR = BOOLEAN_VALIDATOR; @@ -12346,6 +12347,12 @@ public final class Settings { public static final String GAME_DRIVER_BLACKLIST = "game_driver_blacklist"; /** + * List of blacklists, each blacklist is a blacklist for a specific version of Game Driver. + * @hide + */ + public static final String GAME_DRIVER_BLACKLISTS = "game_driver_blacklists"; + + /** * Apps on the whitelist that are allowed to use Game Driver. * The string is a list of application package names, seperated by comma. * i.e. <apk1>,<apk2>,...,<apkN> @@ -13284,17 +13291,6 @@ public final class Settings { public static final String AUTOFILL_MAX_VISIBLE_DATASETS = "autofill_max_visible_datasets"; /** - * Used to emulate Smart Suggestion for Augmented Autofill during development - * - * <p>Valid values: {@code 0x1} for IME and/or {@code 0x2} for popup window. - * - * @hide - */ - @TestApi - public static final String AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS = - "autofill_smart_suggestion_emulation_flags"; - - /** * Exemptions to the hidden API blacklist. * * @hide @@ -13353,6 +13349,14 @@ public final class Settings { public static final String ISOLATED_STORAGE_REMOTE = "isolated_storage_remote"; /** + * Indicates whether aware is available in the current location. + * @hide + */ + public static final String AWARE_ALLOWED = "aware_allowed"; + + private static final Validator AWARE_ALLOWED_VALIDATOR = BOOLEAN_VALIDATOR; + + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. * @@ -13398,6 +13402,7 @@ public final class Settings { SOFT_AP_TIMEOUT_ENABLED, ZEN_DURATION, CHARGING_VIBRATION_ENABLED, + AWARE_ALLOWED, }; /** @@ -13458,6 +13463,7 @@ public final class Settings { VALIDATORS.put(WIFI_PNO_RECENCY_SORTING_ENABLED, WIFI_PNO_RECENCY_SORTING_ENABLED_VALIDATOR); VALIDATORS.put(WIFI_LINK_PROBING_ENABLED, WIFI_LINK_PROBING_ENABLED_VALIDATOR); + VALIDATORS.put(AWARE_ALLOWED, AWARE_ALLOWED_VALIDATOR); } /** diff --git a/core/java/android/service/textclassifier/TEST_MAPPING b/core/java/android/service/textclassifier/TEST_MAPPING new file mode 100644 index 000000000000..ccf26315852d --- /dev/null +++ b/core/java/android/service/textclassifier/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "imports": [ + { + "path": "frameworks/base/core/java/android/view/textclassifier" + } + ] +} diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 03e8a0fc0d39..c64386e8db79 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -133,7 +133,7 @@ public final class Choreographer { }; // Enable/disable vsync for animations and drawing. - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769497) private static final boolean USE_VSYNC = SystemProperties.getBoolean( "debug.choreographer.vsync", true); diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index e3a6bd7a6949..49bae280321e 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -32,6 +32,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerGlobal; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.Process; @@ -495,7 +496,7 @@ public final class Display { * @return True if the display is still valid. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public boolean getDisplayInfo(DisplayInfo outDisplayInfo) { synchronized (this) { updateDisplayInfoLocked(); diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index ff4ee9ce7ded..ad8fee978c9a 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -158,8 +158,9 @@ public final class DisplayInfo implements Parcelable { * * @hide */ + // Remark on @UnsupportedAppUsage: Display.getCutout should be used instead @Nullable - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public DisplayCutout displayCutout; /** diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 8ae4757f5de6..2ef7c4b16d9d 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -25,6 +25,7 @@ import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.GraphicBuffer; +import android.graphics.Insets; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; @@ -380,6 +381,16 @@ interface IWindowManager void getStableInsets(int displayId, out Rect outInsets); /** + * Set the forwarded insets on the display. + * <p> + * This is only used in case a virtual display is displayed on another display that has insets, + * and the bounds of the virtual display is overlapping with the insets from the host display. + * In that case, the contents on the virtual display won't be placed over the forwarded insets. + * Only the owner of the display is permitted to set the forwarded insets on it. + */ + void setForwardedInsets(int displayId, in Insets insets); + + /** * Register shortcut key. Shortcut code is packed as: * (MetaState << Integer.SIZE) | KeyCode * @hide diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index 7295259a0f89..868a9de93972 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -22,6 +22,7 @@ import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputManager; +import android.os.Build; import android.os.NullVibrator; import android.os.Parcel; import android.os.Parcelable; @@ -54,7 +55,7 @@ public final class InputDevice implements Parcelable { private final int mProductId; private final String mDescriptor; private final InputDeviceIdentifier mIdentifier; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private final boolean mIsExternal; private final int mSources; private final int mKeyboardType; @@ -608,10 +609,7 @@ public final class InputDevice implements Parcelable { * peripheral bus), otherwise it is built-in. * * @return True if the device is external. - * - * @hide */ - @UnsupportedAppUsage public boolean isExternal() { return mIsExternal; } diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index 583651dee379..dd88e3c34d30 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -33,6 +33,7 @@ import android.util.SparseSetArray; import android.view.InsetsState.InsetSide; import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams; import android.view.WindowInsets.Type.InsetType; +import android.view.WindowManager.LayoutParams; import com.android.internal.annotations.VisibleForTesting; @@ -165,7 +166,8 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll @Nullable @InsetSide SparseIntArray typeSideMap) { return state.calculateInsets(frame, false /* isScreenRound */, false /* alwaysConsumerNavBar */, null /* displayCutout */, - null /* legacyContentInsets */, null /* legacyStableInsets */, typeSideMap) + null /* legacyContentInsets */, null /* legacyStableInsets */, + LayoutParams.SOFT_INPUT_ADJUST_RESIZE /* legacySoftInputMode*/, typeSideMap) .getInsets(mTypes); } diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 7ad97a6d393e..258600019e71 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -112,6 +112,8 @@ public class InsetsController implements WindowInsetsController { private int mPendingTypesToShow; + private int mLastLegacySoftInputMode; + public InsetsController(ViewRootImpl viewRoot) { mViewRoot = viewRoot; mAnimCallback = () -> { @@ -126,13 +128,17 @@ public class InsetsController implements WindowInsetsController { } WindowInsets insets = state.calculateInsets(mFrame, mLastInsets.isRound(), mLastInsets.shouldAlwaysConsumeNavBar(), mLastInsets.getDisplayCutout(), - mLastLegacyContentInsets, mLastLegacyStableInsets, + mLastLegacyContentInsets, mLastLegacyStableInsets, mLastLegacySoftInputMode, null /* typeSideMap */); mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets); }; } void onFrameChanged(Rect frame) { + if (mFrame.equals(frame)) { + return; + } + mViewRoot.notifyInsetsChanged(); mFrame.set(frame); } @@ -160,11 +166,12 @@ public class InsetsController implements WindowInsetsController { @VisibleForTesting public WindowInsets calculateInsets(boolean isScreenRound, boolean alwaysConsumeNavBar, DisplayCutout cutout, Rect legacyContentInsets, - Rect legacyStableInsets) { + Rect legacyStableInsets, int legacySoftInputMode) { mLastLegacyContentInsets.set(legacyContentInsets); mLastLegacyStableInsets.set(legacyStableInsets); + mLastLegacySoftInputMode = legacySoftInputMode; mLastInsets = mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeNavBar, cutout, - legacyContentInsets, legacyStableInsets, + legacyContentInsets, legacyStableInsets, legacySoftInputMode, null /* typeSideMap */); return mLastInsets; } @@ -257,11 +264,21 @@ public class InsetsController implements WindowInsetsController { private void controlWindowInsetsAnimation(@InsetType int types, WindowInsetsAnimationControlListener listener, boolean fromIme) { + // If the frame of our window doesn't span the entire display, the control API makes very + // little sense, as we don't deal with negative insets. So just cancel immediately. + if (!mState.getDisplayFrame().equals(mFrame)) { + listener.onCancelled(); + return; + } + controlAnimationUnchecked(types, listener, mFrame, fromIme); + } + + private void controlAnimationUnchecked(@InsetType int types, + WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme) { if (types == 0) { // nothing to animate. return; } - // TODO: Check whether we already have a controller. final ArraySet<Integer> internalTypes = mState.toInternalType(types); final SparseArray<InsetsSourceConsumer> consumers = new SparseArray<>(); @@ -285,7 +302,7 @@ public class InsetsController implements WindowInsetsController { } final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(consumers, - mFrame, mState, listener, typesReady, + frame, mState, listener, typesReady, () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView), this); mAnimationControls.add(controller); } @@ -436,6 +453,7 @@ public class InsetsController implements WindowInsetsController { // nothing to animate. return; } + WindowInsetsAnimationControlListener listener = new WindowInsetsAnimationControlListener() { @Override public void onReady(WindowInsetsAnimationController controller, int types) { @@ -479,7 +497,10 @@ public class InsetsController implements WindowInsetsController { // TODO: Instead of clearing this here, properly wire up // InsetsAnimationControlImpl.finish() to remove this from mAnimationControls. mAnimationControls.clear(); - controlWindowInsetsAnimation(types, listener, fromIme); + + // Show/hide animations always need to be relative to the display frame, in order that shown + // and hidden state insets are correct. + controlAnimationUnchecked(types, listener, mState.getDisplayFrame(), fromIme); } private void hideDirectly(@InsetType int types) { diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 4f809fe6d54a..69f86aa5b37e 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -19,6 +19,7 @@ package android.view; import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; +import static android.view.WindowInsets.Type.IME; import static android.view.WindowInsets.Type.SIZE; import static android.view.WindowInsets.Type.indexOf; @@ -34,11 +35,13 @@ import android.util.SparseArray; import android.util.SparseIntArray; import android.view.WindowInsets.Type; import android.view.WindowInsets.Type.InsetType; +import android.view.WindowManager.LayoutParams; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Objects; /** * Holder for state of system windows that cause window insets for all other windows in the system. @@ -104,6 +107,11 @@ public class InsetsState implements Parcelable { private final ArrayMap<Integer, InsetsSource> mSources = new ArrayMap<>(); + /** + * The frame of the display these sources are relative to. + */ + private final Rect mDisplayFrame = new Rect(); + public InsetsState() { } @@ -124,7 +132,7 @@ public class InsetsState implements Parcelable { public WindowInsets calculateInsets(Rect frame, boolean isScreenRound, boolean alwaysConsumeNavBar, DisplayCutout cutout, @Nullable Rect legacyContentInsets, @Nullable Rect legacyStableInsets, - @Nullable @InsetSide SparseIntArray typeSideMap) { + int legacySoftInputMode, @Nullable @InsetSide SparseIntArray typeSideMap) { Insets[] typeInsetsMap = new Insets[Type.SIZE]; Insets[] typeMaxInsetsMap = new Insets[Type.SIZE]; boolean[] typeVisibilityMap = new boolean[SIZE]; @@ -140,8 +148,12 @@ public class InsetsState implements Parcelable { if (source == null) { continue; } - if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL - && (type == TYPE_TOP_BAR || type == TYPE_NAVIGATION_BAR)) { + + boolean skipSystemBars = ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL + && (type == TYPE_TOP_BAR || type == TYPE_NAVIGATION_BAR); + boolean skipIme = source.getType() == TYPE_IME + && (legacySoftInputMode & LayoutParams.SOFT_INPUT_ADJUST_RESIZE) == 0; + if (skipSystemBars || skipIme) { typeVisibilityMap[indexOf(toPublicType(type))] = source.isVisible(); continue; } @@ -209,6 +221,14 @@ public class InsetsState implements Parcelable { return mSources.computeIfAbsent(type, InsetsSource::new); } + public void setDisplayFrame(Rect frame) { + mDisplayFrame.set(frame); + } + + public Rect getDisplayFrame() { + return mDisplayFrame; + } + /** * Modifies the state of this class to exclude a certain type to make it ready for dispatching * to the client. @@ -224,6 +244,7 @@ public class InsetsState implements Parcelable { } public void set(InsetsState other, boolean copySources) { + mDisplayFrame.set(other.mDisplayFrame); mSources.clear(); if (copySources) { for (int i = 0; i < other.mSources.size(); i++) { @@ -323,6 +344,9 @@ public class InsetsState implements Parcelable { InsetsState state = (InsetsState) o; + if (!mDisplayFrame.equals(state.mDisplayFrame)) { + return false; + } if (mSources.size() != state.mSources.size()) { return false; } @@ -341,7 +365,7 @@ public class InsetsState implements Parcelable { @Override public int hashCode() { - return mSources.hashCode(); + return Objects.hash(mDisplayFrame, mSources); } public InsetsState(Parcel in) { @@ -355,9 +379,10 @@ public class InsetsState implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(mDisplayFrame, flags); dest.writeInt(mSources.size()); for (int i = 0; i < mSources.size(); i++) { - dest.writeParcelable(mSources.valueAt(i), 0 /* flags */); + dest.writeParcelable(mSources.valueAt(i), flags); } } @@ -374,6 +399,7 @@ public class InsetsState implements Parcelable { public void readFromParcel(Parcel in) { mSources.clear(); + mDisplayFrame.set(in.readParcelable(null /* loader */)); final int size = in.readInt(); for (int i = 0; i < size; i++) { final InsetsSource source = in.readParcelable(null /* loader */); diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index 6a290b7fe045..b28ac4714e90 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -33,6 +33,8 @@ import android.os.Handler; import android.os.Message; import android.os.SystemProperties; import android.os.Trace; +import android.provider.DeviceConfig; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; @@ -42,14 +44,16 @@ import android.widget.FrameLayout; import com.android.internal.R; import dalvik.system.PathClassLoader; -import java.io.File; -import java.lang.reflect.Method; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; +import java.lang.reflect.Method; import java.util.HashMap; +import java.util.Objects; /** * Instantiates a layout XML file into its corresponding {@link android.view.View} @@ -78,8 +82,6 @@ public abstract class LayoutInflater { private static final String TAG = LayoutInflater.class.getSimpleName(); private static final boolean DEBUG = false; - private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY - = "view.precompiled_layout_enabled"; private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex"; /** Empty stack trace used to avoid log spam in re-throw exceptions. */ @@ -93,7 +95,12 @@ public abstract class LayoutInflater { protected final Context mContext; // these are optional, set by the caller - @UnsupportedAppUsage + /** + * If any developer has desire to change this value, they should instead use + * {@link #cloneInContext(Context)} and set the new factory in thew newly-created + * LayoutInflater. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private boolean mFactorySet; @UnsupportedAppUsage private Factory mFactory; @@ -110,7 +117,12 @@ public abstract class LayoutInflater { // The classloader includes the generated compiled_view.dex file. private ClassLoader mPrecompiledClassLoader; - @UnsupportedAppUsage + /** + * This is not a public API. Two APIs are now available to alleviate the need to access + * this directly: {@link #createView(Context, String, String, AttributeSet)} and + * {@link #onCreateView(Context, View, String, AttributeSet)}. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) final Object[] mConstructorArgs = new Object[2]; @UnsupportedAppUsage @@ -400,8 +412,24 @@ public abstract class LayoutInflater { } private void initPrecompiledViews() { - initPrecompiledViews( - SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false)); + // Use the device config if enabled, otherwise default to the system property. + String usePrecompiledLayout = null; + try { + usePrecompiledLayout = DeviceConfig.getProperty( + DeviceConfig.Runtime.NAMESPACE, + DeviceConfig.Runtime.USE_PRECOMPILED_LAYOUT); + } catch (Exception e) { + // May be caused by permission errors reading the property (i.e. instant apps). + } + boolean enabled = false; + if (TextUtils.isEmpty(usePrecompiledLayout)) { + enabled = SystemProperties.getBoolean( + DeviceConfig.Runtime.USE_PRECOMPILED_LAYOUT, + false); + } else { + enabled = Boolean.parseBoolean(usePrecompiledLayout); + } + initPrecompiledViews(enabled); } private void initPrecompiledViews(boolean enablePrecompiledViews) { @@ -721,6 +749,32 @@ public abstract class LayoutInflater { } while (cl != null); return false; } + /** + * Low-level function for instantiating a view by name. This attempts to + * instantiate a view class of the given <var>name</var> found in this + * LayoutInflater's ClassLoader. To use an explicit Context in the View + * constructor, use {@link #createView(Context, String, String, AttributeSet)} instead. + * + * <p> + * There are two things that can happen in an error case: either the + * exception describing the error will be thrown, or a null will be + * returned. You must deal with both possibilities -- the former will happen + * the first time createView() is called for a class of a particular name, + * the latter every time there-after for that class name. + * + * @param name The full name of the class to be instantiated. + * @param attrs The XML attributes supplied for this instance. + * + * @return View The newly instantiated view, or null. + */ + public final View createView(String name, String prefix, AttributeSet attrs) + throws ClassNotFoundException, InflateException { + Context context = (Context) mConstructorArgs[0]; + if (context == null) { + context = mContext; + } + return createView(context, name, prefix, attrs); + } /** * Low-level function for instantiating a view by name. This attempts to @@ -734,13 +788,18 @@ public abstract class LayoutInflater { * the first time createView() is called for a class of a particular name, * the latter every time there-after for that class name. * + * @param viewContext The context used as the context parameter of the View constructor * @param name The full name of the class to be instantiated. * @param attrs The XML attributes supplied for this instance. * * @return View The newly instantiated view, or null. */ - public final View createView(String name, String prefix, AttributeSet attrs) + @Nullable + public final View createView(@NonNull Context viewContext, @NonNull String name, + @Nullable String prefix, @Nullable AttributeSet attrs) throws ClassNotFoundException, InflateException { + Objects.requireNonNull(viewContext); + Objects.requireNonNull(name); Constructor<? extends View> constructor = sConstructorMap.get(name); if (constructor != null && !verifyClassLoader(constructor)) { constructor = null; @@ -787,22 +846,21 @@ public abstract class LayoutInflater { } Object lastContext = mConstructorArgs[0]; - if (mConstructorArgs[0] == null) { - // Fill in the context if not already within inflation. - mConstructorArgs[0] = mContext; - } + mConstructorArgs[0] = viewContext; Object[] args = mConstructorArgs; args[1] = attrs; - final View view = constructor.newInstance(args); - if (view instanceof ViewStub) { - // Use the same context when inflating ViewStub later. - final ViewStub viewStub = (ViewStub) view; - viewStub.setLayoutInflater(cloneInContext((Context) args[0])); + try { + final View view = constructor.newInstance(args); + if (view instanceof ViewStub) { + // Use the same context when inflating ViewStub later. + final ViewStub viewStub = (ViewStub) view; + viewStub.setLayoutInflater(cloneInContext((Context) args[0])); + } + return view; + } finally { + mConstructorArgs[0] = lastContext; } - mConstructorArgs[0] = lastContext; - return view; - } catch (NoSuchMethodException e) { final InflateException ie = new InflateException(attrs.getPositionDescription() + ": Error inflating class " + (prefix != null ? (prefix + name) : name), e); @@ -871,6 +929,26 @@ public abstract class LayoutInflater { } /** + * Version of {@link #onCreateView(View, String, AttributeSet)} that also + * takes the inflation context. The default + * implementation simply calls {@link #onCreateView(View, String, AttributeSet)}. + * + * @param viewContext The Context to be used as a constructor parameter for the View + * @param parent The future parent of the returned view. <em>Note that + * this may be null.</em> + * @param name The fully qualified class name of the View to be create. + * @param attrs An AttributeSet of attributes to apply to the View. + * + * @return View The View created. + */ + @Nullable + public View onCreateView(@NonNull Context viewContext, @Nullable View parent, + @NonNull String name, @Nullable AttributeSet attrs) + throws ClassNotFoundException { + return onCreateView(parent, name, attrs); + } + + /** * Convenience method for calling through to the five-arg createViewFromTag * method. This method passes {@code false} for the {@code ignoreThemeAttr} * argument and should be used for everything except {@code >include>} @@ -921,9 +999,9 @@ public abstract class LayoutInflater { mConstructorArgs[0] = context; try { if (-1 == name.indexOf('.')) { - view = onCreateView(parent, name, attrs); + view = onCreateView(context, parent, name, attrs); } else { - view = createView(name, null, attrs); + view = createView(context, name, null, attrs); } } finally { mConstructorArgs[0] = lastContext; diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index b6a4a095066f..b6c4cbbbe54d 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -24,6 +24,7 @@ import android.annotation.IntDef; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.graphics.Matrix; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -1513,7 +1514,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { } // Pointer to the native MotionEvent object that contains the actual data. - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private long mNativePtr; private MotionEvent mNext; diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java index dc11d3ddd1d6..c24b8b2a5ee3 100644 --- a/core/java/android/view/ScaleGestureDetector.java +++ b/core/java/android/view/ScaleGestureDetector.java @@ -18,7 +18,6 @@ package android.view; import android.annotation.UnsupportedAppUsage; import android.content.Context; -import android.content.res.Resources; import android.os.Build; import android.os.Handler; @@ -145,7 +144,7 @@ public class ScaleGestureDetector { private boolean mInProgress; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768938) private int mSpanSlop; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768938) private int mMinSpan; private final Handler mHandler; @@ -200,10 +199,9 @@ public class ScaleGestureDetector { Handler handler) { mContext = context; mListener = listener; - mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2; - - final Resources res = context.getResources(); - mMinSpan = res.getDimensionPixelSize(com.android.internal.R.dimen.config_minScalingSpan); + final ViewConfiguration viewConfiguration = ViewConfiguration.get(context); + mSpanSlop = viewConfiguration.getScaledTouchSlop() * 2; + mMinSpan = viewConfiguration.getScaledMinScalingSpan(); mHandler = handler; // Quick scale is enabled by default after JB_MR2 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 8028715219cc..1212df0c397a 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -62,6 +62,7 @@ import libcore.util.NativeAllocationRegistry; import java.io.Closeable; import java.nio.ByteBuffer; +import java.nio.ByteOrder; /** * Handle to an on-screen Surface managed by the system compositor. The SurfaceControl is @@ -711,8 +712,10 @@ public final class SurfaceControl implements Parcelable { for (int i = 0; i < metadata.size(); ++i) { metaParcel.writeInt(metadata.keyAt(i)); metaParcel.writeByteArray( - ByteBuffer.allocate(4).putInt(metadata.valueAt(i)).array()); + ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()) + .putInt(metadata.valueAt(i)).array()); } + metaParcel.setDataPosition(0); } mNativeObject = nativeCreate(session, name, w, h, format, flags, parent != null ? parent.mNativeObject : 0, metaParcel); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 3f2795ba1e00..83df33e9742e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4030,8 +4030,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * {@hide} + * + * Not available for general use. If you need help, hang up and then dial one of the following + * public APIs: + * + * @see #isAttachedToWindow() for current attach state + * @see #onAttachedToWindow() for subclasses performing work when becoming attached + * @see #onDetachedFromWindow() for subclasses performing work when becoming detached + * @see OnAttachStateChangeListener for other code performing work on attach/detach + * @see #getHandler() for posting messages to this view's UI thread/looper + * @see #getParent() for interacting with the parent chain + * @see #getWindowToken() for the current window token + * @see #getRootView() for the view at the root of the attached hierarchy + * @see #getDisplay() for the Display this view is presented on + * @see #getRootWindowInsets() for the current insets applied to the whole attached window + * @see #hasWindowFocus() for whether the attached window is currently focused + * @see #getWindowVisibility() for checking the visibility of the attached window */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) AttachInfo mAttachInfo; /** @@ -28193,18 +28209,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, View mViewRequestingLayout; /** - * Used to track views that need (at least) a partial relayout at their current size - * during the next traversal. - */ - List<View> mPartialLayoutViews = new ArrayList<>(); - - /** - * Swapped with mPartialLayoutViews during layout to avoid concurrent - * modification. Lazily assigned during ViewRootImpl layout. - */ - List<View> mEmptyPartialLayoutViews; - - /** * Used to track the identity of the current drag operation. */ IBinder mDragToken; diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 6beae37d6b46..bb29ed6c5339 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -293,12 +293,14 @@ public class ViewConfiguration { */ private static final float AMBIGUOUS_GESTURE_MULTIPLIER = 2f; + private final boolean mConstructedWithContext; private final int mEdgeSlop; private final int mFadingEdgeLength; private final int mMinimumFlingVelocity; private final int mMaximumFlingVelocity; private final int mScrollbarSize; private final int mTouchSlop; + private final int mMinScalingSpan; private final int mHoverSlop; private final int mMinScrollbarTouchTarget; private final int mDoubleTapTouchSlop; @@ -329,6 +331,7 @@ public class ViewConfiguration { */ @Deprecated public ViewConfiguration() { + mConstructedWithContext = false; mEdgeSlop = EDGE_SLOP; mFadingEdgeLength = FADING_EDGE_LENGTH; mMinimumFlingVelocity = MINIMUM_FLING_VELOCITY; @@ -350,6 +353,10 @@ public class ViewConfiguration { mHorizontalScrollFactor = HORIZONTAL_SCROLL_FACTOR; mVerticalScrollFactor = VERTICAL_SCROLL_FACTOR; mShowMenuShortcutsWhenKeyboardPresent = false; + + // Getter throws if mConstructedWithContext is false so doesn't matter what + // this value is. + mMinScalingSpan = 0; } /** @@ -363,6 +370,7 @@ public class ViewConfiguration { * @see android.util.DisplayMetrics */ private ViewConfiguration(Context context) { + mConstructedWithContext = true; final Resources res = context.getResources(); final DisplayMetrics metrics = res.getDisplayMetrics(); final Configuration config = res.getConfiguration(); @@ -447,6 +455,8 @@ public class ViewConfiguration { mShowMenuShortcutsWhenKeyboardPresent = res.getBoolean( com.android.internal.R.bool.config_showMenuShortcutsWhenKeyboardPresent); + mMinScalingSpan = res.getDimensionPixelSize( + com.android.internal.R.dimen.config_minScalingSpan); } /** @@ -959,6 +969,26 @@ public class ViewConfiguration { } /** + * Retrieves the distance in pixels between touches that must be reached for a gesture to be + * interpreted as scaling. + * + * In general, scaling shouldn't start until this distance has been met or surpassed, and + * scaling should end when the distance in pixels between touches drops below this distance. + * + * @return The distance in pixels + * @throws IllegalStateException if this method is called on a ViewConfiguration that was + * instantiated using a constructor with no Context parameter. + */ + public int getScaledMinScalingSpan() { + if (!mConstructedWithContext) { + throw new IllegalStateException("Min scaling span cannot be determined when this " + + "method is called on a ViewConfiguration that was instantiated using a " + + "constructor with no Context parameter"); + } + return mMinScalingSpan; + } + + /** * @hide * @return Whether or not marquee should use fading edges. */ diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index d2b40f75a6a8..aaf1d110c8c2 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -703,7 +703,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager private void initFromAttributes( Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, defStyleAttr, + final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, + defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.ViewGroup, attrs, a, defStyleAttr, defStyleRes); final int N = a.getIndexCount(); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 156972f6ecbb..1a782ee5d3dd 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1887,7 +1887,7 @@ public final class ViewRootImpl implements ViewParent, mLastWindowInsets = mInsetsController.calculateInsets( mContext.getResources().getConfiguration().isScreenRound(), mAttachInfo.mAlwaysConsumeNavBar, displayCutout, - contentInsets, stableInsets); + contentInsets, stableInsets, mWindowAttributes.softInputMode); } else { mLastWindowInsets = new WindowInsets(contentInsets, stableInsets, mContext.getResources().getConfiguration().isScreenRound(), diff --git a/core/java/android/view/ViewStub.java b/core/java/android/view/ViewStub.java index e9d1b8784914..9ca16327844c 100644 --- a/core/java/android/view/ViewStub.java +++ b/core/java/android/view/ViewStub.java @@ -108,6 +108,9 @@ public final class ViewStub extends View { final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewStub, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.ViewStub, attrs, a, defStyleAttr, + defStyleRes); + mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID); mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0); mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID); diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 46aea80efe7a..e3833c01eeaf 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -520,7 +520,7 @@ public final class WindowManagerGlobal { return false; } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public void trimMemory(int level) { if (ThreadedRenderer.isAvailable()) { if (shouldDestroyEglContext(level)) { diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS new file mode 100644 index 000000000000..265674a74b7e --- /dev/null +++ b/core/java/android/view/accessibility/OWNERS @@ -0,0 +1,3 @@ +svetoslavganov@google.com +pweaver@google.com +rhedjao@google.com diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java index dfd9a2e95cb7..e0950948afb8 100644 --- a/core/java/android/view/animation/Animation.java +++ b/core/java/android/view/animation/Animation.java @@ -23,6 +23,7 @@ import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.RectF; +import android.os.Build; import android.os.Handler; import android.os.SystemProperties; import android.util.AttributeSet; @@ -30,9 +31,6 @@ import android.util.TypedValue; import dalvik.system.CloseGuard; -import java.util.ArrayList; -import java.util.List; - /** * Abstraction for an Animation that can be applied to Views, Surfaces, or * other objects. See the {@link android.view.animation animation package @@ -187,15 +185,12 @@ public abstract class Animation implements Cloneable { /** * An animation listener to be notified when the animation starts, ends or repeats. */ - @UnsupportedAppUsage + // If you need to chain the AnimationListener, wrap the existing Animation into an AnimationSet + // and add your new listener to that set + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 117519981) private AnimationListener mListener; /** - * A list of animation listeners to be notified when the animation starts, ends or repeats. - */ - private List<AnimationListener> mListeners; - - /** * Desired Z order mode during animation. */ private int mZAdjustment; @@ -833,7 +828,7 @@ public abstract class Animation implements Cloneable { } private boolean hasAnimationListener() { - return mListener != null || (mListeners != null && !mListeners.isEmpty()); + return mListener != null; } /** @@ -848,32 +843,6 @@ public abstract class Animation implements Cloneable { } /** - * <p>Adds an animation listener to this animation. The animation listener - * is notified of animation events such as the end of the animation or the - * repetition of the animation.</p> - * - * @param listener the animation listener to be notified - */ - public void addAnimationListener(AnimationListener listener) { - if (mListeners == null) { - mListeners = new ArrayList<>(1); - } - mListeners.add(listener); - } - - /** - * <p>Removes an animation listener that has been added with - * {@link #addAnimationListener(AnimationListener)}.</p> - * - * @param listener the animation listener to be removed - */ - public void removeAnimationListener(AnimationListener listener) { - if (mListeners != null) { - mListeners.remove(listener); - } - } - - /** * Gurantees that this animation has an interpolator. Will use * a AccelerateDecelerateInterpolator is nothing else was specified. */ @@ -1003,33 +972,18 @@ public abstract class Animation implements Cloneable { if (mListener != null) { mListener.onAnimationStart(this); } - if (mListeners != null && !mListeners.isEmpty()) { - for (AnimationListener listener : mListeners) { - listener.onAnimationStart(this); - } - } } void dispatchAnimationRepeat() { if (mListener != null) { mListener.onAnimationRepeat(this); } - if (mListeners != null && !mListeners.isEmpty()) { - for (AnimationListener listener : mListeners) { - listener.onAnimationRepeat(this); - } - } } void dispatchAnimationEnd() { if (mListener != null) { mListener.onAnimationEnd(this); } - if (mListeners != null && !mListeners.isEmpty()) { - for (AnimationListener listener : mListeners) { - listener.onAnimationEnd(this); - } - } } /** diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 83fc017373a6..5e5c8265f782 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -17,7 +17,6 @@ package android.view.autofill; import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST; -import static android.util.DebugUtils.flagsToString; import static android.view.autofill.Helper.sDebug; import static android.view.autofill.Helper.sVerbose; @@ -338,6 +337,14 @@ public final class AutofillManager { public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes /** + * Disables Augmented Autofill. + * + * @hide + */ + @TestApi + public static final int FLAG_SMART_SUGGESTION_OFF = 0x0; + + /** * Displays the Augment Autofill window using the same mechanism (such as a popup-window * attached to the focused view) as the standard autofill. * @@ -347,13 +354,21 @@ public final class AutofillManager { public static final int FLAG_SMART_SUGGESTION_SYSTEM = 0x1; /** @hide */ - @IntDef(flag = true, prefix = { "FLAG_SMART_SUGGESTION_" }, value = { - FLAG_SMART_SUGGESTION_SYSTEM - }) + @IntDef(flag = false, value = { FLAG_SMART_SUGGESTION_OFF, FLAG_SMART_SUGGESTION_SYSTEM }) @Retention(RetentionPolicy.SOURCE) public @interface SmartSuggestionMode {} /** + * {@code DeviceConfig} property used to set which Smart Suggestion modes for Augmented Autofill + * are available. + * + * @hide + */ + @TestApi + public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = + "smart_suggestion_supported_modes"; + + /** * Makes an authentication id from a request id and a dataset id. * * @param requestId The request id. @@ -2347,7 +2362,14 @@ public final class AutofillManager { /** @hide */ public static String getSmartSuggestionModeToString(@SmartSuggestionMode int flags) { - return flagsToString(AutofillManager.class, "FLAG_SMART_SUGGESTION_", flags); + switch (flags) { + case FLAG_SMART_SUGGESTION_OFF: + return "OFF"; + case FLAG_SMART_SUGGESTION_SYSTEM: + return "SYSTEM"; + default: + return "INVALID:" + flags; + } } @GuardedBy("mLock") diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 2512b95fe0ec..634443d78b49 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -66,6 +66,25 @@ public final class ContentCaptureManager { */ private static final int SYNC_CALLS_TIMEOUT_MS = 5000; + /** + * DeviceConfig property used by {@code com.android.server.SystemServer} on start to decide + * whether the Content Capture service should be created or not + * + * <p>By default it should *NOT* be set (or set to {@code "default"}, so the decision is based + * on whether the OEM provides an implementation for the service), but it can be overridden to: + * + * <ul> + * <li>Provide a "kill switch" so OEMs can disable it remotely in case of emergency (when + * it's set to {@code "false"}). + * <li>Enable the CTS tests to be run on AOSP builds (when it's set to {@code "true"}). + * </ul> + * + * @hide + */ + @TestApi + public static final String DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED = + "service_explicitly_enabled"; + private final Object mLock = new Object(); @NonNull diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index eb945b55bd7e..810c967ce2c8 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -303,6 +303,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { Log.v(TAG, "Buffering VIEW_TEXT_CHANGED event, updated text=" + getSanitizedString(event.getText())); } + // TODO(b/124107816): should call lastEvent.merge(event) instead lastEvent.setText(event.getText()); addEvent = false; } @@ -316,7 +317,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { Log.v(TAG, "Buffering TYPE_VIEW_DISAPPEARED events for session " + lastEvent.getSessionId()); } - lastEvent.addAutofillId(event.getId()); + mergeViewsDisappearedEvent(lastEvent, event); addEvent = false; } } @@ -364,6 +365,30 @@ public final class MainContentCaptureSession extends ContentCaptureSession { flush(flushReason); } + // TODO(b/124107816): should be ContentCaptureEvent Event.merge(event) instead (which would + // replace the addAutofillId() method - we would also need unit tests on ContentCaptureEventTest + // to check these scenarios) + private void mergeViewsDisappearedEvent(@NonNull ContentCaptureEvent lastEvent, + @NonNull ContentCaptureEvent event) { + final List<AutofillId> ids = event.getIds(); + final AutofillId id = event.getId(); + if (ids != null) { + if (id != null) { + Log.w(TAG, "got TYPE_VIEW_DISAPPEARED event with both id and ids: " + event); + } + for (int i = 0; i < ids.size(); i++) { + lastEvent.addAutofillId(ids.get(i)); + } + return; + } + if (id != null) { + lastEvent.addAutofillId(id); + return; + } + throw new IllegalArgumentException( + "got TYPE_VIEW_DISAPPEARED event with neither id or ids: " + event); + } + @UiThread private boolean hasStarted() { return mState != UNKNOWN_STATE; diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 8a097883dd5c..e63a406411d8 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1373,7 +1373,7 @@ public final class InputMethodManager { * @hide */ @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499) public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) { try { Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be removed " diff --git a/core/java/android/view/textclassifier/ConversationAction.java b/core/java/android/view/textclassifier/ConversationAction.java index 1a6e5d8e8b03..ae6a645c90a1 100644 --- a/core/java/android/view/textclassifier/ConversationAction.java +++ b/core/java/android/view/textclassifier/ConversationAction.java @@ -92,6 +92,9 @@ public final class ConversationAction implements Parcelable { */ public static final String TYPE_SHARE_LOCATION = "share_location"; + /** @hide **/ + public static final String TYPE_ADD_CONTACT = "add_contact"; + public static final Creator<ConversationAction> CREATOR = new Creator<ConversationAction>() { @Override diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java index 602455c65beb..b0e7ad5d7264 100644 --- a/core/java/android/view/textclassifier/ExtrasUtils.java +++ b/core/java/android/view/textclassifier/ExtrasUtils.java @@ -85,15 +85,16 @@ public final class ExtrasUtils { } /** - * Returns the first "translate" action found in the {@code classification} object. + * Returns the first action found in the {@code classification} object with an intent + * action string, {@code intentAction}. */ @Nullable - public static RemoteAction findTranslateAction(TextClassification classification) { + public static RemoteAction findAction(TextClassification classification, String intentAction) { final ArrayList<Intent> actionIntents = getActionsIntents(classification); if (actionIntents != null) { final int size = actionIntents.size(); for (int i = 0; i < size; i++) { - if (Intent.ACTION_TRANSLATE.equals(actionIntents.get(i).getAction())) { + if (intentAction.equals(actionIntents.get(i).getAction())) { return classification.getActions().get(i); } } @@ -102,6 +103,14 @@ public final class ExtrasUtils { } /** + * Returns the first "translate" action found in the {@code classification} object. + */ + @Nullable + public static RemoteAction findTranslateAction(TextClassification classification) { + return findAction(classification, Intent.ACTION_TRANSLATE); + } + + /** * Returns the entity type contained in the {@code extra}. */ @Nullable diff --git a/core/java/android/view/textclassifier/LegacyIntentFactory.java b/core/java/android/view/textclassifier/LegacyIntentFactory.java index b6e5b3e26b16..2d0d032cfef3 100644 --- a/core/java/android/view/textclassifier/LegacyIntentFactory.java +++ b/core/java/android/view/textclassifier/LegacyIntentFactory.java @@ -182,7 +182,8 @@ public final class LegacyIntentFactory implements IntentFactory { actions.add(new LabeledIntent( context.getString(com.android.internal.R.string.browse), context.getString(com.android.internal.R.string.browse_desc), - new Intent(Intent.ACTION_VIEW, Uri.parse(text)) + new Intent(Intent.ACTION_VIEW) + .setDataAndNormalize(Uri.parse(text)) .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()), LabeledIntent.DEFAULT_REQUEST_CODE)); return actions; diff --git a/core/java/android/view/textclassifier/TEST_MAPPING b/core/java/android/view/textclassifier/TEST_MAPPING new file mode 100644 index 000000000000..01a6edecf21e --- /dev/null +++ b/core/java/android/view/textclassifier/TEST_MAPPING @@ -0,0 +1,15 @@ +{ + "presubmit": [ + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "android.view.textclassifier" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + } + ] +} diff --git a/core/java/android/view/textclassifier/TemplateIntentFactory.java b/core/java/android/view/textclassifier/TemplateIntentFactory.java index 52788436b3ea..95f88c7de146 100644 --- a/core/java/android/view/textclassifier/TemplateIntentFactory.java +++ b/core/java/android/view/textclassifier/TemplateIntentFactory.java @@ -49,20 +49,18 @@ public final class TemplateIntentFactory { } final List<TextClassifierImpl.LabeledIntent> labeledIntents = new ArrayList<>(); for (RemoteActionTemplate remoteActionTemplate : remoteActionTemplates) { - Intent intent = createIntent(remoteActionTemplate); - if (intent == null) { + if (!isValidTemplate(remoteActionTemplate)) { + Log.w(TAG, "Invalid RemoteActionTemplate skipped."); continue; } - TextClassifierImpl.LabeledIntent - labeledIntent = new TextClassifierImpl.LabeledIntent( - remoteActionTemplate.title, - remoteActionTemplate.description, - intent, - remoteActionTemplate.requestCode == null - ? TextClassifierImpl.LabeledIntent.DEFAULT_REQUEST_CODE - : remoteActionTemplate.requestCode - ); - labeledIntents.add(labeledIntent); + labeledIntents.add( + new TextClassifierImpl.LabeledIntent( + remoteActionTemplate.title, + remoteActionTemplate.description, + createIntent(remoteActionTemplate), + remoteActionTemplate.requestCode == null + ? TextClassifierImpl.LabeledIntent.DEFAULT_REQUEST_CODE + : remoteActionTemplate.requestCode)); } labeledIntents.forEach( action -> action.getIntent() @@ -70,29 +68,43 @@ public final class TemplateIntentFactory { return labeledIntents; } - @Nullable - private static Intent createIntent(RemoteActionTemplate remoteActionTemplate) { - Intent intent = new Intent(); - if (!TextUtils.isEmpty(remoteActionTemplate.packageName)) { - Log.w(TAG, "A RemoteActionTemplate is skipped as package name is set."); - return null; + private static boolean isValidTemplate(@Nullable RemoteActionTemplate remoteActionTemplate) { + if (remoteActionTemplate == null) { + Log.w(TAG, "Invalid RemoteActionTemplate: is null"); + return false; } - if (!TextUtils.isEmpty(remoteActionTemplate.action)) { - intent.setAction(remoteActionTemplate.action); + if (TextUtils.isEmpty(remoteActionTemplate.title)) { + Log.w(TAG, "Invalid RemoteActionTemplate: title is null"); + return false; } - Uri data = null; - if (!TextUtils.isEmpty(remoteActionTemplate.data)) { - data = Uri.parse(remoteActionTemplate.data); + if (TextUtils.isEmpty(remoteActionTemplate.description)) { + Log.w(TAG, "Invalid RemoteActionTemplate: description is null"); + return false; } - if (data != null || !TextUtils.isEmpty(remoteActionTemplate.type)) { - intent.setDataAndType(data, remoteActionTemplate.type); + if (!TextUtils.isEmpty(remoteActionTemplate.packageName)) { + Log.w(TAG, "Invalid RemoteActionTemplate: package name is set"); + return false; } - if (remoteActionTemplate.flags != null) { - intent.setFlags(remoteActionTemplate.flags); + if (TextUtils.isEmpty(remoteActionTemplate.action)) { + Log.w(TAG, "Invalid RemoteActionTemplate: intent action not set"); + return false; } + return true; + } + + private static Intent createIntent(RemoteActionTemplate remoteActionTemplate) { + final Intent intent = new Intent(remoteActionTemplate.action); + final Uri uri = TextUtils.isEmpty(remoteActionTemplate.data) + ? null : Uri.parse(remoteActionTemplate.data).normalizeScheme(); + final String type = TextUtils.isEmpty(remoteActionTemplate.type) + ? null : Intent.normalizeMimeType(remoteActionTemplate.type); + intent.setDataAndType(uri, type); + intent.setFlags(remoteActionTemplate.flags == null ? 0 : remoteActionTemplate.flags); if (remoteActionTemplate.category != null) { for (String category : remoteActionTemplate.category) { - intent.addCategory(category); + if (category != null) { + intent.addCategory(category); + } } } intent.putExtras(createExtras(remoteActionTemplate.extras)); @@ -105,6 +117,9 @@ public final class TemplateIntentFactory { } Bundle bundle = new Bundle(); for (NamedVariant namedVariant : namedVariants) { + if (namedVariant == null) { + continue; + } switch (namedVariant.getType()) { case NamedVariant.TYPE_INT: bundle.putInt(namedVariant.getName(), namedVariant.getInt()); diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java index ee9e04e5329a..2ef8d04939bd 100644 --- a/core/java/android/view/textclassifier/TextClassificationConstants.java +++ b/core/java/android/view/textclassifier/TextClassificationConstants.java @@ -131,6 +131,7 @@ public final class TextClassificationConstants { .add(ConversationAction.TYPE_TRACK_FLIGHT) .add(ConversationAction.TYPE_VIEW_CALENDAR) .add(ConversationAction.TYPE_VIEW_MAP) + .add(ConversationAction.TYPE_ADD_CONTACT) .toString(); /** * < 0 : Not set. Use value from LangId model. diff --git a/core/java/android/webkit/OWNERS b/core/java/android/webkit/OWNERS index 00e540a46ab2..b33da57c42e3 100644 --- a/core/java/android/webkit/OWNERS +++ b/core/java/android/webkit/OWNERS @@ -1,3 +1,4 @@ changwan@google.com +ntfschr@google.com tobiasjs@google.com torne@google.com diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 60393502bbe7..2171fc52a0ba 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -61,6 +61,7 @@ import android.view.accessibility.AccessibilityNodeProvider; import android.view.autofill.AutofillValue; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; +import android.view.inspector.InspectableProperty; import android.view.textclassifier.TextClassifier; import android.widget.AbsoluteLayout; @@ -1239,6 +1240,7 @@ public class WebView extends AbsoluteLayout * * @return the URL for the current page */ + @InspectableProperty(hasAttributeId = false) @ViewDebug.ExportedProperty(category = "webview") public String getUrl() { checkThread(); @@ -1254,6 +1256,7 @@ public class WebView extends AbsoluteLayout * * @return the URL that was originally requested for the current page */ + @InspectableProperty(hasAttributeId = false) @ViewDebug.ExportedProperty(category = "webview") public String getOriginalUrl() { checkThread(); @@ -1266,6 +1269,7 @@ public class WebView extends AbsoluteLayout * * @return the title for the current page */ + @InspectableProperty(hasAttributeId = false) @ViewDebug.ExportedProperty(category = "webview") public String getTitle() { checkThread(); @@ -1278,6 +1282,7 @@ public class WebView extends AbsoluteLayout * * @return the favicon for the current page */ + @InspectableProperty(hasAttributeId = false) public Bitmap getFavicon() { checkThread(); return mProvider.getFavicon(); @@ -1300,6 +1305,7 @@ public class WebView extends AbsoluteLayout * * @return the progress for the current page between 0 and 100 */ + @InspectableProperty(hasAttributeId = false) public int getProgress() { checkThread(); return mProvider.getProgress(); @@ -1310,6 +1316,7 @@ public class WebView extends AbsoluteLayout * * @return the height of the HTML content */ + @InspectableProperty(hasAttributeId = false) @ViewDebug.ExportedProperty(category = "webview") public int getContentHeight() { checkThread(); @@ -2276,6 +2283,11 @@ public class WebView extends AbsoluteLayout * * @return the requested renderer priority policy. */ + @InspectableProperty(hasAttributeId = false, enumMapping = { + @InspectableProperty.EnumMap(name = "waived", value = RENDERER_PRIORITY_WAIVED), + @InspectableProperty.EnumMap(name = "bound", value = RENDERER_PRIORITY_BOUND), + @InspectableProperty.EnumMap(name = "important", value = RENDERER_PRIORITY_IMPORTANT) + }) @RendererPriority public int getRendererRequestedPriority() { return mProvider.getRendererRequestedPriority(); @@ -2288,6 +2300,7 @@ public class WebView extends AbsoluteLayout * @return whether this WebView requests a priority of * {@link #RENDERER_PRIORITY_WAIVED} when not visible. */ + @InspectableProperty(hasAttributeId = false) public boolean getRendererPriorityWaivedWhenNotVisible() { return mProvider.getRendererPriorityWaivedWhenNotVisible(); } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 1f8a9086ccb6..4b7c393b1b96 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -338,7 +338,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * The data set used to store unused views that should be reused during the next layout * to avoid creating new ones */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769398) final RecycleBin mRecycler = new RecycleBin(); /** @@ -421,7 +421,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * One of TOUCH_MODE_REST, TOUCH_MODE_DOWN, TOUCH_MODE_TAP, TOUCH_MODE_SCROLL, or * TOUCH_MODE_DONE_WAITING */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769413) int mTouchMode = TOUCH_MODE_REST; /** @@ -634,7 +634,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te /** * Helper object that renders and controls the fast scroll thumb. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768941) private FastScroller mFastScroll; /** @@ -657,7 +657,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te private Runnable mClearScrollingCache; Runnable mPositionScrollAfterLayout; private int mMinimumVelocity; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051740) private int mMaximumVelocity; private float mVelocityScale = 1.0f; @@ -700,7 +700,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te /** * Maximum distance to overfling during edge effects */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769379) int mOverflingDistance; // These two EdgeGlows are always set and used together. @@ -875,6 +875,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.AbsListView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.AbsListView, attrs, a, defStyleAttr, + defStyleRes); final Drawable selector = a.getDrawable(R.styleable.AbsListView_listSelector); if (selector != null) { @@ -4613,7 +4615,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * * @param newState The new scroll state. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769710) void reportScrollStateChange(int newState) { if (newState != mLastScrollState) { if (mOnScrollListener != null) { @@ -5156,7 +5158,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * @param incrementalDeltaY Change in deltaY from the previous event. * @return true if we're already at the beginning/end of the list and have nothing to do. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051739) boolean trackMotionScroll(int deltaY, int incrementalDeltaY) { final int childCount = getChildCount(); if (childCount == 0) { diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index c8be1d66ed4a..cd5f2e222b39 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -107,6 +107,8 @@ public abstract class AbsSeekBar extends ProgressBar { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.SeekBar, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.SeekBar, attrs, a, defStyleAttr, + defStyleRes); final Drawable thumb = a.getDrawable(R.styleable.SeekBar_thumb); setThumb(thumb); diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java index 816c9499e292..3dcba48b8dc8 100644 --- a/core/java/android/widget/AbsSpinner.java +++ b/core/java/android/widget/AbsSpinner.java @@ -82,6 +82,8 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.AbsSpinner, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.AbsSpinner, attrs, a, defStyleAttr, + defStyleRes); final CharSequence[] entries = a.getTextArray(R.styleable.AbsSpinner_entries); if (entries != null) { diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java index 58715eefc25e..89ea0747b532 100644 --- a/core/java/android/widget/ActivityChooserView.java +++ b/core/java/android/widget/ActivityChooserView.java @@ -232,6 +232,8 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod TypedArray attributesArray = context.obtainStyledAttributes(attrs, R.styleable.ActivityChooserView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.ActivityChooserView, attrs, + attributesArray, defStyleAttr, defStyleRes); mInitialActivityCount = attributesArray.getInt( R.styleable.ActivityChooserView_initialActivityCount, diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index ddff8581d568..c55f7d654548 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.database.DataSetObserver; +import android.os.Build; import android.os.Parcelable; import android.os.SystemClock; import android.util.AttributeSet; @@ -152,7 +153,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { /** * True if the data has changed since the last layout */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768524) boolean mDataChanged; /** diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java index 6f293684ad3c..5174c1a34fcd 100644 --- a/core/java/android/widget/AdapterViewAnimator.java +++ b/core/java/android/widget/AdapterViewAnimator.java @@ -180,6 +180,9 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> final TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AdapterViewAnimator, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.AdapterViewAnimator, + attrs, a, defStyleAttr, defStyleRes); + int resource = a.getResourceId( com.android.internal.R.styleable.AdapterViewAnimator_inAnimation, 0); if (resource > 0) { diff --git a/core/java/android/widget/AdapterViewFlipper.java b/core/java/android/widget/AdapterViewFlipper.java index 18d74705773a..065089f53633 100644 --- a/core/java/android/widget/AdapterViewFlipper.java +++ b/core/java/android/widget/AdapterViewFlipper.java @@ -69,6 +69,8 @@ public class AdapterViewFlipper extends AdapterViewAnimator { final TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AdapterViewFlipper, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.AdapterViewFlipper, + attrs, a, defStyleAttr, defStyleRes); mFlipInterval = a.getInt( com.android.internal.R.styleable.AdapterViewFlipper_flipInterval, DEFAULT_INTERVAL); mAutoStart = a.getBoolean( diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java index 795b03493efb..339947ac8d5a 100644 --- a/core/java/android/widget/AnalogClock.java +++ b/core/java/android/widget/AnalogClock.java @@ -81,6 +81,8 @@ public class AnalogClock extends View { final Resources r = context.getResources(); final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.AnalogClock, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.AnalogClock, + attrs, a, defStyleAttr, defStyleRes); mDial = a.getDrawable(com.android.internal.R.styleable.AnalogClock_dial); if (mDial == null) { diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index 9bc055e7111b..904a86261e6c 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -126,7 +126,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe private boolean mDropDownDismissedOnCompletion = true; private int mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN; - private boolean mOpenBefore; + private MyWatcher mAutoCompleteTextWatcher; private Validator mValidator = null; @@ -227,6 +227,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.AutoCompleteTextView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.AutoCompleteTextView, + attrs, a, defStyleAttr, defStyleRes); if (popupTheme != null) { mPopupContext = new ContextThemeWrapper(context, popupTheme); @@ -245,6 +247,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe if (mPopupContext != context) { pa = mPopupContext.obtainStyledAttributes( attrs, R.styleable.AutoCompleteTextView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.AutoCompleteTextView, + attrs, a, defStyleAttr, defStyleRes); } else { pa = a; } @@ -302,7 +306,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe setFocusable(true); - addTextChangedListener(new MyWatcher()); + mAutoCompleteTextWatcher = new MyWatcher(); + addTextChangedListener(mAutoCompleteTextWatcher); mPassThroughClickListener = new PassThroughClickListener(); super.setOnClickListener(mPassThroughClickListener); @@ -872,45 +877,66 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe return getText().length() >= mThreshold; } - /** - * This is used to watch for edits to the text view. Note that we call - * to methods on the auto complete text view class so that we can access - * private vars without going through thunks. - */ + + + /** This is used to watch for edits to the text view. */ private class MyWatcher implements TextWatcher { - public void afterTextChanged(Editable s) { - doAfterTextChanged(); - } + private boolean mOpenBefore; + public void beforeTextChanged(CharSequence s, int start, int count, int after) { - doBeforeTextChanged(); + if (mBlockCompletion) return; + + // when text is changed, inserted or deleted, we attempt to show + // the drop down + mOpenBefore = isPopupShowing(); + if (DEBUG) Log.v(TAG, "before text changed: open=" + mOpenBefore); + } + + public void afterTextChanged(Editable s) { + if (mBlockCompletion) return; + + // if the list was open before the keystroke, but closed afterwards, + // then something in the keystroke processing (an input filter perhaps) + // called performCompletion() and we shouldn't do any more processing. + if (DEBUG) { + Log.v(TAG, "after text changed: openBefore=" + mOpenBefore + + " open=" + isPopupShowing()); + } + + if (mOpenBefore && !isPopupShowing()) return; + + refreshAutoCompleteResults(); } + public void onTextChanged(CharSequence s, int start, int before, int count) { } } - @UnsupportedAppUsage + /** + * This function is deprecated. Please use {@link #refreshAutoCompleteResults} instead. + * Note: Remove {@link #mAutoCompleteTextWatcher} after removing this function. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) void doBeforeTextChanged() { - if (mBlockCompletion) return; - - // when text is changed, inserted or deleted, we attempt to show - // the drop down - mOpenBefore = isPopupShowing(); - if (DEBUG) Log.v(TAG, "before text changed: open=" + mOpenBefore); + mAutoCompleteTextWatcher.beforeTextChanged(null, 0, 0, 0); } - @UnsupportedAppUsage + /** + * This function is deprecated. Please use {@link #refreshAutoCompleteResults} instead. + * Note: Remove {@link #mAutoCompleteTextWatcher} after removing this function. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) void doAfterTextChanged() { - if (mBlockCompletion) return; - - // if the list was open before the keystroke, but closed afterwards, - // then something in the keystroke processing (an input filter perhaps) - // called performCompletion() and we shouldn't do any more processing. - if (DEBUG) Log.v(TAG, "after text changed: openBefore=" + mOpenBefore - + " open=" + isPopupShowing()); - if (mOpenBefore && !isPopupShowing()) { - return; - } + mAutoCompleteTextWatcher.afterTextChanged(null); + } + /** + * Refreshes the auto complete results. You usually shouldn't have to manually refresh the + * AutoCompleteResults as this is done automatically whenever the text changes. However if the + * results are not available and have to be fetched, you can call this function after fetching + * the results. + */ + public final void refreshAutoCompleteResults() { // the drop down is shown only when a minimum number of characters // was typed in the text view if (enoughToFilter()) { diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java index 6c74c8c24c44..b552aa6c85c4 100644 --- a/core/java/android/widget/CalendarView.java +++ b/core/java/android/widget/CalendarView.java @@ -112,6 +112,8 @@ public class CalendarView extends FrameLayout { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.CalendarView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.CalendarView, + attrs, a, defStyleAttr, defStyleRes); final int mode = a.getInt(R.styleable.CalendarView_calendarViewMode, MODE_HOLO); a.recycle(); diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java index b7fdcbe2b399..99440f862871 100644 --- a/core/java/android/widget/CheckedTextView.java +++ b/core/java/android/widget/CheckedTextView.java @@ -90,6 +90,8 @@ public class CheckedTextView extends TextView implements Checkable { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.CheckedTextView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.CheckedTextView, + attrs, a, defStyleAttr, defStyleRes); final Drawable d = a.getDrawable(R.styleable.CheckedTextView_checkMark); if (d != null) { diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java index 66c35d903366..0b67cad0112b 100644 --- a/core/java/android/widget/Chronometer.java +++ b/core/java/android/widget/Chronometer.java @@ -116,6 +116,8 @@ public class Chronometer extends TextView { final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.Chronometer, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.Chronometer, + attrs, a, defStyleAttr, defStyleRes); setFormat(a.getString(R.styleable.Chronometer_format)); setCountDown(a.getBoolean(R.styleable.Chronometer_countDown, false)); a.recycle(); diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java index a0f93da90847..3cfd373c2906 100644 --- a/core/java/android/widget/CompoundButton.java +++ b/core/java/android/widget/CompoundButton.java @@ -100,6 +100,8 @@ public abstract class CompoundButton extends Button implements Checkable { final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.CompoundButton, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.CompoundButton, + attrs, a, defStyleAttr, defStyleRes); final Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button); if (d != null) { diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index cca951ca9298..ada4f00256eb 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -161,6 +161,8 @@ public class DatePicker extends FrameLayout { final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.DatePicker, + attrs, a, defStyleAttr, defStyleRes); final boolean isDialogMode = a.getBoolean(R.styleable.DatePicker_dialogMode, false); final int requestedMode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER); final int firstDayOfWeek = a.getInt(R.styleable.DatePicker_firstDayOfWeek, 0); diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java index f712d5fa65ca..67fef13d23f2 100644 --- a/core/java/android/widget/DayPickerView.java +++ b/core/java/android/widget/DayPickerView.java @@ -82,6 +82,8 @@ class DayPickerView extends ViewGroup { final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CalendarView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.CalendarView, + attrs, a, defStyleAttr, defStyleRes); final int firstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek, LocaleData.get(Locale.getDefault()).firstDayOfWeek); diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java index 33d15394332e..2cc013ec4f78 100644 --- a/core/java/android/widget/ExpandableListView.java +++ b/core/java/android/widget/ExpandableListView.java @@ -242,6 +242,8 @@ public class ExpandableListView extends ListView { final TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ExpandableListView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ExpandableListView, + attrs, a, defStyleAttr, defStyleRes); mGroupIndicator = a.getDrawable( com.android.internal.R.styleable.ExpandableListView_groupIndicator); diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java index 5723b9467aa2..3570c79430a4 100644 --- a/core/java/android/widget/FrameLayout.java +++ b/core/java/android/widget/FrameLayout.java @@ -100,6 +100,8 @@ public class FrameLayout extends ViewGroup { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.FrameLayout, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.FrameLayout, + attrs, a, defStyleAttr, defStyleRes); if (a.getBoolean(R.styleable.FrameLayout_measureAllChildren, false)) { setMeasureAllChildren(true); diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java index d6a0ae48cc13..64192aaff1cf 100644 --- a/core/java/android/widget/Gallery.java +++ b/core/java/android/widget/Gallery.java @@ -213,6 +213,8 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.Gallery, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.Gallery, + attrs, a, defStyleAttr, defStyleRes); int index = a.getInt(com.android.internal.R.styleable.Gallery_gravity, -1); if (index >= 0) { diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index c8abf18f88f9..1c8bb0470e2e 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -303,6 +303,8 @@ public class GridLayout extends ViewGroup { mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap); final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.GridLayout, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.GridLayout, + attrs, a, defStyleAttr, defStyleRes); try { setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT)); setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT)); diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index bbbe369d5262..a6129b04d14f 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -150,6 +150,8 @@ public class GridView extends AbsListView { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.GridView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.GridView, + attrs, a, defStyleAttr, defStyleRes); int hSpacing = a.getDimensionPixelOffset( R.styleable.GridView_horizontalSpacing, 0); diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index 1c5f837728a0..25cfdc7e4411 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -16,6 +16,7 @@ package android.widget; +import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.content.Context; @@ -80,10 +81,24 @@ public class HorizontalScrollView extends FrameLayout { private final Rect mTempRect = new Rect(); @UnsupportedAppUsage private OverScroller mScroller; - @UnsupportedAppUsage - private EdgeEffect mEdgeGlowLeft; - @UnsupportedAppUsage - private EdgeEffect mEdgeGlowRight; + /** + * Tracks the state of the left edge glow. + * + * Even though this field is practically final, we cannot make it final because there are apps + * setting it via reflection and they need to keep working until they target Q. + */ + @NonNull + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124053130) + private EdgeEffect mEdgeGlowLeft = new EdgeEffect(getContext()); + + /** + * Tracks the state of the bottom edge glow. + * + * Even though this field is practically final, we cannot make it final because there are apps + * setting it via reflection and they need to keep working until they target Q. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124052619) + private EdgeEffect mEdgeGlowRight = new EdgeEffect(getContext()); /** * Position of the last motion event. @@ -175,6 +190,8 @@ public class HorizontalScrollView extends FrameLayout { final TypedArray a = context.obtainStyledAttributes( attrs, android.R.styleable.HorizontalScrollView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, android.R.styleable.HorizontalScrollView, + attrs, a, defStyleAttr, defStyleRes); setFillViewport(a.getBoolean(android.R.styleable.HorizontalScrollView_fillViewport, false)); @@ -216,6 +233,74 @@ public class HorizontalScrollView extends FrameLayout { } /** + * Sets the edge effect color for both left and right edge effects. + * + * @param color The color for the edge effects. + * @see #setLeftEdgeEffectColor(int) + * @see #setRightEdgeEffectColor(int) + * @see #getLeftEdgeEffectColor() + * @see #getRightEdgeEffectColor() + */ + public void setEdgeEffectColor(@ColorInt int color) { + setLeftEdgeEffectColor(color); + setRightEdgeEffectColor(color); + } + + /** + * Sets the right edge effect color. + * + * @param color The color for the right edge effect. + * @see #setLeftEdgeEffectColor(int) + * @see #setEdgeEffectColor(int) + * @see #getLeftEdgeEffectColor() + * @see #getRightEdgeEffectColor() + */ + public void setRightEdgeEffectColor(@ColorInt int color) { + mEdgeGlowRight.setColor(color); + } + + /** + * Sets the left edge effect color. + * + * @param color The color for the left edge effect. + * @see #setRightEdgeEffectColor(int) + * @see #setEdgeEffectColor(int) + * @see #getLeftEdgeEffectColor() + * @see #getRightEdgeEffectColor() + */ + public void setLeftEdgeEffectColor(@ColorInt int color) { + mEdgeGlowLeft.setColor(color); + } + + /** + * Returns the left edge effect color. + * + * @return The left edge effect color. + * @see #setEdgeEffectColor(int) + * @see #setLeftEdgeEffectColor(int) + * @see #setRightEdgeEffectColor(int) + * @see #getRightEdgeEffectColor() + */ + @ColorInt + public int getLeftEdgeEffectColor() { + return mEdgeGlowLeft.getColor(); + } + + /** + * Returns the right edge effect color. + * + * @return The right edge effect color. + * @see #setEdgeEffectColor(int) + * @see #setLeftEdgeEffectColor(int) + * @see #setRightEdgeEffectColor(int) + * @see #getLeftEdgeEffectColor() + */ + @ColorInt + public int getRightEdgeEffectColor() { + return mEdgeGlowRight.getColor(); + } + + /** * @return The maximum amount this scroll view will scroll in response to * an arrow event. */ @@ -665,7 +750,7 @@ public class HorizontalScrollView extends FrameLayout { mEdgeGlowLeft.onRelease(); } } - if (mEdgeGlowLeft != null + if (shouldDisplayEdgeEffects() && (!mEdgeGlowLeft.isFinished() || !mEdgeGlowRight.isFinished())) { postInvalidateOnAnimation(); } @@ -693,7 +778,7 @@ public class HorizontalScrollView extends FrameLayout { mIsBeingDragged = false; recycleVelocityTracker(); - if (mEdgeGlowLeft != null) { + if (shouldDisplayEdgeEffects()) { mEdgeGlowLeft.onRelease(); mEdgeGlowRight.onRelease(); } @@ -708,7 +793,7 @@ public class HorizontalScrollView extends FrameLayout { mIsBeingDragged = false; recycleVelocityTracker(); - if (mEdgeGlowLeft != null) { + if (shouldDisplayEdgeEffects()) { mEdgeGlowLeft.onRelease(); mEdgeGlowRight.onRelease(); } @@ -1650,26 +1735,15 @@ public class HorizontalScrollView extends FrameLayout { } } - @Override - public void setOverScrollMode(int mode) { - if (mode != OVER_SCROLL_NEVER) { - if (mEdgeGlowLeft == null) { - Context context = getContext(); - mEdgeGlowLeft = new EdgeEffect(context); - mEdgeGlowRight = new EdgeEffect(context); - } - } else { - mEdgeGlowLeft = null; - mEdgeGlowRight = null; - } - super.setOverScrollMode(mode); + private boolean shouldDisplayEdgeEffects() { + return getOverScrollMode() != OVER_SCROLL_NEVER; } @SuppressWarnings({"SuspiciousNameCombination"}) @Override public void draw(Canvas canvas) { super.draw(canvas); - if (mEdgeGlowLeft != null) { + if (shouldDisplayEdgeEffects()) { final int scrollX = mScrollX; if (!mEdgeGlowLeft.isFinished()) { final int restoreCount = canvas.save(); diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index e9c31db8110b..9ae62ef8ab7a 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -138,7 +138,7 @@ public class ImageView extends View { private int mDrawableWidth; @UnsupportedAppUsage private int mDrawableHeight; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051687) private Matrix mDrawMatrix = null; // Avoid allocations... @@ -200,6 +200,8 @@ public class ImageView extends View { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.ImageView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.ImageView, + attrs, a, defStyleAttr, defStyleRes); final Drawable d = a.getDrawable(R.styleable.ImageView_src); if (d != null) { diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java index 64769b5337df..e833df9d498a 100644 --- a/core/java/android/widget/LinearLayout.java +++ b/core/java/android/widget/LinearLayout.java @@ -264,6 +264,8 @@ public class LinearLayout extends ViewGroup { final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.LinearLayout, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.LinearLayout, + attrs, a, defStyleAttr, defStyleRes); int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1); if (index >= 0) { diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index f9564b44e825..25e5dd32c6b2 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -471,11 +471,24 @@ public class ListPopupWindow implements ShowableListMenu { * Specifies the anchor-relative bounds of the popup's transition * epicenter. * - * @param bounds anchor-relative bounds - * @hide + * @param bounds anchor-relative bounds, or {@code null} to use default epicenter + * + * @see #getEpicenterBounds() + */ + public void setEpicenterBounds(@Nullable Rect bounds) { + mEpicenterBounds = bounds != null ? new Rect(bounds) : null; + } + + /** + * Returns bounds which are used as a popup's epicenter + * of the enter and exit transitions. + * + * @return bounds relative to anchor view, or {@code null} if not set + * @see #setEpicenterBounds(Rect) */ - public void setEpicenterBounds(Rect bounds) { - mEpicenterBounds = bounds; + @Nullable + public Rect getEpicenterBounds() { + return mEpicenterBounds != null ? new Rect(mEpicenterBounds) : null; } /** diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 311f8968150c..2aa019b5d0f4 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -236,6 +236,8 @@ public class ListView extends AbsListView { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.ListView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.ListView, + attrs, a, defStyleAttr, defStyleRes); final CharSequence[] entries = a.getTextArray(R.styleable.ListView_entries); if (entries != null) { diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index 157992a98a4a..dad2669d3de8 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -17,6 +17,8 @@ package android.widget; import android.annotation.CallSuper; +import android.annotation.ColorInt; +import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.Px; @@ -340,7 +342,7 @@ public class NumberPicker extends LinearLayout { /** * The {@link Paint} for drawing the selector. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private final Paint mSelectorWheelPaint; /** @@ -639,6 +641,8 @@ public class NumberPicker extends LinearLayout { // process style attributes final TypedArray attributesArray = context.obtainStyledAttributes( attrs, R.styleable.NumberPicker, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.NumberPicker, + attrs, attributesArray, defStyleAttr, defStyleRes); final int layoutResId = attributesArray.getResourceId( R.styleable.NumberPicker_internalLayout, DEFAULT_LAYOUT_RESOURCE_ID); @@ -1716,6 +1720,44 @@ public class NumberPicker extends LinearLayout { } /** + * Sets the text color for all the states (normal, selected, focused) to be the given color. + * + * @param color A color value in the form 0xAARRGGBB. + */ + public void setTextColor(@ColorInt int color) { + mSelectorWheelPaint.setColor(color); + mInputText.setTextColor(color); + invalidate(); + } + + /** + * @return the text color. + */ + @ColorInt + public int getTextColor() { + return mSelectorWheelPaint.getColor(); + } + + /** + * Sets the text size to the given value. This value must be > 0 + * + * @param size The size in pixel units. + */ + public void setTextSize(@FloatRange(from = 0.0, fromInclusive = false) float size) { + mSelectorWheelPaint.setTextSize(size); + mInputText.setTextSize(TypedValue.COMPLEX_UNIT_PX, size); + invalidate(); + } + + /** + * @return the size (in pixels) of the text size in this NumberPicker. + */ + @FloatRange(from = 0.0, fromInclusive = false) + public float getTextSize() { + return mSelectorWheelPaint.getTextSize(); + } + + /** * Makes a measure spec that tries greedily to use the max value. * * @param measureSpec The measure spec. diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 705a371e483e..279829672c57 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -264,7 +264,7 @@ public class PopupWindow { private WeakReference<View> mAnchorRoot; private boolean mIsAnchorRootAttached; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private final OnScrollChangedListener mOnScrollChangedListener = this::alignToAnchor; private final View.OnLayoutChangeListener mOnLayoutChangeListener = @@ -476,23 +476,40 @@ public class PopupWindow { } /** - * Sets the bounds used as the epicenter of the enter and exit transitions. - * <p> - * Transitions use a point or Rect, referred to as the epicenter, to orient + * <p>Returns bounds which are used as a center of the enter and exit transitions.<p/> + * + * <p>Transitions use Rect, referred to as the epicenter, to orient * the direction of travel. For popup windows, the anchor view bounds are - * used as the default epicenter. - * <p> - * See {@link Transition#setEpicenterCallback(EpicenterCallback)} for more - * information about how transition epicenters. + * used as the default epicenter.</p> + * + * <p>See {@link Transition#setEpicenterCallback(EpicenterCallback)} for more + * information about how transition epicenters work.</p> + * + * @return bounds relative to anchor view, or {@code null} if not set + * @see #setEpicenterBounds(Rect) + */ + @Nullable + public Rect getEpicenterBounds() { + return mEpicenterBounds != null ? new Rect(mEpicenterBounds) : null; + } + + /** + * <p>Sets the bounds used as the epicenter of the enter and exit transitions.</p> + * + * <p>Transitions use Rect, referred to as the epicenter, to orient + * the direction of travel. For popup windows, the anchor view bounds are + * used as the default epicenter.</p> + * + * <p>See {@link Transition#setEpicenterCallback(EpicenterCallback)} for more + * information about how transition epicenters work.</p> * * @param bounds the epicenter bounds relative to the anchor view, or * {@code null} to use the default epicenter - * @see #getTransitionEpicenter() - * @hide + * + * @see #getEpicenterBounds() */ - @UnsupportedAppUsage - public void setEpicenterBounds(Rect bounds) { - mEpicenterBounds = bounds; + public void setEpicenterBounds(@Nullable Rect bounds) { + mEpicenterBounds = bounds != null ? new Rect(bounds) : null; } private Transition getTransition(int resId) { @@ -865,12 +882,28 @@ public class PopupWindow { } /** - * Clip this popup window to the screen, but not to the containing window. + * <p>Indicates whether this popup will be clipped to the screen and not to the + * containing window<p/> * - * @param enabled True to clip to the screen. - * @hide + * @return true if popup will be clipped to the screen instead of the window, false otherwise + * + * @see #setClipToScreenEnabled(boolean) + */ + public boolean isClipToScreenEnabled() { + return mClipToScreen; + } + + /** + * <p>Clip this popup window to the screen, but not to the containing window.</p> + * + * <p>If the popup is showing, calling this method will take effect only + * the next time the popup is shown or through a manual call to one of + * the {@link #update()} methods.</p> + * + * @param enabled true to clip to the screen. + * + * @see #isClipToScreenEnabled() */ - @UnsupportedAppUsage public void setClipToScreenEnabled(boolean enabled) { mClipToScreen = enabled; } @@ -927,7 +960,8 @@ public class PopupWindow { * for positioning.</p> * * @return true if the window will always be positioned in screen coordinates. - * @hide + * + * @see #setLayoutInScreenEnabled(boolean) */ public boolean isLayoutInScreenEnabled() { return mLayoutInScreen; @@ -939,9 +973,9 @@ public class PopupWindow { * This will cause the popup to be positioned in absolute screen coordinates.</p> * * @param enabled true if the popup should always be positioned in screen coordinates - * @hide + * + * @see #isLayoutInScreenEnabled() */ - @UnsupportedAppUsage public void setLayoutInScreenEnabled(boolean enabled) { mLayoutInScreen = enabled; } @@ -1021,11 +1055,30 @@ public class PopupWindow { } /** - * Set whether this window is touch modal or if outside touches will be sent to - * other windows behind it. - * @hide + * <p>Indicates whether outside touches will be sent to this window + * or other windows behind it<p/> + * + * @return true if touches will be sent to this window, false otherwise + * + * @see #setTouchModal(boolean) + */ + public boolean isTouchModal() { + return !mNotTouchModal; + } + + /** + * <p>Set whether this window is touch modal or if outside touches will be sent to + * other windows behind it.<p/> + * + * <p>If the popup is showing, calling this method will take effect only + * the next time the popup is shown or through a manual call to one of + * the {@link #update()} methods.</p> + * + * @param touchModal true to sent all outside touches to this window, + * false to other windows behind it + * + * @see #isTouchModal() */ - @UnsupportedAppUsage public void setTouchModal(boolean touchModal) { mNotTouchModal = !touchModal; } @@ -1454,7 +1507,7 @@ public class PopupWindow { * * @param p the layout parameters of the popup's content view */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private void invokePopup(WindowManager.LayoutParams p) { if (mContext != null) { p.packageName = mContext.getPackageName(); @@ -2060,6 +2113,8 @@ public class PopupWindow { * <li>{@link #setInputMethodMode(int)}</li> * <li>{@link #setTouchable(boolean)}</li> * <li>{@link #setAnimationStyle(int)}</li> + * <li>{@link #setTouchModal(boolean)} (boolean)}</li> + * <li>{@link #setClipToScreenEnabled(boolean)}</li> * </ul> */ public void update() { diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 6b48c6584ad2..29f070ed5a65 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -203,7 +203,7 @@ public class ProgressBar extends View { private int mDuration; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private boolean mIndeterminate; - @UnsupportedAppUsage + @UnsupportedAppUsage(trackingBug = 124049927) private boolean mOnlyIndeterminate; private Transformation mTransformation; private AlphaAnimation mAnimation; @@ -211,7 +211,12 @@ public class ProgressBar extends View { private Drawable mIndeterminateDrawable; private Drawable mProgressDrawable; - @UnsupportedAppUsage + /** + * Outside the framework, instead of accessing this directly, please use + * {@link #getCurrentDrawable()}, {@link #setProgressDrawable(Drawable)}, + * {@link #setIndeterminateDrawable(Drawable)} and their tiled versions. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private Drawable mCurrentDrawable; private ProgressTintInfo mProgressTintInfo; @@ -262,6 +267,8 @@ public class ProgressBar extends View { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.ProgressBar, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.ProgressBar, + attrs, a, defStyleAttr, defStyleRes); mNoInvalidate = true; @@ -1298,9 +1305,14 @@ public class ProgressBar extends View { } /** - * @return The drawable currently used to draw the progress bar + * Returns the drawable currently used to draw the progress bar. This will be + * either {@link #getProgressDrawable()} or {@link #getIndeterminateDrawable()} + * depending on whether the progress bar is in determinate or indeterminate mode. + * + * @return the drawable currently used to draw the progress bar */ - Drawable getCurrentDrawable() { + @Nullable + public Drawable getCurrentDrawable() { return mCurrentDrawable; } diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java index 757a4ca04871..f3600b0de22b 100644 --- a/core/java/android/widget/RadialTimePickerView.java +++ b/core/java/android/widget/RadialTimePickerView.java @@ -404,6 +404,8 @@ public class RadialTimePickerView extends View { final Context context = getContext(); final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.TimePicker, + attrs, a, defStyleAttr, defStyleRes); final ColorStateList numbersTextColor = a.getColorStateList( R.styleable.TimePicker_numbersTextColor); diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java index ab12eaccad45..c62c16c7e719 100644 --- a/core/java/android/widget/RadioGroup.java +++ b/core/java/android/widget/RadioGroup.java @@ -98,6 +98,8 @@ public class RadioGroup extends LinearLayout { // XML layout file TypedArray attributes = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.RadioGroup, com.android.internal.R.attr.radioButtonStyle, 0); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.RadioGroup, + attrs, attributes, com.android.internal.R.attr.radioButtonStyle, 0); int value = attributes.getResourceId(R.styleable.RadioGroup_checkedButton, View.NO_ID); if (value != View.NO_ID) { diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java index 9f9fdee46fdf..3cf3d9102d21 100644 --- a/core/java/android/widget/RatingBar.java +++ b/core/java/android/widget/RatingBar.java @@ -93,6 +93,8 @@ public class RatingBar extends AbsSeekBar { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.RatingBar, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.RatingBar, + attrs, a, defStyleAttr, defStyleRes); final int numStars = a.getInt(R.styleable.RatingBar_numStars, mNumStars); setIsIndicator(a.getBoolean(R.styleable.RatingBar_isIndicator, !mIsUserSeekable)); final float rating = a.getFloat(R.styleable.RatingBar_rating, -1); diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index 556bfd19f942..109c0a432c1b 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -257,6 +257,8 @@ public class RelativeLayout extends ViewGroup { Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.RelativeLayout, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.RelativeLayout, + attrs, a, defStyleAttr, defStyleRes); mIgnoreGravity = a.getResourceId(R.styleable.RelativeLayout_ignoreGravity, View.NO_ID); mGravity = a.getInt(R.styleable.RelativeLayout_gravity, mGravity); a.recycle(); diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 24bc9f1e4985..7e72c6a4789c 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -16,6 +16,7 @@ package android.widget; +import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.content.Context; @@ -89,10 +90,25 @@ public class ScrollView extends FrameLayout { private final Rect mTempRect = new Rect(); @UnsupportedAppUsage private OverScroller mScroller; - @UnsupportedAppUsage - private EdgeEffect mEdgeGlowTop; - @UnsupportedAppUsage - private EdgeEffect mEdgeGlowBottom; + /** + * Tracks the state of the top edge glow. + * + * Even though this field is practically final, we cannot make it final because there are apps + * setting it via reflection and they need to keep working until they target Q. + */ + @NonNull + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768600) + private EdgeEffect mEdgeGlowTop = new EdgeEffect(getContext()); + + /** + * Tracks the state of the bottom edge glow. + * + * Even though this field is practically final, we cannot make it final because there are apps + * setting it via reflection and they need to keep working until they target Q. + */ + @NonNull + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769386) + private EdgeEffect mEdgeGlowBottom = new EdgeEffect(getContext()); /** * Position of the last motion event. @@ -141,13 +157,13 @@ public class ScrollView extends FrameLayout { private boolean mSmoothScrollingEnabled = true; private int mTouchSlop; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051125) private int mMinimumVelocity; private int mMaximumVelocity; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = VERSION_CODES.P, trackingBug = 124050903) private int mOverscrollDistance; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = VERSION_CODES.P, trackingBug = 124050903) private int mOverflingDistance; private float mVerticalScrollFactor; @@ -201,6 +217,8 @@ public class ScrollView extends FrameLayout { final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.ScrollView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ScrollView, + attrs, a, defStyleAttr, defStyleRes); setFillViewport(a.getBoolean(R.styleable.ScrollView_fillViewport, false)); @@ -247,6 +265,74 @@ public class ScrollView extends FrameLayout { } /** + * Sets the edge effect color for both top and bottom edge effects. + * + * @param color The color for the edge effects. + * @see #setTopEdgeEffectColor(int) + * @see #setBottomEdgeEffectColor(int) + * @see #getTopEdgeEffectColor() + * @see #getBottomEdgeEffectColor() + */ + public void setEdgeEffectColor(@ColorInt int color) { + setTopEdgeEffectColor(color); + setBottomEdgeEffectColor(color); + } + + /** + * Sets the bottom edge effect color. + * + * @param color The color for the bottom edge effect. + * @see #setTopEdgeEffectColor(int) + * @see #setEdgeEffectColor(int) + * @see #getTopEdgeEffectColor() + * @see #getBottomEdgeEffectColor() + */ + public void setBottomEdgeEffectColor(@ColorInt int color) { + mEdgeGlowBottom.setColor(color); + } + + /** + * Sets the top edge effect color. + * + * @param color The color for the top edge effect. + * @see #setBottomEdgeEffectColor(int) + * @see #setEdgeEffectColor(int) + * @see #getTopEdgeEffectColor() + * @see #getBottomEdgeEffectColor() + */ + public void setTopEdgeEffectColor(@ColorInt int color) { + mEdgeGlowTop.setColor(color); + } + + /** + * Returns the top edge effect color. + * + * @return The top edge effect color. + * @see #setEdgeEffectColor(int) + * @see #setTopEdgeEffectColor(int) + * @see #setBottomEdgeEffectColor(int) + * @see #getBottomEdgeEffectColor() + */ + @ColorInt + public int getTopEdgeEffectColor() { + return mEdgeGlowTop.getColor(); + } + + /** + * Returns the bottom edge effect color. + * + * @return The bottom edge effect color. + * @see #setEdgeEffectColor(int) + * @see #setTopEdgeEffectColor(int) + * @see #setBottomEdgeEffectColor(int) + * @see #getTopEdgeEffectColor() + */ + @ColorInt + public int getBottomEdgeEffectColor() { + return mEdgeGlowBottom.getColor(); + } + + /** * @return The maximum amount this scroll view will scroll in response to * an arrow event. */ @@ -624,6 +710,10 @@ public class ScrollView extends FrameLayout { return mIsBeingDragged; } + private boolean shouldDisplayEdgeEffects() { + return getOverScrollMode() != OVER_SCROLL_NEVER; + } + @Override public boolean onTouchEvent(MotionEvent ev) { initVelocityTrackerIfNotExists(); @@ -732,7 +822,7 @@ public class ScrollView extends FrameLayout { mEdgeGlowTop.onRelease(); } } - if (mEdgeGlowTop != null + if (shouldDisplayEdgeEffects() && (!mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished())) { postInvalidateOnAnimation(); } @@ -1670,7 +1760,7 @@ public class ScrollView extends FrameLayout { recycleVelocityTracker(); - if (mEdgeGlowTop != null) { + if (shouldDisplayEdgeEffects()) { mEdgeGlowTop.onRelease(); mEdgeGlowBottom.onRelease(); } @@ -1700,21 +1790,6 @@ public class ScrollView extends FrameLayout { } @Override - public void setOverScrollMode(int mode) { - if (mode != OVER_SCROLL_NEVER) { - if (mEdgeGlowTop == null) { - Context context = getContext(); - mEdgeGlowTop = new EdgeEffect(context); - mEdgeGlowBottom = new EdgeEffect(context); - } - } else { - mEdgeGlowTop = null; - mEdgeGlowBottom = null; - } - super.setOverScrollMode(mode); - } - - @Override public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { return (nestedScrollAxes & SCROLL_AXIS_VERTICAL) != 0; } @@ -1758,7 +1833,7 @@ public class ScrollView extends FrameLayout { @Override public void draw(Canvas canvas) { super.draw(canvas); - if (mEdgeGlowTop != null) { + if (shouldDisplayEdgeEffects()) { final int scrollY = mScrollY; final boolean clipToPadding = getClipToPadding(); if (!mEdgeGlowTop.isFinished()) { diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index af3b8c0afe08..630c38a734bd 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -283,6 +283,8 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.SearchView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.SearchView, + attrs, a, defStyleAttr, defStyleRes); final LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE); final int layoutResId = a.getResourceId( diff --git a/core/java/android/widget/SlidingDrawer.java b/core/java/android/widget/SlidingDrawer.java index 8011c3aef494..2ab2b2407a50 100644 --- a/core/java/android/widget/SlidingDrawer.java +++ b/core/java/android/widget/SlidingDrawer.java @@ -218,6 +218,8 @@ public class SlidingDrawer extends ViewGroup { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.SlidingDrawer, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.SlidingDrawer, + attrs, a, defStyleAttr, defStyleRes); int orientation = a.getInt(R.styleable.SlidingDrawer_orientation, ORIENTATION_VERTICAL); mVertical = orientation == ORIENTATION_VERTICAL; diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java index fb56d9739435..d6c657b4dc21 100644 --- a/core/java/android/widget/Spinner.java +++ b/core/java/android/widget/Spinner.java @@ -247,6 +247,8 @@ public class Spinner extends AbsSpinner implements OnClickListener { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.Spinner, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.Spinner, + attrs, a, defStyleAttr, defStyleRes); if (popupTheme != null) { mPopupContext = new ContextThemeWrapper(context, popupTheme); diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java index 6cc86b9b871c..5091eea1898d 100644 --- a/core/java/android/widget/StackView.java +++ b/core/java/android/widget/StackView.java @@ -176,6 +176,8 @@ public class StackView extends AdapterViewAnimator { super(context, attrs, defStyleAttr, defStyleRes); final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.StackView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.StackView, + attrs, a, defStyleAttr, defStyleRes); mResOutColor = a.getColor( com.android.internal.R.styleable.StackView_resOutColor, 0); diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index af4f0202fd6a..ea9cd421d438 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -239,6 +239,8 @@ public class Switch extends CompoundButton { final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.Switch, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.Switch, + attrs, a, defStyleAttr, defStyleRes); mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_thumb); if (mThumbDrawable != null) { mThumbDrawable.setCallback(this); diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java index b1fcbc33bbc9..481704c80287 100644 --- a/core/java/android/widget/TabHost.java +++ b/core/java/android/widget/TabHost.java @@ -93,6 +93,8 @@ public class TabHost extends FrameLayout implements ViewTreeObserver.OnTouchMode final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.TabWidget, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.TabWidget, + attrs, a, defStyleAttr, defStyleRes); mTabLayoutId = a.getResourceId(R.styleable.TabWidget_tabLayout, 0); a.recycle(); diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java index a90741b48684..49a0f39b3bad 100644 --- a/core/java/android/widget/TabWidget.java +++ b/core/java/android/widget/TabWidget.java @@ -95,6 +95,8 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.TabWidget, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.TabWidget, + attrs, a, defStyleAttr, defStyleRes); mDrawBottomStrips = a.getBoolean(R.styleable.TabWidget_tabStripEnabled, mDrawBottomStrips); diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java index 7f462cb3289b..616c4b51eca0 100644 --- a/core/java/android/widget/TextClock.java +++ b/core/java/android/widget/TextClock.java @@ -242,6 +242,8 @@ public class TextClock extends TextView { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.TextClock, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.TextClock, + attrs, a, defStyleAttr, defStyleRes); try { mFormat12 = a.getText(R.styleable.TextClock_format12Hour); mFormat24 = a.getText(R.styleable.TextClock_format24Hour); @@ -610,8 +612,16 @@ public class TextClock extends TextView { resolver.registerContentObserver(uri, true, mFormatChangeObserver, UserHandle.USER_ALL); } else { + // UserHandle.myUserId() is needed. This class is supported by the + // remote views mechanism and as a part of that the remote views + // can be inflated by a context for another user without the app + // having interact users permission - just for loading resources. + // For example, when adding widgets from a managed profile to the + // home screen. Therefore, we register the ContentObserver with the user + // the app is running (e.g. the launcher) and not the user of the + // context (e.g. the widget's profile). resolver.registerContentObserver(uri, true, - mFormatChangeObserver); + mFormatChangeObserver, UserHandle.myUserId()); } } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index d87600125a54..51eaa12aa314 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -664,7 +664,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @UnsupportedAppUsage private CharWrapper mCharWrapper; - @UnsupportedAppUsage + @UnsupportedAppUsage(trackingBug = 124050217) private Marquee mMarquee; @UnsupportedAppUsage private boolean mRestartMarquee; diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index b239ce638e68..97a8ade589d1 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -127,6 +127,8 @@ public class TimePicker extends FrameLayout { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.TimePicker, + attrs, a, defStyleAttr, defStyleRes); final boolean isDialogMode = a.getBoolean(R.styleable.TimePicker_dialogMode, false); final int requestedMode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER); a.recycle(); diff --git a/core/java/android/widget/ToggleButton.java b/core/java/android/widget/ToggleButton.java index bba6da6b7b4c..b76c2cafd912 100644 --- a/core/java/android/widget/ToggleButton.java +++ b/core/java/android/widget/ToggleButton.java @@ -48,6 +48,8 @@ public class ToggleButton extends CompoundButton { final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.ToggleButton, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ToggleButton, + attrs, a, defStyleAttr, defStyleRes); mTextOn = a.getText(com.android.internal.R.styleable.ToggleButton_textOn); mTextOff = a.getText(com.android.internal.R.styleable.ToggleButton_textOff); mDisabledAlpha = a.getFloat(com.android.internal.R.styleable.ToggleButton_disabledAlpha, 0.5f); diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index a33c47d86673..f25109ee82df 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -237,6 +237,8 @@ public class Toolbar extends ViewGroup { final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Toolbar, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.Toolbar, + attrs, a, defStyleAttr, defStyleRes); mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0); mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0); diff --git a/core/java/android/widget/TwoLineListItem.java b/core/java/android/widget/TwoLineListItem.java index 553b86e1f0c2..4c613a71a3ac 100644 --- a/core/java/android/widget/TwoLineListItem.java +++ b/core/java/android/widget/TwoLineListItem.java @@ -62,6 +62,8 @@ public class TwoLineListItem extends RelativeLayout { final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.TwoLineListItem, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.TwoLineListItem, + attrs, a, defStyleAttr, defStyleRes); a.recycle(); } diff --git a/core/java/com/android/internal/colorextraction/ColorExtractor.java b/core/java/com/android/internal/colorextraction/ColorExtractor.java index c171fa6b25fd..258d081c6ad8 100644 --- a/core/java/com/android/internal/colorextraction/ColorExtractor.java +++ b/core/java/com/android/internal/colorextraction/ColorExtractor.java @@ -22,7 +22,6 @@ import android.app.WallpaperColors; import android.app.WallpaperManager; import android.content.Context; import android.os.Trace; -import android.os.UserHandle; import android.util.Log; import android.util.SparseArray; @@ -32,7 +31,6 @@ import com.android.internal.colorextraction.types.Tonal; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Iterator; /** * Class to process wallpaper colors and generate a tonal palette based on them. @@ -222,6 +220,7 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener public static class GradientColors { private int mMainColor; private int mSecondaryColor; + private int[] mColorPalette; private boolean mSupportsDarkText; public void setMainColor(int mainColor) { @@ -232,6 +231,10 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener mSecondaryColor = secondaryColor; } + public void setColorPalette(int[] colorPalette) { + mColorPalette = colorPalette; + } + public void setSupportsDarkText(boolean supportsDarkText) { mSupportsDarkText = supportsDarkText; } @@ -239,6 +242,7 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener public void set(GradientColors other) { mMainColor = other.mMainColor; mSecondaryColor = other.mSecondaryColor; + mColorPalette = other.mColorPalette; mSupportsDarkText = other.mSupportsDarkText; } @@ -250,6 +254,10 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener return mSecondaryColor; } + public int[] getColorPalette() { + return mColorPalette; + } + public boolean supportsDarkText() { return mSupportsDarkText; } @@ -283,4 +291,4 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener public interface OnColorsChangedListener { void onColorsChanged(ColorExtractor colorExtractor, int which); } -}
\ No newline at end of file +} diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java index 3fd88dbb8704..d6a8934566b2 100644 --- a/core/java/com/android/internal/colorextraction/types/Tonal.java +++ b/core/java/com/android/internal/colorextraction/types/Tonal.java @@ -173,6 +173,7 @@ public class Tonal implements ExtractionType { Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY); float[] s = fit(palette.s, hsl[1], fitIndex, 0.0f, 1.0f); float[] l = fit(palette.l, hsl[2], fitIndex, 0.0f, 1.0f); + int[] colorPalette = getColorPalette(h, s, l); if (DEBUG) { StringBuilder builder = new StringBuilder("Tonal Palette - index: " + fitIndex + @@ -209,6 +210,7 @@ public class Tonal implements ExtractionType { // Normal colors: outColorsNormal.setMainColor(mainColor); outColorsNormal.setSecondaryColor(mainColor); + outColorsNormal.setColorPalette(colorPalette); // Dark colors: // Stops at 4th color, only lighter if dark text is supported @@ -222,6 +224,7 @@ public class Tonal implements ExtractionType { mainColor = getColorInt(primaryIndex, h, s, l); outColorsDark.setMainColor(mainColor); outColorsDark.setSecondaryColor(mainColor); + outColorsDark.setColorPalette(colorPalette); // Extra Dark: // Stay close to dark colors until dark text is supported @@ -235,6 +238,7 @@ public class Tonal implements ExtractionType { mainColor = getColorInt(primaryIndex, h, s, l); outColorsExtraDark.setMainColor(mainColor); outColorsExtraDark.setSecondaryColor(mainColor); + outColorsExtraDark.setColorPalette(colorPalette); outColorsNormal.setSupportsDarkText(supportsDarkText); outColorsDark.setSupportsDarkText(supportsDarkText); @@ -262,16 +266,19 @@ public class Tonal implements ExtractionType { * @param inWallpaperColors Colors to read. * @param outGradientColors Destination. */ - public static void applyFallback(@Nullable WallpaperColors inWallpaperColors, + public void applyFallback(@Nullable WallpaperColors inWallpaperColors, @NonNull GradientColors outGradientColors) { boolean light = inWallpaperColors != null && (inWallpaperColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0; final int color = light ? MAIN_COLOR_LIGHT : MAIN_COLOR_DARK; + final float[] hsl = new float[3]; + ColorUtils.colorToHSL(color, hsl); outGradientColors.setMainColor(color); outGradientColors.setSecondaryColor(color); outGradientColors.setSupportsDarkText(light); + outGradientColors.setColorPalette(getColorPalette(findTonalPalette(hsl[0], hsl[1]))); } private int getColorInt(int fitIndex, float[] h, float[] s, float[] l) { @@ -281,6 +288,19 @@ public class Tonal implements ExtractionType { return ColorUtils.HSLToColor(mTmpHSL); } + private int[] getColorPalette(float[] h, float[] s, float[] l) { + int[] colorPalette = new int[h.length]; + for (int i = 0; i < colorPalette.length; i++) { + colorPalette[i] = getColorInt(i, h, s, l); + } + return colorPalette; + } + + private int[] getColorPalette(TonalPalette palette) { + return getColorPalette(palette.h, palette.s, palette.l); + } + + /** * Checks if a given color exists in the blacklist * @param hsl float array with 3 components (H 0..360, S 0..1 and L 0..1) @@ -598,4 +618,4 @@ public class Tonal implements ExtractionType { return numbers; } } -}
\ No newline at end of file +} diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java index 2c272dea073b..7f4d8a2d0587 100644 --- a/core/java/com/android/internal/os/BinderCallsStats.java +++ b/core/java/com/android/internal/os/BinderCallsStats.java @@ -52,6 +52,8 @@ public class BinderCallsStats implements BinderInternal.Observer { public static final boolean ENABLED_DEFAULT = true; public static final boolean DETAILED_TRACKING_DEFAULT = true; public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 100; + public static final boolean DEFAULT_TRACK_SCREEN_INTERACTIVE = false; + public static final boolean DEFAULT_TRACK_DIRECT_CALLING_UID = true; public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 5000; private static final String DEBUG_ENTRY_PREFIX = "__DEBUG_"; @@ -85,6 +87,8 @@ public class BinderCallsStats implements BinderInternal.Observer { private long mStartElapsedTime = SystemClock.elapsedRealtime(); private long mCallStatsCount = 0; private boolean mAddDebugEntries = false; + private boolean mTrackDirectCallingUid = DEFAULT_TRACK_DIRECT_CALLING_UID; + private boolean mTrackScreenInteractive = DEFAULT_TRACK_SCREEN_INTERACTIVE; private CachedDeviceState.Readonly mDeviceState; private CachedDeviceState.TimeInStateStopwatch mBatteryStopwatch; @@ -160,7 +164,12 @@ public class BinderCallsStats implements BinderInternal.Observer { duration = 0; latencyDuration = 0; } - final int callingUid = getCallingUid(); + final boolean screenInteractive = mTrackScreenInteractive + ? mDeviceState.isScreenInteractive() + : OVERFLOW_SCREEN_INTERACTIVE; + final int callingUid = mTrackDirectCallingUid + ? getCallingUid() + : OVERFLOW_DIRECT_CALLING_UID; synchronized (mLock) { // This was already checked in #callStart but check again while synchronized. @@ -177,7 +186,7 @@ public class BinderCallsStats implements BinderInternal.Observer { final CallStat callStat = uidEntry.getOrCreate( callingUid, s.binderClass, s.transactionCode, - mDeviceState.isScreenInteractive(), + screenInteractive, mCallStatsCount >= mMaxBinderCallStatsCount); final boolean isNewCallStat = callStat.callCount == 0; if (isNewCallStat) { @@ -484,6 +493,30 @@ public class BinderCallsStats implements BinderInternal.Observer { } } + /** + * Whether to track the screen state. + */ + public void setTrackScreenInteractive(boolean enabled) { + synchronized (mLock) { + if (enabled != mTrackScreenInteractive) { + mTrackScreenInteractive = enabled; + reset(); + } + } + } + + /** + * Whether to track direct caller uid. + */ + public void setTrackDirectCallerUid(boolean enabled) { + synchronized (mLock) { + if (enabled != mTrackDirectCallingUid) { + mTrackDirectCallingUid = enabled; + reset(); + } + } + } + public void setAddDebugEntries(boolean addDebugEntries) { mAddDebugEntries = addDebugEntries; } diff --git a/core/java/com/android/internal/os/ChildZygoteInit.java b/core/java/com/android/internal/os/ChildZygoteInit.java index cc74863632dd..1f816c18f886 100644 --- a/core/java/com/android/internal/os/ChildZygoteInit.java +++ b/core/java/com/android/internal/os/ChildZygoteInit.java @@ -102,7 +102,7 @@ public class ChildZygoteInit { // are just isolated UIDs in the range, because for the webview zygote, there is no // single range that captures all possible isolated UIDs. // TODO(b/123615476) narrow this down - if (uidGidMin < Process.FIRST_ISOLATED_UID) { + if (uidGidMin < Process.FIRST_APP_ZYGOTE_ISOLATED_UID) { throw new RuntimeException("Passed in UID range does not map to isolated processes."); } diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java index b3d9ca7670b5..c059721eb2d3 100644 --- a/core/java/com/android/internal/os/LooperStats.java +++ b/core/java/com/android/internal/os/LooperStats.java @@ -39,6 +39,7 @@ import java.util.concurrent.ThreadLocalRandom; public class LooperStats implements Looper.Observer { public static final String DEBUG_ENTRY_PREFIX = "__DEBUG_"; private static final int SESSION_POOL_SIZE = 50; + private static final boolean DISABLED_SCREEN_STATE_TRACKING_VALUE = false; @GuardedBy("mLock") private final SparseArray<Entry> mEntries = new SparseArray<>(512); @@ -54,6 +55,7 @@ public class LooperStats implements Looper.Observer { private long mStartCurrentTime = System.currentTimeMillis(); private long mStartElapsedTime = SystemClock.elapsedRealtime(); private boolean mAddDebugEntries = false; + private boolean mTrackScreenInteractive = false; public LooperStats(int samplingInterval, int entriesSizeCap) { this.mSamplingInterval = samplingInterval; @@ -218,9 +220,15 @@ public class LooperStats implements Looper.Observer { mSamplingInterval = samplingInterval; } + public void setTrackScreenInteractive(boolean enabled) { + mTrackScreenInteractive = enabled; + } + @Nullable private Entry findEntry(Message msg, boolean allowCreateNew) { - final boolean isInteractive = mDeviceState.isScreenInteractive(); + final boolean isInteractive = mTrackScreenInteractive + ? mDeviceState.isScreenInteractive() + : DISABLED_SCREEN_STATE_TRACKING_VALUE; final int id = Entry.idFor(msg, isInteractive); Entry entry; synchronized (mLock) { diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 8b669d5db8df..40d78688cb4c 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -254,14 +254,14 @@ public final class Zygote { public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, - String packageName, String[] packagesForUID, String[] visibleVolIDs) { + String packageName, String[] packagesForUID, String[] visibleVolIDs, String sandboxId) { ZygoteHooks.preFork(); // Resets nice priority for zygote process. resetNicePriority(); int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir, packageName, - packagesForUID, visibleVolIDs); + packagesForUID, visibleVolIDs, sandboxId); // Enable tracing as soon as possible for the child process. if (pid == 0) { Trace.setTracingEnabled(true, runtimeFlags); @@ -276,7 +276,8 @@ public final class Zygote { private static native int nativeForkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, - String appDataDir, String packageName, String[] packagesForUID, String[] visibleVolIDs); + String appDataDir, String packageName, String[] packagesForUID, String[] visibleVolIDs, + String sandboxId); /** * Specialize a Blastula instance. The current VM must have been started @@ -302,11 +303,11 @@ public final class Zygote { public static void specializeBlastula(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir, String packageName, - String[] packagesForUID, String[] visibleVolIDs) { + String[] packagesForUID, String[] visibleVolIDs, String sandboxId) { nativeSpecializeBlastula(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, startChildZygote, instructionSet, appDataDir, - packageName, packagesForUID, visibleVolIDs); + packageName, packagesForUID, visibleVolIDs, sandboxId); // Enable tracing as soon as possible for the child process. Trace.setTracingEnabled(true, runtimeFlags); @@ -326,7 +327,7 @@ public final class Zygote { private static native void nativeSpecializeBlastula(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir, String packageName, - String[] packagesForUID, String[] visibleVolIDs); + String[] packagesForUID, String[] visibleVolIDs, String sandboxId); /** * Called to do any initialization before starting an application. @@ -638,7 +639,7 @@ public final class Zygote { args.mRuntimeFlags, rlimits, args.mMountExternal, args.mSeInfo, args.mNiceName, args.mStartChildZygote, args.mInstructionSet, args.mAppDataDir, args.mPackageName, - args.mPackagesForUid, args.mVisibleVolIds); + args.mPackagesForUid, args.mVisibleVolIds, args.mSandboxId); if (args.mNiceName != null) { Process.setArgV0(args.mNiceName); diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java index 24a08ca5b1e0..e6bcd37ad3e5 100644 --- a/core/java/com/android/internal/os/ZygoteArguments.java +++ b/core/java/com/android/internal/os/ZygoteArguments.java @@ -119,6 +119,9 @@ class ZygoteArguments { /** from --visible-vols */ String[] mVisibleVolIds; + /** from --sandbox-id */ + String mSandboxId; + /** * Any args after and including the first non-option arg (or after a '--') */ @@ -385,6 +388,11 @@ class ZygoteArguments { mPackagesForUid = arg.substring(arg.indexOf('=') + 1).split(","); } else if (arg.startsWith("--visible-vols=")) { mVisibleVolIds = arg.substring(arg.indexOf('=') + 1).split(","); + } else if (arg.startsWith("--sandbox-id=")) { + if (mSandboxId != null) { + throw new IllegalArgumentException("Duplicate arg specified"); + } + mSandboxId = arg.substring(arg.indexOf('=') + 1); } else { break; } diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 4ac7f5012613..9cf7e2770e86 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -258,7 +258,7 @@ class ZygoteConnection { parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote, parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mPackageName, - parsedArgs.mPackagesForUid, parsedArgs.mVisibleVolIds); + parsedArgs.mPackagesForUid, parsedArgs.mVisibleVolIds, parsedArgs.mSandboxId); try { if (pid == 0) { diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp index a9d75fd6aff7..15d1944205b6 100644 --- a/core/jni/android_opengl_EGL14.cpp +++ b/core/jni/android_opengl_EGL14.cpp @@ -107,6 +107,7 @@ fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) { if (obj == NULL){ jniThrowException(_env, "java/lang/IllegalArgumentException", "Object is set to null."); + return nullptr; } jlong handle = _env->CallLongMethod(obj, mid); @@ -238,6 +239,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return false; } return (jboolean)_returnValue; } @@ -335,6 +337,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return false; } return (jboolean)_returnValue; } @@ -454,6 +457,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return false; } return (jboolean)_returnValue; } @@ -509,6 +513,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return false; } return (jboolean)_returnValue; } @@ -582,6 +587,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return nullptr; } return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue); } @@ -664,6 +670,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return nullptr; } return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue); } @@ -721,6 +728,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return nullptr; } return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue); } @@ -731,7 +739,7 @@ android_eglCreatePixmapSurface (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jint pixmap, jintArray attrib_list_ref, jint offset) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglCreatePixmapSurface"); - return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, (EGLSurface) 0); + return nullptr; } /* EGLBoolean eglDestroySurface ( EGLDisplay dpy, EGLSurface surface ) */ @@ -800,6 +808,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return false; } return (jboolean)_returnValue; } @@ -898,6 +907,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return nullptr; } return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue); } @@ -1034,6 +1044,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return nullptr; } return toEGLHandle(_env, eglcontextClass, eglcontextConstructor, _returnValue); } @@ -1152,6 +1163,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return false; } return (jboolean)_returnValue; } diff --git a/core/jni/android_opengl_EGL15.cpp b/core/jni/android_opengl_EGL15.cpp index b52f137da7d6..2abd95020f1c 100644 --- a/core/jni/android_opengl_EGL15.cpp +++ b/core/jni/android_opengl_EGL15.cpp @@ -194,6 +194,7 @@ fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) { if (obj == NULL){ jniThrowException(_env, "java/lang/IllegalArgumentException", "Object is set to null."); + return nullptr; } jlong handle = _env->CallLongMethod(obj, mid); @@ -254,6 +255,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return nullptr; } return toEGLHandle(_env, eglsyncClass, eglsyncConstructor, _returnValue); } @@ -335,6 +337,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return false; } return (jboolean)_returnValue; } @@ -381,6 +384,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return nullptr; } return toEGLHandle(_env, egldisplayClass, egldisplayConstructor, _returnValue); } @@ -448,6 +452,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return nullptr; } return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue); } @@ -456,8 +461,11 @@ exit: static jobject android_eglCreatePlatformPixmapSurface (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject native_pixmap_buf, jlongArray attrib_list_ref, jint offset) { - jniThrowException(_env, "java/lang/UnsupportedOperationException", - "eglCreatePlatformPixmapSurface"); + if ((true)) { + jniThrowException(_env, "java/lang/UnsupportedOperationException", + "eglCreatePlatformPixmapSurface"); + return nullptr; + } return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, (EGLSurface) 0); } @@ -523,6 +531,7 @@ exit: } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); + return nullptr; } return toEGLHandle(_env, eglimageClass, eglimageConstructor, _returnValue); } diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index d493ddfaae13..a212f47c0104 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -104,6 +104,12 @@ static struct configuration_offsets_t { jfieldID mScreenHeightDpOffset; } gConfigurationOffsets; +static struct arraymap_offsets_t { + jclass classObject; + jmethodID constructor; + jmethodID put; +} gArrayMapOffsets; + jclass g_stringClass = nullptr; // ---------------------------------------------------------------------------- @@ -326,6 +332,50 @@ static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) { return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr)); } +static jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr, + jstring package_name) { + ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); + const ScopedUtfChars package_name_utf8(env, package_name); + CHECK(package_name_utf8.c_str() != nullptr); + const std::string std_package_name(package_name_utf8.c_str()); + const std::unordered_map<std::string, std::string>* map = nullptr; + + assetmanager->ForEachPackage([&](const std::string& this_package_name, uint8_t package_id) { + if (this_package_name == std_package_name) { + map = assetmanager->GetOverlayableMapForPackage(package_id); + } + }); + + if (map == nullptr) { + return nullptr; + } + + jobject array_map = env->NewObject(gArrayMapOffsets.classObject, gArrayMapOffsets.constructor); + if (array_map == nullptr) { + return nullptr; + } + + for (const auto& iter : *map) { + jstring name = env->NewStringUTF(iter.first.c_str()); + if (env->ExceptionCheck()) { + return nullptr; + } + + jstring actor = env->NewStringUTF(iter.second.c_str()); + if (env->ExceptionCheck()) { + env->DeleteLocalRef(name); + return nullptr; + } + + env->CallObjectMethod(array_map, gArrayMapOffsets.put, name, actor); + + env->DeleteLocalRef(name); + env->DeleteLocalRef(actor); + } + + return array_map; +} + static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset, jlongArray out_offsets) { off64_t start_offset, length; @@ -1524,6 +1574,8 @@ static const JNINativeMethod gAssetManagerMethods[] = { {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps}, {"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;", (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid}, + {"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;", + (void*)NativeGetOverlayableMap}, // Global management/debug methods. {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount}, @@ -1575,6 +1627,14 @@ int register_android_content_AssetManager(JNIEnv* env) { gConfigurationOffsets.mScreenHeightDpOffset = GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I"); + jclass arrayMapClass = FindClassOrDie(env, "android/util/ArrayMap"); + gArrayMapOffsets.classObject = MakeGlobalRefOrDie(env, arrayMapClass); + gArrayMapOffsets.constructor = + GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "<init>", "()V"); + gArrayMapOffsets.put = + GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods)); } diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 0ef4f874f583..d04db92294d7 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -598,72 +598,80 @@ static int UnmountTree(const char* path) { return 0; } +static void CreateDir(const std::string& dir, + mode_t mode, uid_t uid, gid_t gid, + fail_fn_t fail_fn) { + if (TEMP_FAILURE_RETRY(access(dir.c_str(), F_OK)) == 0) { + return; + } else if (errno != ENOENT) { + fail_fn(CREATE_ERROR("Failed to stat %s: %s", dir.c_str(), strerror(errno))); + } + if (fs_prepare_dir(dir.c_str(), mode, uid, gid) != 0) { + fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s: %s", + dir.c_str(), strerror(errno))); + } +} + static void CreatePkgSandbox(uid_t uid, const std::string& package_name, fail_fn_t fail_fn) { // Create /mnt/user/0/package/<package-name> userid_t user_id = multiuser_get_user_id(uid); std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id); - if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0751, AID_ROOT, AID_ROOT) != 0) { - fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str())); - } + CreateDir(pkg_sandbox_dir, 0751, AID_ROOT, AID_ROOT, fail_fn); StringAppendF(&pkg_sandbox_dir, "/package"); - if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) { - fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str())); - } + CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn); StringAppendF(&pkg_sandbox_dir, "/%s", package_name.c_str()); - if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0755, uid, uid) != 0) { - fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str())); - } + CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn); } static void BindMount(const std::string& sourceDir, const std::string& targetDir, fail_fn_t fail_fn) { if (TEMP_FAILURE_RETRY(mount(sourceDir.c_str(), targetDir.c_str(), nullptr, - MS_BIND | MS_REC, nullptr)) == -1) { + MS_BIND, nullptr)) == -1) { fail_fn(CREATE_ERROR("Failed to mount %s to %s: %s", sourceDir.c_str(), targetDir.c_str(), strerror(errno))); } - - if (TEMP_FAILURE_RETRY(mount(nullptr, targetDir.c_str(), nullptr, - MS_SLAVE | MS_REC, nullptr)) == -1) { - fail_fn(CREATE_ERROR("Failed to set MS_SLAVE for %s", targetDir.c_str())); - } } static void MountPkgSpecificDir(const std::string& mntSourceRoot, const std::string& mntTargetRoot, const std::string& packageName, + uid_t uid, const char* dirName, fail_fn_t fail_fn) { std::string mntSourceDir = StringPrintf("%s/Android/%s/%s", mntSourceRoot.c_str(), dirName, packageName.c_str()); + CreateDir(mntSourceDir, 0755, uid, uid, fail_fn); + std::string mntTargetDir = StringPrintf("%s/Android/%s/%s", mntTargetRoot.c_str(), dirName, packageName.c_str()); + CreateDir(mntTargetDir, 0755, uid, uid, fail_fn); BindMount(mntSourceDir, mntTargetDir, fail_fn); } + +static void createPkgSpecificDirRoots(const std::string& parentDir, + bool createSandbox, + mode_t mode, uid_t uid, gid_t gid, + fail_fn_t fail_fn) { + std::string androidDir = StringPrintf("%s/Android", parentDir.c_str()); + CreateDir(androidDir, mode, uid, gid, fail_fn); + std::vector<std::string> dirs = {"data", "media", "obb"}; + if (createSandbox) { + dirs.push_back("sandbox"); + } + for (auto& dir : dirs) { + std::string path = StringPrintf("%s/%s", androidDir.c_str(), dir.c_str()); + CreateDir(path, mode, uid, gid, fail_fn); + } +} + static void PreparePkgSpecificDirs(const std::vector<std::string>& packageNames, const std::vector<std::string>& volumeLabels, - bool mountAllObbs, userid_t userId, fail_fn_t fail_fn) { - if (volumeLabels.size() > 0) { - std::string sandboxDataDir = StringPrintf("/storage/%s", volumeLabels[0].c_str()); - if (volumeLabels[0] == "emulated") { - StringAppendF(&sandboxDataDir, "/%d", userId); - } - StringAppendF(&sandboxDataDir, "/Android/data/%s", packageNames[0].c_str()); - struct stat sb; - if (TEMP_FAILURE_RETRY(lstat(sandboxDataDir.c_str(), &sb)) == -1) { - if (errno == ENOENT) { - ALOGD("Sandbox not fully prepared for %s", sandboxDataDir.c_str()); - return; - } else { - fail_fn(CREATE_ERROR("Failed to lstat %s: %s", - sandboxDataDir.c_str(), strerror(errno))); - } - } - } + bool mountAllObbs, const std::string& sandboxId, + userid_t userId, uid_t uid, fail_fn_t fail_fn) { for (auto& label : volumeLabels) { std::string mntSource = StringPrintf("/mnt/runtime/write/%s", label.c_str()); std::string mntTarget = StringPrintf("/storage/%s", label.c_str()); @@ -672,11 +680,26 @@ static void PreparePkgSpecificDirs(const std::vector<std::string>& packageNames, StringAppendF(&mntTarget, "/%d", userId); } + if (TEMP_FAILURE_RETRY(access(mntSource.c_str(), F_OK)) < 0) { + ALOGE("Can't access %s: %s", mntSource.c_str(), strerror(errno)); + continue; + } + + // Create /mnt/runtime/write/emulated/0/Android/{data,media,obb,sandbox} + createPkgSpecificDirRoots(mntSource, true, 0700, AID_ROOT, AID_ROOT, fail_fn); + + std::string sandboxSource = StringPrintf("%s/Android/sandbox/%s", + mntSource.c_str(), sandboxId.c_str()); + CreateDir(sandboxSource, 0755, uid, uid, fail_fn); + BindMount(sandboxSource, mntTarget, fail_fn); + + // Create /storage/emulated/0/Android/{data,media,obb} + createPkgSpecificDirRoots(mntTarget, false, 0755, uid, uid, fail_fn); for (auto& package : packageNames) { - MountPkgSpecificDir(mntSource, mntTarget, package, "data", fail_fn); - MountPkgSpecificDir(mntSource, mntTarget, package, "media", fail_fn); + MountPkgSpecificDir(mntSource, mntTarget, package, uid, "data", fail_fn); + MountPkgSpecificDir(mntSource, mntTarget, package, uid, "media", fail_fn); if (!mountAllObbs) { - MountPkgSpecificDir(mntSource, mntTarget, package, "obb", fail_fn); + MountPkgSpecificDir(mntSource, mntTarget, package, uid, "obb", fail_fn); } } @@ -693,7 +716,8 @@ static void PreparePkgSpecificDirs(const std::vector<std::string>& packageNames, static void MountEmulatedStorage(uid_t uid, jint mount_mode, bool force_mount_namespace, const std::string& package_name, const std::vector<std::string>& packages_for_uid, - const std::vector<std::string>& visible_vol_ids, fail_fn_t fail_fn) { + const std::vector<std::string>& visible_vol_ids, const std::string& sandbox_id, + fail_fn_t fail_fn) { // See storage config details at http://source.android.com/tech/storage/ String8 storageSource; @@ -744,7 +768,7 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode, strerror(errno))); } } else { - if (package_name.empty()) { + if (package_name.empty() || sandbox_id.empty()) { return; } @@ -790,7 +814,7 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode, // care of by vold later. if (sandboxAlreadyCreated) { PreparePkgSpecificDirs(packages_for_uid, visible_vol_ids, - mount_mode == MOUNT_EXTERNAL_INSTALLER, user_id, fail_fn); + mount_mode == MOUNT_EXTERNAL_INSTALLER, sandbox_id, user_id, uid, fail_fn); } } } else { @@ -1127,7 +1151,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, bool is_child_zygote, jstring managed_instruction_set, jstring managed_app_data_dir, jstring managed_package_name, jobjectArray managed_pacakges_for_uid, - jobjectArray managed_visible_vol_ids) { + jobjectArray managed_visible_vol_ids, jstring managed_sandbox_id) { const char* process_name = is_system_server ? "system_server" : "zygote"; auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1); auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1); @@ -1137,6 +1161,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, auto instruction_set = extract_fn(managed_instruction_set); auto app_data_dir = extract_fn(managed_app_data_dir); auto package_name = extract_fn(managed_package_name); + auto sandbox_id = extract_fn(managed_sandbox_id); // Keep capabilities across UID change, unless we're staying root. if (uid != 0) { @@ -1179,7 +1204,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, value_or(std::vector<std::string>()); MountEmulatedStorage(uid, mount_external, use_native_bridge, package_name.value(), - packages_for_uid, visible_vol_ids, fail_fn); + packages_for_uid, visible_vol_ids, sandbox_id.value_or(""), fail_fn); // If this zygote isn't root, it won't be able to create a process group, // since the directory is owned by root. @@ -1479,7 +1504,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( jint mount_external, jstring se_info, jstring nice_name, jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jstring package_name, - jobjectArray packages_for_uid, jobjectArray visible_vol_ids) { + jobjectArray packages_for_uid, jobjectArray visible_vol_ids, jstring sandbox_id) { jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); if (UNLIKELY(managed_fds_to_close == nullptr)) { @@ -1511,7 +1536,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( capabilities, capabilities, mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE, instruction_set, app_data_dir, - package_name, packages_for_uid, visible_vol_ids); + package_name, packages_for_uid, visible_vol_ids, sandbox_id); } return pid; } @@ -1537,7 +1562,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true, - false, nullptr, nullptr, nullptr, nullptr, nullptr); + false, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); } else if (pid > 0) { // The zygote process checks whether the child process has died or not. ALOGI("System server process %d has been created", pid); @@ -1691,14 +1716,15 @@ static void com_android_internal_os_Zygote_nativeSpecializeBlastula( jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, - jstring package_name, jobjectArray packages_for_uid, jobjectArray visible_vol_ids) { + jstring package_name, jobjectArray packages_for_uid, jobjectArray visible_vol_ids, + jstring sandbox_id) { jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities, mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE, instruction_set, app_data_dir, - package_name, packages_for_uid, visible_vol_ids); + package_name, packages_for_uid, visible_vol_ids, sandbox_id); } /** @@ -1789,7 +1815,7 @@ static const JNINativeMethod gMethods[] = { { "nativeSecurityInit", "()V", (void *) com_android_internal_os_Zygote_nativeSecurityInit }, { "nativeForkAndSpecialize", - "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)I", + "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)I", (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize }, { "nativeForkSystemServer", "(II[II[[IJJ)I", (void *) com_android_internal_os_Zygote_nativeForkSystemServer }, @@ -1804,7 +1830,7 @@ static const JNINativeMethod gMethods[] = { { "nativeForkBlastula", "(II[I)I", (void *) com_android_internal_os_Zygote_nativeForkBlastula }, { "nativeSpecializeBlastula", - "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V", + "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V", (void *) com_android_internal_os_Zygote_nativeSpecializeBlastula }, { "nativeGetSocketFDs", "(Z)V", (void *) com_android_internal_os_Zygote_nativeGetSocketFDs }, diff --git a/core/jni/runtime_native_boot-flags-test.sh b/core/jni/runtime_native_boot-flags-test.sh new file mode 100755 index 000000000000..66e18bb19c44 --- /dev/null +++ b/core/jni/runtime_native_boot-flags-test.sh @@ -0,0 +1,244 @@ +#!/bin/bash + +# Copyright (C) 2019 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. +# + +# Test Android Runtime (Boot) device configuration flags (living in namespace +# `runtime_native_boot`). + +me=$(basename $0) + +# Namespace containing the tested flag. +namespace=runtime_native_boot +# Default set of checked zygote processes. +zygotes= + +# Status of whole test script. +exit_status=0 + +function say { + echo "$me: $*" +} + +function banner { + local separator=$(echo "$@" | sed s/./=/g ) + say "$separator" + say "$@" + say "$separator" +} + +function fail { + say "FAILED: $@" + exit_status=1 +} + +function reboot_and_wait_for_device { + say "Rebooting device..." + adb reboot + adb wait-for-device >/dev/null + # Wait until the device has finished booting. Give the device 60 iterations + # (~60 seconds) to try and finish booting before declaring defeat. + local niters=60 + for i in $(seq $niters); do + [[ $(adb shell getprop sys.boot_completed) -eq 1 ]] && return 0 + sleep 1 + done + fail "Device did not finish booting before timeout (~$niters seconds)" +} + +# check_device_config_flag CONTEXT FLAG VALUE +# ------------------------------------------- +# Check that the device configuration flag FLAG is set to VALUE. Use CONTEXT in +# logging. +function check_device_config_flag { + local context=$1 + local flag=$2 + local value=$3 + + say "[$context] Check that the device configuration flag is set..." + local flag_value=$(adb shell device_config get "$namespace" "$flag") + [[ "$flag_value" = "$value" ]] \ + || fail "Device configuration flag \`$flag\` set to \`$flag_value\` (expected \`$value\`)" +} + +# check_no_device_config_flag CONTEXT FLAG +# ---------------------------------------- +# Check that the device configuration flag FLAG is not set. Use CONTEXT in +# logging. +function check_no_device_config_flag { + local context=$1 + local flag=$2 + + say "[$context] Check that the device configuration flag is not set..." + local flag_value=$(adb shell device_config get "$namespace" "$flag") + [[ "$flag_value" = null ]] \ + || fail "Device configuration flag \`$flag\` set to \`$flag_value\` (expected `null`)" +} + +# get_system_property PROP +# ------------------------ +# Get system property PROP associated with a device configuration flag. +function get_system_property { + local prop=$1 + + # Note that we need to be root to read that system property. + adb root >/dev/null + local prop_value=$(adb shell getprop "$prop") + adb unroot >/dev/null + echo "$prop_value" +} + +# check_system_property CONTEXT PROP VALUE +# ---------------------------------------- +# Check that the system property PROP associated with a device configuration +# flag is set to VALUE. Use CONTEXT in logging. +function check_system_property { + local context=$1 + local prop=$2 + local value=$3 + + say "[$context] Check that the persistent system property is set..." + local prop_value=$(get_system_property "$prop") + [[ "$prop_value" = "$value" ]] \ + || fail "System property \`$prop\` set to \`$prop_value\` (expected \`$value\`)" +} + +# check_no_system_property CONTEXT PROP +# ------------------------------------- +# Check that the system property PROP associated with a device configuration +# flag is not set. Use CONTEXT in logging. +function check_no_system_property { + local context=$1 + local prop=$2 + + say "[$context] Check that the persistent system property is not set..." + local prop_value=$(get_system_property "$prop") + [[ -z "$prop_value" ]] \ + || fail "System property \`$prop\` set to \`$prop_value\` (expected unset property)" +} + +# find_zygote_runtime_option ZYGOTE RUNTIME_OPTION +# ------------------------------------------------ +# Return whether ZYGOTE is passed RUNTIME_OPTION. +function find_zygote_runtime_option { + local zygote=$1 + local runtime_option=$2 + + adb logcat -d -s "$zygote" | grep -q -e "option\[[0-9]\+\]=$runtime_option" +} + +# check_zygote_gc_runtime_option CONTEXT VALUE +# -------------------------------------------- +# Check that all zygote processes are passed device configuration flag VALUE as +# GC runtime option. Use CONTEXT in logging. +function check_zygote_gc_runtime_option { + local context=$1 + local value=$2 + + say \ + "[$context] Check that all zygote processes are passed the flag value as a GC runtime option..." + local runtime_option="-Xgc:$value" + for zygote in $zygotes; do + find_zygote_runtime_option "$zygote" "$runtime_option"\ + || fail "Found no \`$runtime_option\` among runtime options passed to \`$zygote\`" + done +} + +# check_no_zygote_gc_runtime_option CONTEXT VALUE +# ----------------------------------------------- +# Check that no zygote process is passed device configuration flag VALUE as GC +# runtime option. Use CONTEXT in logging. +function check_no_zygote_gc_runtime_option { + local context=$1 + local value=$2 + + say "[$context] Check no zygote process is passed the flag value as a GC runtime option..." + local runtime_option="-Xgc:$value" + for zygote in $zygotes; do + find_zygote_runtime_option "$zygote" "$runtime_option"\ + && fail "Found \`$runtime_option\` among runtime options passed to \`$zygote\`" + done +} + +# test_android_runtime_flag FLAG VALUE +# ------------------------------------ +# Test device configuration FLAG with VALUE. +function test_android_runtime_flag { + local flag=$1 + local value=$2 + + # Persistent system property (set after a reboot) associated with the device + # configuration flag. + local prop="persist.device_config.$namespace.$flag" + + banner "Testing \`$flag\` value \`$value\`." + + say "Setting device configuration flag..." + adb shell device_config put "$namespace" "$flag" "$value" + # Give some time to the device to digest this change before rebooting. + sleep 3 + + # Check that both the device configuration flag and the associated system + # property are set, but that the zygote hasn't had the flag passed to it as a + # GC runtime option (as we haven't rebooted yet). + local context="Flag set, before reboot" + check_device_config_flag "$context" "$flag" "$value" + check_system_property "$context" "$prop" "$value" + check_no_zygote_gc_runtime_option "$context" "$value" + + # Reboot device for the flag value to take effect. + reboot_and_wait_for_device + context="Flag set, after 1st reboot" + check_device_config_flag "$context" "$flag" "$value" + check_system_property "$context" "$prop" "$value" + check_zygote_gc_runtime_option "$context" "$value" + + # Reboot device a second time and check that the state has persisted. + reboot_and_wait_for_device + context="Flag set, after 2nd reboot" + check_device_config_flag "$context" "$flag" "$value" + check_system_property "$context" "$prop" "$value" + check_zygote_gc_runtime_option "$context" "$value" + + say "Unsetting device configuration flag..." + adb shell device_config delete "$namespace" "$flag" >/dev/null + # Give some time to the device to digest this change before rebooting. + sleep 3 + + # Reboot and check that the device is back to its default state. + reboot_and_wait_for_device + context="Flag unset, after 3rd reboot" + check_no_device_config_flag "$context" "$flag" + check_no_system_property "$context" "$prop" + check_no_zygote_gc_runtime_option "$context" "$value" +} + +# Enumerate Zygote processes. +case $(adb shell getprop ro.zygote) in + (zygote32) zygotes="zygote";; + (zygote64) zygotes="zygote64";; + (zygote32_64|zygote64_32) zygotes="zygote zygote64";; +esac + +# Test "gctype" flag values. +test_android_runtime_flag gctype nogenerational_cc +test_android_runtime_flag gctype generational_cc + +if [[ "$exit_status" -eq 0 ]]; then + banner "All tests passed." +else + banner "Test(s) failed." +fi +exit $exit_status diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto index 5b5c9c28b4a0..b4f3d1ea5ae4 100644 --- a/core/proto/android/bluetooth/enums.proto +++ b/core/proto/android/bluetooth/enums.proto @@ -132,3 +132,9 @@ enum SocketConnectionstateEnum { // This socket is closed SOCKET_CONNECTION_STATE_DISCONNECTED = 5; } + +enum SocketRoleEnum { + SOCKET_ROLE_UNKNOWN = 0; + SOCKET_ROLE_LISTEN = 1; + SOCKET_ROLE_CONNECTION = 2; +} diff --git a/core/proto/android/hardware/biometrics/enums.proto b/core/proto/android/hardware/biometrics/enums.proto index 91f2acbbaf03..973e3e65cf1a 100644 --- a/core/proto/android/hardware/biometrics/enums.proto +++ b/core/proto/android/hardware/biometrics/enums.proto @@ -43,4 +43,16 @@ enum ActionEnum { ACTION_AUTHENTICATE = 2; ACTION_ENUMERATE = 3; ACTION_REMOVE = 4; +} + +enum IssueEnum { + ISSUE_UNKNOWN = 0; + // When a biometric HAL has crashed. + ISSUE_HAL_DEATH = 1; + // When Android Framework has a template that doesn't exist in the HAL. The framework + // is expected to remove its template to stay in sync with the HAL. + ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK = 2; + // When the HAL has a template that doesn't exist in Android Framework. The framework + // is expected to notify the HAL to remove this template to stay in sync with the framework. + ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL = 3; }
\ No newline at end of file diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index d5776534bb90..39d61a15eb28 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -448,6 +448,9 @@ message GlobalSettingsProto { optional SettingProto game_driver_whitelist = 12; // ANGLE - List of Apps that can check ANGLE rules optional SettingProto angle_whitelist = 13; + // Game Driver - List of blacklists, each blacklist is a blacklist for + // a specific Game Driver version + optional SettingProto game_driver_blacklists = 14; } optional Gpu gpu = 59; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 07dd26e4969b..5b74d90608f7 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2151,13 +2151,13 @@ android:label="@string/permlab_disableKeyguard" android:protectionLevel="normal" /> - <!-- Allows an application to get the screen lock complexity and prompt users to update the + <!-- Allows an application to request the screen lock complexity and prompt users to update the screen lock to a certain complexity level. <p>Protection level: normal --> - <permission android:name="android.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY" - android:label="@string/permlab_getAndRequestScreenLockComplexity" - android:description="@string/permdesc_getAndRequestScreenLockComplexity" + <permission android:name="android.permission.REQUEST_SCREEN_LOCK_COMPLEXITY" + android:label="@string/permlab_requestScreenLockComplexity" + android:description="@string/permdesc_requestScreenLockComplexity" android:protectionLevel="normal" /> <!-- ================================== --> @@ -2267,7 +2267,7 @@ <!-- Allows an application to start activities from background @hide --> <permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" - android:protectionLevel="signature|privileged|vendorPrivileged|oem" /> + android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier" /> <!-- @SystemApi Must be required by activities that handle the intent action {@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that diff --git a/core/res/res/drawable/bottomsheet_background.xml b/core/res/res/drawable/bottomsheet_background.xml index bc32ba6e3896..3a8ad71187a0 100644 --- a/core/res/res/drawable/bottomsheet_background.xml +++ b/core/res/res/drawable/bottomsheet_background.xml @@ -16,7 +16,7 @@ <shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android"> <corners - android:topLeftRadius="?attr/dialogCornerRadius" - android:topRightRadius="?attr/dialogCornerRadius" /> + android:topLeftRadius="@dimen/config_bottomDialogCornerRadius" + android:topRightRadius="@dimen/config_bottomDialogCornerRadius"/> <solid android:color="?attr/colorBackgroundFloating" /> </shape> diff --git a/core/res/res/drawable/ic_action_open.xml b/core/res/res/drawable/ic_action_open.xml new file mode 100644 index 000000000000..3d3d36ece0af --- /dev/null +++ b/core/res/res/drawable/ic_action_open.xml @@ -0,0 +1,24 @@ +<!-- +Copyright (C) 2019 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF737373" + android:pathData="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/> +</vector>
\ No newline at end of file diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 53cae638db80..1053184bc2fc 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -118,7 +118,7 @@ <attr name="manageSpaceActivity" format="string" /> <!-- Option to let applications specify that user data can/cannot be - cleared. This flag is turned on by default. + cleared by the user in Settings. This flag is turned on by default. <em>This attribute is usable only by applications included in the system image. Third-party apps cannot use it.</em> --> <attr name="allowClearUserData" format="boolean" /> @@ -1661,7 +1661,12 @@ <!-- If {@code true} the user is prompted to keep the app's data on uninstall --> <attr name="hasFragileUserData" /> - <attr name="zygotePreloadName" /> + <attr name="zygotePreloadName" /> + + <!-- If {@code true} the system will clear app's data if a restore operation fails. + This flag is turned on by default. <em>This attribute is usable only by system apps. + </em> --> + <attr name="allowClearUserDataOnFailedRestore"/> </declare-styleable> <!-- The <code>permission</code> tag declares a security permission that can be used to control access from other packages to specific components or diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index ec53811a6983..d14164f69850 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1921,8 +1921,6 @@ cell broadcasting sms, and MMS. --> <bool name="config_sms_capable">true</bool> - <!-- TODO: STOPSHIP(b/110557011): Remove this from framework and overlays as we use - config_defaultRoleHolders now. --> <!-- Default SMS Application. This will be the default SMS application when the phone first boots. The user can then change the default app to one of their choosing. @@ -1930,15 +1928,33 @@ application is desired. If this string is empty or the specified package does not exist, then - the platform will search for an SMS app and use that (if there is one)--> + the platform will search for an SMS app and use that (if there is one) + + Note: This config is deprecated, please use config_defaultSms instead. --> <string name="default_sms_application" translatable="false">com.android.messaging</string> - <!-- Default role holders. This will be an array of roles and package names of their default - holders, with each item in the format of "ROLE_NAME: PACKAGE_NAME_1, PACKAGE_NAME_2". --> - <string-array name="config_defaultRoleHolders" translatable="false"> - <item>android.app.role.SMS: com.android.messaging</item> - <item>android.app.role.DIALER: com.android.phone</item> - </string-array> + <!-- Default web browser. This is the package name of the application that will + be the default browser when the device first boots. Afterwards the user + can select whatever browser app they wish to use as the default. + + If this string is empty or the specified package does not exist, then + the behavior will be as though no app was named as an explicit default. + + Note: This config is deprecated, please use config_defaultBrowser instead. --> + <string name="default_browser" translatable="false"></string> + + <!-- The name of the package that will hold the assistant role by default. --> + <string name="config_defaultAssistant" translatable="false" /> + <!-- The name of the package that will hold the browser role by default. --> + <string name="config_defaultBrowser" translatable="false">@string/default_browser</string> + <!-- The name of the package that will hold the dialer role by default. --> + <string name="config_defaultDialer" translatable="false">com.android.phone</string> + <!-- The name of the package that will hold the SMS role by default. --> + <string name="config_defaultSms" translatable="false">@string/default_sms_application</string> + <!-- The name of the package that will hold the music role by default. --> + <string name="config_defaultMusic" translatable="false">com.android.music</string> + <!-- The name of the package that will hold the gallery role by default. --> + <string name="config_defaultGallery" translatable="false">com.android.gallery3d</string> <!-- Enable/disable default bluetooth profiles: HSP_AG, ObexObjectPush, Audio, NAP --> @@ -3409,8 +3425,14 @@ --> <string-array translatable="false" name="config_convert_to_emergency_number_map" /> - <!-- An array of packages for which notifications cannot be blocked. --> - <string-array translatable="false" name="config_nonBlockableNotificationPackages" /> + <!-- An array of packages for which notifications cannot be blocked. + Should only be used for core device functionality that must not be + rendered inoperative for safety reasons, like the phone dialer and + SMS handler. --> + <string-array translatable="false" name="config_nonBlockableNotificationPackages"> + <item>com.android.dialer</item> + <item>com.android.messaging</item> + </string-array> <!-- An array of packages which can listen for notifications on low ram devices. --> <string-array translatable="false" name="config_allowedManagedServicesOnLowRamDevices" /> @@ -3881,4 +3903,22 @@ The ambient color temperature (in cct) to which we fall back when the ambient brightness drops beneath a certain threshold. --> <item name="config_displayWhiteBalanceLowLightAmbientColorTemperature" format="float" type="dimen">6500.0</item> + + <!-- See DisplayWhiteBalanceController. + A float array containing a list of ambient color temperatures, in Kelvin. This array, + together with config_displayWhiteBalanceDisplayTemperatureValues, is used to generate a + lookup table used in DisplayWhiteBalanceController. This lookup table is used to map + ambient color temperature readings to a target color temperature for the display. + This table is optional. If used, this array must, + 1) Contain at least two entries + 2) Be the same length as config_displayWhiteBalanceDisplayTemperatureValues. --> + <array name="config_displayWhiteBalanceAmbientTemperatureValues"> + </array> + + <!-- See DisplayWhiteBalanceController. + An array containing a list of display color temperatures, in Kelvin. See + config_displayWhiteBalanceAmbientTemperatureValues for additional details. + The same restrictions apply to this array. --> + <array name="config_displayWhiteBalanceDisplayTemperatureValues"> + </array> </resources> diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index bbe3ff995ac3..ce7995a93f7f 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -193,4 +193,7 @@ <!-- A tag used to save the notification action object --> <item type="id" name="notification_action_index_tag" /> + + <!-- A tag used to save the index where the custom view is stored --> + <item type="id" name="notification_custom_view_index_tag" /> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index e6d478aadae0..5e65605a4c65 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2939,6 +2939,8 @@ <public name="zygotePreloadName" /> <public name="useEmbeddedDex" /> <public name="forceUriPermissions" /> + <!-- @hide @SystemApi --> + <public name="allowClearUserDataOnFailedRestore"/> </public-group> <public-group type="drawable" first-id="0x010800b4"> @@ -2971,6 +2973,18 @@ <public name="config_feedbackIntentExtraKey" /> <!-- @hide @SystemApi --> <public name="config_feedbackIntentNameKey" /> + <!-- @hide @SystemApi @TestApi --> + <public name="config_defaultAssistant" /> + <!-- @hide @SystemApi --> + <public name="config_defaultBrowser" /> + <!-- @hide @SystemApi @TestApi --> + <public name="config_defaultDialer" /> + <!-- @hide @SystemApi --> + <public name="config_defaultSms" /> + <!-- @hide @SystemApi --> + <public name="config_defaultMusic" /> + <!-- @hide @SystemApi --> + <public name="config_defaultGallery" /> </public-group> <public-group type="bool" first-id="0x01110000"> @@ -2990,11 +3004,6 @@ <public name="system_notification_accent_color" /> </public-group> - <public-group type="array" first-id="0x01070006"> - <!-- @hide @TestApi @SystemApi --> - <public name="config_defaultRoleHolders" /> - </public-group> - <!-- =============================================================== DO NOT ADD UN-GROUPED ITEMS HERE diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index fadb28f05ef7..62e79da1ff6a 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1406,9 +1406,9 @@ re-enables the keylock when the call is finished.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] --> - <string name="permlab_getAndRequestScreenLockComplexity">get and request screen lock complexity</string> + <string name="permlab_requestScreenLockComplexity">request screen lock complexity</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] --> - <string name="permdesc_getAndRequestScreenLockComplexity">Allows the app to learn the screen + <string name="permdesc_requestScreenLockComplexity">Allows the app to learn the screen lock complexity level (high, medium, low or none), which indicates the possible range of length and type of the screen lock. The app can also suggest to users that they update the screen lock to a certain level but users can freely ignore and navigate away. Note that the @@ -1471,6 +1471,8 @@ <string name="biometric_not_recognized">Not recognized</string> <!-- Message shown when biometric authentication has been canceled [CHAR LIMIT=50] --> <string name="biometric_error_canceled">Authentication canceled</string> + <!-- Message returned to applications if BiometricPrompt setAllowDeviceCredentials is enabled but no pin, pattern, or password is set. [CHAR LIMIT=NONE] --> + <string name="biometric_error_device_not_secured">No pin, pattern, or password set</string> <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized --> <string name="fingerprint_acquired_partial">Partial fingerprint detected. Please try again.</string> @@ -1512,7 +1514,7 @@ <!-- Generic error message shown when the user has no enrolled fingerprints --> <string name="fingerprint_error_no_fingerprints">No fingerprints enrolled.</string> <!-- Generic error message shown when the app requests fingerprint authentication on a device without a sensor --> - <string name="fingerprint_error_hw_not_present">This device does not have a fingerprint sensor</string> + <string name="fingerprint_error_hw_not_present">This device does not have a fingerprint sensor.</string> <!-- Template to be used to name enrolled fingerprints by default. --> <string name="fingerprint_name_template">Finger <xliff:g id="fingerId" example="1">%d</xliff:g></string> @@ -1555,8 +1557,22 @@ <string name="face_acquired_poor_gaze">Please look at the sensor.</string> <!-- Message shown during face acquisition when the user is not detected [CHAR LIMIT=50] --> <string name="face_acquired_not_detected">No face detected.</string> - <!-- Message shown during face acquisition when the face is not kept steady infront of device [CHAR LIMIT=50] --> - <string name="face_acquired_not_steady">Keep face steady infront of device.</string> + <!-- Message shown during face acquisition when the device is not steady [CHAR LIMIT=50] --> + <string name="face_acquired_too_much_motion">Too much motion.</string> + <!-- Message shown during face acquisition when the sensor needs to be recalibrated [CHAR LIMIT=50] --> + <string name="face_acquired_recalibrate">Please re-enroll your face.</string> + <!-- Message shown during face enrollment when a different person's face is detected [CHAR LIMIT=50] --> + <string name="face_acquired_too_different">Different face detected.</string> + <!-- Message shown during face enrollment when the face is too similar to a previous acquisition [CHAR LIMIT=50] --> + <string name="face_acquired_too_similar">Too similar, please change your pose.</string> + <!-- Message shown during acqusition when the user's face is turned too far left or right [CHAR LIMIT=50] --> + <string name="face_acquired_pan_too_extreme">Please look more directly at the camera.</string> + <!-- Message shown during acqusition when the user's face is tilted too high or too low [CHAR LIMIT=50] --> + <string name="face_acquired_tilt_too_extreme">Please look more directly at the camera.</string> + <!-- Message shown during acquisiton when the user's face is tilted too far left or right [CHAR LIMIT=50] --> + <string name="face_acquired_roll_too_extreme">Please straighten your head vertically.</string> + <!-- Message shown during acquisition when the user's face is obscured [CHAR LIMIT=50] --> + <string name="face_acquired_obscured">Please uncover your face.</string> <!-- Array containing custom messages shown during face acquisition from vendor. Vendor is expected to add and translate these strings --> <string-array name="face_acquired_vendor"> </string-array> @@ -1580,7 +1596,7 @@ <!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=50] --> <string name="face_error_not_enrolled">No face enrolled.</string> <!-- Generic error message shown when the app requests face authentication on a device without a sensor. [CHAR LIMIT=60] --> - <string name="face_error_hw_not_present">This device does not have a face authentication sensor</string> + <string name="face_error_hw_not_present">This device does not have a face authentication sensor.</string> <!-- Template to be used to name enrolled faces by default. [CHAR LIMIT=10] --> <string name="face_name_template">Face <xliff:g id="faceId" example="1">%d</xliff:g></string> diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml index 0dc54e091f9d..93068ea975bd 100644 --- a/core/res/res/values/styles_device_defaults.xml +++ b/core/res/res/values/styles_device_defaults.xml @@ -41,9 +41,7 @@ easier. <item name="textAppearance">?attr/textAppearanceButton</item> <item name="textColor">@color/btn_colored_text_material</item> </style> - <style name="Widget.DeviceDefault.TextView" parent="Widget.Material.TextView"> - <item name="fontFamily">@string/config_bodyFontFamily</item> - </style> + <style name="Widget.DeviceDefault.TextView" parent="Widget.Material.TextView" /> <style name="Widget.DeviceDefault.CheckedTextView" parent="Widget.Material.CheckedTextView"/> <style name="Widget.DeviceDefault.AutoCompleteTextView" parent="Widget.Material.AutoCompleteTextView"/> <style name="Widget.DeviceDefault.CompoundButton.CheckBox" parent="Widget.Material.CompoundButton.CheckBox"/> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 1da91494306d..5a7d71f17139 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1034,6 +1034,7 @@ <java-symbol type="string" name="sipAddressTypeOther" /> <java-symbol type="string" name="sipAddressTypeWork" /> <java-symbol type="string" name="default_sms_application" /> + <java-symbol type="string" name="default_browser" /> <java-symbol type="string" name="sms_control_message" /> <java-symbol type="string" name="sms_control_title" /> <java-symbol type="string" name="sms_control_no" /> @@ -2472,6 +2473,7 @@ <java-symbol type="string" name="biometric_error_user_canceled" /> <java-symbol type="string" name="biometric_not_recognized" /> <java-symbol type="string" name="biometric_error_canceled" /> + <java-symbol type="string" name="biometric_error_device_not_secured" /> <!-- Fingerprint messages --> <java-symbol type="string" name="fingerprint_error_unable_to_process" /> @@ -2521,6 +2523,14 @@ <java-symbol type="string" name="face_acquired_too_left" /> <java-symbol type="string" name="face_acquired_poor_gaze" /> <java-symbol type="string" name="face_acquired_not_detected" /> + <java-symbol type="string" name="face_acquired_too_much_motion" /> + <java-symbol type="string" name="face_acquired_recalibrate" /> + <java-symbol type="string" name="face_acquired_too_different" /> + <java-symbol type="string" name="face_acquired_too_similar" /> + <java-symbol type="string" name="face_acquired_pan_too_extreme" /> + <java-symbol type="string" name="face_acquired_tilt_too_extreme" /> + <java-symbol type="string" name="face_acquired_roll_too_extreme" /> + <java-symbol type="string" name="face_acquired_obscured" /> <java-symbol type="array" name="face_acquired_vendor" /> <java-symbol type="string" name="face_name_template" /> <java-symbol type="string" name="face_authenticated_no_confirmation_required" /> @@ -3585,6 +3595,7 @@ <java-symbol type="bool" name="config_useSmsAppService" /> <java-symbol type="id" name="transition_overlay_view_tag" /> + <java-symbol type="id" name="notification_custom_view_index_tag" /> <java-symbol type="dimen" name="rounded_corner_radius" /> <java-symbol type="dimen" name="rounded_corner_radius_top" /> @@ -3632,4 +3643,7 @@ <java-symbol type="array" name="config_displayWhiteBalanceDecreaseThresholds" /> <java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientBrightnessThreshold" /> <java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientColorTemperature" /> + <java-symbol type="array" name="config_displayWhiteBalanceAmbientTemperatureValues" /> + <java-symbol type="array" name="config_displayWhiteBalanceDisplayTemperatureValues" /> + <java-symbol type="drawable" name="ic_action_open" /> </resources> diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java index 300394d426e4..aa0e0cdae265 100644 --- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java +++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java @@ -162,14 +162,13 @@ public class PackageParserTest { } private void verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename, - boolean isPlatformReleased, int expectedTargetSdk, boolean forceCurrentDev) { + boolean isPlatformReleased, int expectedTargetSdk) { final String[] outError = new String[1]; final int result = PackageParser.computeTargetSdkVersion( targetSdkVersion, targetSdkCodename, isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE, - outError, - forceCurrentDev); + outError); assertEquals(result, expectedTargetSdk); @@ -185,28 +184,23 @@ public class PackageParserTest { // Do allow older release targetSdkVersion on pre-release platform. // APP: Released API 10 // DEV: Pre-release API 20 - verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, false, OLDER_VERSION, - false /* forceCurrentDev */); + verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, false, OLDER_VERSION); // Do allow same release targetSdkVersion on pre-release platform. // APP: Released API 20 // DEV: Pre-release API 20 - verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, false, PLATFORM_VERSION, - false /* forceCurrentDev */); + verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, false, PLATFORM_VERSION); // Do allow newer release targetSdkVersion on pre-release platform. // APP: Released API 30 // DEV: Pre-release API 20 - verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, false, NEWER_VERSION, - false /* forceCurrentDev */); + verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, false, NEWER_VERSION); // Don't allow older pre-release targetSdkVersion on pre-release platform. // APP: Pre-release API 10 // DEV: Pre-release API 20 - verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1, - false /* forceCurrentDev */); - verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, -1, - false /* forceCurrentDev */); + verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1); + verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, -1); // Do allow same pre-release targetSdkVersion on pre-release platform, @@ -214,27 +208,16 @@ public class PackageParserTest { // APP: Pre-release API 20 // DEV: Pre-release API 20 verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false, - Build.VERSION_CODES.CUR_DEVELOPMENT, false /* forceCurrentDev */); + Build.VERSION_CODES.CUR_DEVELOPMENT); verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, false, - Build.VERSION_CODES.CUR_DEVELOPMENT, false /* forceCurrentDev */); + Build.VERSION_CODES.CUR_DEVELOPMENT); // Don't allow newer pre-release targetSdkVersion on pre-release platform. // APP: Pre-release API 30 // DEV: Pre-release API 20 - verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1, - false /* forceCurrentDev */); - verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, -1, - false /* forceCurrentDev */); - - - // Force newer pre-release targetSdkVersion to current pre-release platform. - // APP: Pre-release API 30 - // DEV: Pre-release API 20 - verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, - Build.VERSION_CODES.CUR_DEVELOPMENT, true /* forceCurrentDev */); - verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, - Build.VERSION_CODES.CUR_DEVELOPMENT, true /* forceCurrentDev */); + verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1); + verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, -1); } @Test @@ -242,45 +225,36 @@ public class PackageParserTest { // Do allow older release targetSdkVersion on released platform. // APP: Released API 10 // DEV: Released API 20 - verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, true, OLDER_VERSION, - false /* forceCurrentDev */); + verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, true, OLDER_VERSION); // Do allow same release targetSdkVersion on released platform. // APP: Released API 20 // DEV: Released API 20 - verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, true, PLATFORM_VERSION, - false /* forceCurrentDev */); + verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, true, PLATFORM_VERSION); // Do allow newer release targetSdkVersion on released platform. // APP: Released API 30 // DEV: Released API 20 - verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, true, NEWER_VERSION, - false /* forceCurrentDev */); + verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, true, NEWER_VERSION); // Don't allow older pre-release targetSdkVersion on released platform. // APP: Pre-release API 10 // DEV: Released API 20 - verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1, - false /* forceCurrentDev */); - verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, -1, - false /* forceCurrentDev */); + verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1); + verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, -1); // Don't allow same pre-release targetSdkVersion on released platform. // APP: Pre-release API 20 // DEV: Released API 20 - verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1, - false /* forceCurrentDev */); - verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, -1, - false /* forceCurrentDev */); + verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1); + verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, -1); // Don't allow newer pre-release targetSdkVersion on released platform. // APP: Pre-release API 30 // DEV: Released API 20 - verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1, - false /* forceCurrentDev */); - verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, -1, - false /* forceCurrentDev */); + verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1); + verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, -1); } /** diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index ec57f793f15f..b919553dd85d 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -128,7 +128,6 @@ public class SettingsBackupTest { Settings.Global.AUTOFILL_LOGGING_LEVEL, Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE, Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, - Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS, Settings.Global.AUTOMATIC_POWER_SAVER_MODE, Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED, Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY, @@ -492,6 +491,7 @@ public class SettingsBackupTest { Settings.Global.GAME_DRIVER_ALL_APPS, Settings.Global.GAME_DRIVER_OPT_IN_APPS, Settings.Global.GAME_DRIVER_OPT_OUT_APPS, + Settings.Global.GAME_DRIVER_BLACKLISTS, Settings.Global.GAME_DRIVER_BLACKLIST, Settings.Global.GAME_DRIVER_WHITELIST, Settings.Global.GPU_DEBUG_LAYER_APP, diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java index da81d176de8a..80b1f9cb35ae 100644 --- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java +++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java @@ -19,6 +19,7 @@ package android.view; import static android.view.ImeInsetsSourceConsumer.areEditorsSimilar; import static android.view.InsetsState.TYPE_IME; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -73,7 +74,7 @@ public class ImeInsetsSourceConsumerTest { false, new DisplayCutout( Insets.of(10, 10, 10, 10), rect, rect, rect, rect), - rect, rect); + rect, rect, SOFT_INPUT_ADJUST_RESIZE); mImeConsumer = new ImeInsetsSourceConsumer( new InsetsState(), Transaction::new, mController); }); diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index 6dad6a22f7ea..731d5644504b 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -20,10 +20,16 @@ import static android.view.InsetsState.TYPE_IME; import static android.view.InsetsState.TYPE_NAVIGATION_BAR; import static android.view.InsetsState.TYPE_TOP_BAR; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import android.content.Context; import android.graphics.Insets; @@ -73,7 +79,7 @@ public class InsetsControllerTest { false, new DisplayCutout( Insets.of(10, 10, 10, 10), rect, rect, rect, rect), - rect, rect); + rect, rect, SOFT_INPUT_ADJUST_RESIZE); }); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); } @@ -95,6 +101,17 @@ public class InsetsControllerTest { } @Test + public void testFrameDoesntMatchDisplay() { + mController.onFrameChanged(new Rect(0, 0, 100, 100)); + mController.getState().setDisplayFrame(new Rect(0, 0, 200, 200)); + WindowInsetsAnimationControlListener controlListener = + mock(WindowInsetsAnimationControlListener.class); + mController.controlWindowInsetsAnimation(0, controlListener); + verify(controlListener).onCancelled(); + verify(controlListener, never()).onReady(any(), anyInt()); + } + + @Test public void testAnimationEndState() { InsetsSourceControl[] controls = prepareControls(); InsetsSourceControl navBar = controls[0]; diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java index 03af67df13d0..bd036b01c0cf 100644 --- a/core/tests/coretests/src/android/view/InsetsStateTest.java +++ b/core/tests/coretests/src/android/view/InsetsStateTest.java @@ -25,6 +25,8 @@ import static android.view.InsetsState.TYPE_SIDE_BAR_2; import static android.view.InsetsState.TYPE_SIDE_BAR_3; import static android.view.InsetsState.TYPE_TOP_BAR; +import static android.view.WindowInsets.Type.ime; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -37,6 +39,7 @@ import android.os.Parcel; import android.platform.test.annotations.Presubmit; import android.util.SparseIntArray; import android.view.WindowInsets.Type; +import android.view.test.InsetsModeSession; import androidx.test.filters.FlakyTest; import androidx.test.runner.AndroidJUnit4; @@ -53,49 +56,70 @@ public class InsetsStateTest { private InsetsState mState2 = new InsetsState(); @Test - public void testCalculateInsets() { - mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); - mState.getSource(TYPE_TOP_BAR).setVisible(true); - mState.getSource(TYPE_IME).setFrame(new Rect(0, 200, 100, 300)); - mState.getSource(TYPE_IME).setVisible(true); - SparseIntArray typeSideMap = new SparseIntArray(); - WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false, - DisplayCutout.NO_CUTOUT, null, null, typeSideMap); - assertEquals(Insets.of(0, 100, 0, 100), insets.getSystemWindowInsets()); - assertEquals(Insets.of(0, 100, 0, 100), insets.getInsets(Type.all())); - assertEquals(INSET_SIDE_TOP, typeSideMap.get(TYPE_TOP_BAR)); - assertEquals(INSET_SIDE_BOTTOM, typeSideMap.get(TYPE_IME)); - assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.topBar())); - assertEquals(Insets.of(0, 0, 0, 100), insets.getInsets(Type.ime())); + public void testCalculateInsets() throws Exception { + try (final InsetsModeSession session = + new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) { + mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); + mState.getSource(TYPE_TOP_BAR).setVisible(true); + mState.getSource(TYPE_IME).setFrame(new Rect(0, 200, 100, 300)); + mState.getSource(TYPE_IME).setVisible(true); + SparseIntArray typeSideMap = new SparseIntArray(); + WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false, + DisplayCutout.NO_CUTOUT, null, null, SOFT_INPUT_ADJUST_RESIZE, typeSideMap); + assertEquals(Insets.of(0, 100, 0, 100), insets.getSystemWindowInsets()); + assertEquals(Insets.of(0, 100, 0, 100), insets.getInsets(Type.all())); + assertEquals(INSET_SIDE_TOP, typeSideMap.get(TYPE_TOP_BAR)); + assertEquals(INSET_SIDE_BOTTOM, typeSideMap.get(TYPE_IME)); + assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.topBar())); + assertEquals(Insets.of(0, 0, 0, 100), insets.getInsets(Type.ime())); + } } @Test - public void testCalculateInsets_imeAndNav() { - mState.getSource(TYPE_NAVIGATION_BAR).setFrame(new Rect(0, 200, 100, 300)); - mState.getSource(TYPE_NAVIGATION_BAR).setVisible(true); - mState.getSource(TYPE_IME).setFrame(new Rect(0, 100, 100, 300)); - mState.getSource(TYPE_IME).setVisible(true); - WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false, - DisplayCutout.NO_CUTOUT, null, null, null); - assertEquals(100, insets.getStableInsetBottom()); - assertEquals(Insets.of(0, 0, 0, 100), insets.getMaxInsets(Type.all())); - assertEquals(Insets.of(0, 0, 0, 200), insets.getSystemWindowInsets()); - assertEquals(Insets.of(0, 0, 0, 200), insets.getInsets(Type.all())); - assertEquals(Insets.of(0, 0, 0, 100), insets.getInsets(Type.sideBars())); - assertEquals(Insets.of(0, 0, 0, 200), insets.getInsets(Type.ime())); + public void testCalculateInsets_imeAndNav() throws Exception{ + try (final InsetsModeSession session = + new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) { + mState.getSource(TYPE_NAVIGATION_BAR).setFrame(new Rect(0, 200, 100, 300)); + mState.getSource(TYPE_NAVIGATION_BAR).setVisible(true); + mState.getSource(TYPE_IME).setFrame(new Rect(0, 100, 100, 300)); + mState.getSource(TYPE_IME).setVisible(true); + WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false, + DisplayCutout.NO_CUTOUT, null, null, SOFT_INPUT_ADJUST_RESIZE, null); + assertEquals(100, insets.getStableInsetBottom()); + assertEquals(Insets.of(0, 0, 0, 100), insets.getMaxInsets(Type.systemBars())); + assertEquals(Insets.of(0, 0, 0, 200), insets.getSystemWindowInsets()); + assertEquals(Insets.of(0, 0, 0, 200), insets.getInsets(Type.all())); + assertEquals(Insets.of(0, 0, 0, 100), insets.getInsets(Type.sideBars())); + assertEquals(Insets.of(0, 0, 0, 200), insets.getInsets(Type.ime())); + } } @Test - public void testCalculateInsets_navRightStatusTop() { + public void testCalculateInsets_navRightStatusTop() throws Exception { + try (final InsetsModeSession session = + new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) { + mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); + mState.getSource(TYPE_TOP_BAR).setVisible(true); + mState.getSource(TYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300)); + mState.getSource(TYPE_NAVIGATION_BAR).setVisible(true); + WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false, + DisplayCutout.NO_CUTOUT, null, null, 0, null); + assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets()); + assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.topBar())); + assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.sideBars())); + } + } + + @Test + public void testCalculateInsets_imeIgnoredWithoutAdjustResize() { mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); mState.getSource(TYPE_TOP_BAR).setVisible(true); - mState.getSource(TYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300)); - mState.getSource(TYPE_NAVIGATION_BAR).setVisible(true); + mState.getSource(TYPE_IME).setFrame(new Rect(0, 200, 100, 300)); + mState.getSource(TYPE_IME).setVisible(true); WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false, - DisplayCutout.NO_CUTOUT, null, null, null); - assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets()); - assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.topBar())); - assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.sideBars())); + DisplayCutout.NO_CUTOUT, null, null, 0, null); + assertEquals(0, insets.getSystemWindowInsetBottom()); + assertTrue(insets.isVisible(ime())); } @Test @@ -106,7 +130,7 @@ public class InsetsStateTest { mState.getSource(TYPE_IME).setVisible(true); mState.removeSource(TYPE_IME); WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false, - DisplayCutout.NO_CUTOUT, null, null, null); + DisplayCutout.NO_CUTOUT, null, null, SOFT_INPUT_ADJUST_RESIZE, null); assertEquals(0, insets.getSystemWindowInsetBottom()); } @@ -114,14 +138,14 @@ public class InsetsStateTest { public void testEquals_differentRect() { mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); mState2.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 10, 10)); - assertNotEquals(mState, mState2); + assertNotEqualsAndHashCode(); } @Test public void testEquals_differentSource() { mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); mState2.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100)); - assertNotEquals(mState, mState2); + assertNotEqualsAndHashCode(); } @Test @@ -130,7 +154,7 @@ public class InsetsStateTest { mState.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100)); mState2.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100)); mState2.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); - assertEquals(mState, mState2); + assertEqualsAndHashCode(); } @Test @@ -138,7 +162,21 @@ public class InsetsStateTest { mState.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100)); mState.getSource(TYPE_IME).setVisible(true); mState2.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100)); - assertNotEquals(mState, mState2); + assertNotEqualsAndHashCode(); + } + + @Test + public void testEquals_differentFrame() { + mState.setDisplayFrame(new Rect(0, 1, 2, 3)); + mState.setDisplayFrame(new Rect(4, 5, 6, 7)); + assertNotEqualsAndHashCode(); + } + + @Test + public void testEquals_sameFrame() { + mState.setDisplayFrame(new Rect(0, 1, 2, 3)); + mState2.setDisplayFrame(new Rect(0, 1, 2, 3)); + assertEqualsAndHashCode(); } @Test @@ -148,6 +186,7 @@ public class InsetsStateTest { mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); Parcel p = Parcel.obtain(); mState.writeToParcel(p, 0 /* flags */); + p.setDataPosition(0); mState2.readFromParcel(p); p.recycle(); assertEquals(mState, mState2); @@ -161,4 +200,14 @@ public class InsetsStateTest { assertTrue(InsetsState.getDefaultVisibility(TYPE_SIDE_BAR_3)); assertFalse(InsetsState.getDefaultVisibility(TYPE_IME)); } + + private void assertEqualsAndHashCode() { + assertEquals(mState, mState2); + assertEquals(mState.hashCode(), mState2.hashCode()); + } + + private void assertNotEqualsAndHashCode() { + assertNotEquals(mState, mState2); + assertNotEquals(mState.hashCode(), mState2.hashCode()); + } } diff --git a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java index 213cd405e903..93315f11d242 100644 --- a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java @@ -20,11 +20,12 @@ import static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.graphics.Matrix; -import android.support.test.InstrumentationRegistry; import android.view.View; import android.view.ViewStructure.HtmlInfo; import android.view.contentcapture.ViewNode.ViewStructureImpl; +import androidx.test.InstrumentationRegistry; + import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; diff --git a/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java index 08ad62ab843d..d9dac314fc7c 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java @@ -41,6 +41,7 @@ public class TemplateClassificationIntentFactoryTest { private static final String TEXT = "text"; private static final String TITLE = "Map"; + private static final String DESCRIPTION = "Opens in Maps"; private static final String ACTION = Intent.ACTION_VIEW; @Mock @@ -57,19 +58,6 @@ public class TemplateClassificationIntentFactoryTest { @Test public void create_foreignText() { - RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate( - TITLE, - null, - ACTION, - null, - null, - null, - null, - null, - null, - null - ); - AnnotatorModel.ClassificationResult classificationResult = new AnnotatorModel.ClassificationResult( TextClassifier.TYPE_ADDRESS, @@ -81,7 +69,7 @@ public class TemplateClassificationIntentFactoryTest { null, null, null, - new RemoteActionTemplate[]{remoteActionTemplate}); + createRemoteActionTemplates()); List<TextClassifierImpl.LabeledIntent> intents = mTemplateClassificationIntentFactory.create( @@ -106,19 +94,6 @@ public class TemplateClassificationIntentFactoryTest { @Test public void create_notForeignText() { - RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate( - TITLE, - null, - ACTION, - null, - null, - null, - null, - null, - null, - null - ); - AnnotatorModel.ClassificationResult classificationResult = new AnnotatorModel.ClassificationResult( TextClassifier.TYPE_ADDRESS, @@ -130,7 +105,7 @@ public class TemplateClassificationIntentFactoryTest { null, null, null, - new RemoteActionTemplate[]{remoteActionTemplate}); + createRemoteActionTemplates()); List<TextClassifierImpl.LabeledIntent> intents = mTemplateClassificationIntentFactory.create( @@ -147,4 +122,21 @@ public class TemplateClassificationIntentFactoryTest { assertThat(intent.getAction()).isEqualTo(ACTION); assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue(); } + + private static RemoteActionTemplate[] createRemoteActionTemplates() { + return new RemoteActionTemplate[]{ + new RemoteActionTemplate( + TITLE, + DESCRIPTION, + ACTION, + null, + null, + null, + null, + null, + null, + null + ) + }; + } } diff --git a/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java index 0d364a329de4..a1158a7cbb6c 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java @@ -81,7 +81,6 @@ public class TemplateIntentFactoryTest { REQUEST_CODE ); - List<TextClassifierImpl.LabeledIntent> intents = mTemplateIntentFactory.create(new RemoteActionTemplate[]{remoteActionTemplate}); @@ -97,23 +96,22 @@ public class TemplateIntentFactoryTest { assertThat(intent.getFlags()).isEqualTo(FLAG); assertThat(intent.getCategories()).containsExactly((Object[]) CATEGORY); assertThat(intent.getPackage()).isNull(); - assertThat( - intent.getStringExtra(KEY_ONE)).isEqualTo(VALUE_ONE); + assertThat(intent.getStringExtra(KEY_ONE)).isEqualTo(VALUE_ONE); assertThat(intent.getIntExtra(KEY_TWO, 0)).isEqualTo(VALUE_TWO); assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue(); } @Test - public void create_packageIsNotNull() { + public void normalizesScheme() { RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate( TITLE, DESCRIPTION, ACTION, - DATA, + "HTTp://www.android.com", TYPE, FLAG, CATEGORY, - PACKAGE_NAME, + /* packageName */ null, NAMED_VARIANTS, REQUEST_CODE ); @@ -121,15 +119,16 @@ public class TemplateIntentFactoryTest { List<TextClassifierImpl.LabeledIntent> intents = mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate}); - assertThat(intents).hasSize(0); + String data = intents.get(0).getIntent().getData().toString(); + assertThat(data).isEqualTo("http://www.android.com"); } @Test public void create_minimal() { RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate( - null, - null, - null, + TITLE, + DESCRIPTION, + ACTION, null, null, null, @@ -142,15 +141,14 @@ public class TemplateIntentFactoryTest { List<TextClassifierImpl.LabeledIntent> intents = mTemplateIntentFactory.create(new RemoteActionTemplate[]{remoteActionTemplate}); - assertThat(intents).hasSize(1); TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0); - assertThat(labeledIntent.getTitle()).isNull(); - assertThat(labeledIntent.getDescription()).isNull(); + assertThat(labeledIntent.getTitle()).isEqualTo(TITLE); + assertThat(labeledIntent.getDescription()).isEqualTo(DESCRIPTION); assertThat(labeledIntent.getRequestCode()).isEqualTo( TextClassifierImpl.LabeledIntent.DEFAULT_REQUEST_CODE); Intent intent = labeledIntent.getIntent(); - assertThat(intent.getAction()).isNull(); + assertThat(intent.getAction()).isEqualTo(ACTION); assertThat(intent.getData()).isNull(); assertThat(intent.getType()).isNull(); assertThat(intent.getFlags()).isEqualTo(0); @@ -158,4 +156,98 @@ public class TemplateIntentFactoryTest { assertThat(intent.getPackage()).isNull(); assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue(); } + + @Test + public void invalidTemplate_nullTemplate() { + RemoteActionTemplate remoteActionTemplate = null; + + List<TextClassifierImpl.LabeledIntent> intents = + mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate}); + + assertThat(intents).isEmpty(); + } + + @Test + public void invalidTemplate_nonEmptyPackageName() { + RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate( + TITLE, + DESCRIPTION, + ACTION, + DATA, + TYPE, + FLAG, + CATEGORY, + PACKAGE_NAME, + NAMED_VARIANTS, + REQUEST_CODE + ); + + List<TextClassifierImpl.LabeledIntent> intents = + mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate}); + + assertThat(intents).isEmpty(); + } + + @Test + public void invalidTemplate_emptyTitle() { + RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate( + null, + DESCRIPTION, + ACTION, + null, + null, + null, + null, + null, + null, + null + ); + + List<TextClassifierImpl.LabeledIntent> intents = + mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate}); + + assertThat(intents).isEmpty(); + } + + @Test + public void invalidTemplate_emptyDescription() { + RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate( + TITLE, + null, + ACTION, + null, + null, + null, + null, + null, + null, + null + ); + + List<TextClassifierImpl.LabeledIntent> intents = + mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate}); + + assertThat(intents).isEmpty(); + } + + @Test + public void invalidTemplate_emptyIntentAction() { + RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate( + TITLE, + DESCRIPTION, + null, + null, + null, + null, + null, + null, + null, + null + ); + + List<TextClassifierImpl.LabeledIntent> intents = + mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate}); + + assertThat(intents).isEmpty(); + } } diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java index 32bafec4081a..fe2a6608c781 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java @@ -195,11 +195,13 @@ public class TextClassificationConstantsTest { assertWithMessage("in_app_conversation_action_types_default") .that(constants.getInAppConversationActionTypes()) .containsExactly("text_reply", "create_reminder", "call_phone", "open_url", - "send_email", "send_sms", "track_flight", "view_calendar", "view_map"); + "send_email", "send_sms", "track_flight", "view_calendar", "view_map", + "add_contact"); assertWithMessage("notification_conversation_action_types_default") .that(constants.getNotificationConversationActionTypes()) .containsExactly("text_reply", "create_reminder", "call_phone", "open_url", - "send_email", "send_sms", "track_flight", "view_calendar", "view_map"); + "send_email", "send_sms", "track_flight", "view_calendar", "view_map", + "add_contact"); assertWithMessage("lang_id_threshold_override") .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(-1f); } diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java index 582be9d51731..d2d03e565522 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java @@ -176,6 +176,7 @@ public class TextClassifierTest { TextClassification classification = mClassifier.classifyText(request); assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL)); + assertThat(classification, containsIntentWithAction(Intent.ACTION_VIEW)); } @Test @@ -207,6 +208,7 @@ public class TextClassifierTest { TextClassification classification = mClassifier.classifyText(request); assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL)); + assertThat(classification, containsIntentWithAction(Intent.ACTION_VIEW)); } @Test @@ -380,7 +382,6 @@ public class TextClassifierTest { assertThat(textLanguage, isTextLanguage("ja")); } - /* DISABLED: b/122467291 @Test public void testSuggestConversationActions_textReplyOnly_maxThree() { if (isTextClassifierDisabled()) return; @@ -408,7 +409,7 @@ public class TextClassifierTest { assertThat(conversationAction, isConversationAction(ConversationAction.TYPE_TEXT_REPLY)); } - }*/ + } @Test public void testSuggestConversationActions_textReplyOnly_noMax() { @@ -517,6 +518,24 @@ public class TextClassifierTest { }; } + private static Matcher<TextClassification> containsIntentWithAction(final String action) { + return new BaseMatcher<TextClassification>() { + @Override + public boolean matches(Object o) { + if (o instanceof TextClassification) { + TextClassification result = (TextClassification) o; + return ExtrasUtils.findAction(result, action) != null; + } + return false; + } + + @Override + public void describeTo(Description description) { + description.appendText("intent action=").appendValue(action); + } + }; + } + private static Matcher<TextLanguage> isTextLanguage(final String languageTag) { return new BaseMatcher<TextLanguage>() { @Override diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java index 73af56743b5f..1980a604fdd2 100644 --- a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java @@ -91,8 +91,8 @@ public class TextClassifierEventTronLoggerTest { .isEqualTo(ConversationAction.TYPE_CALL_PHONE); assertThat((float) logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_SCORE)) .isWithin(0.00001f).of(0.5f); - assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME)) - .isEqualTo(EVENT_TIME); + // Never write event time. + assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME)).isNull(); assertThat(logMaker.getPackageName()).isEqualTo(PACKAGE_NAME); assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_TYPE)) .isEqualTo(WIDGET_TYPE); diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java index 1d35143e3fab..e375af3f7b0e 100644 --- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java @@ -658,6 +658,67 @@ public class BinderCallsStatsTest { assertTrue(debugEntry3.latencyMicros >= 0); } + @Test + public void testTrackScreenInteractiveDisabled() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setTrackScreenInteractive(false); + Binder binder = new Binder(); + + mDeviceState.setScreenInteractive(false); + CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); + bcs.time += 10; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); + + mDeviceState.setScreenInteractive(true); + callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); + bcs.time += 1000; // shoud be ignored. + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); + + SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); + assertEquals(1, uidEntries.size()); + BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); + Assert.assertNotNull(uidEntry); + assertEquals(2, uidEntry.callCount); + + List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); + assertEquals(1, callStatsList.size()); + BinderCallsStats.CallStat callStats = callStatsList.get(0); + assertEquals(false, callStats.screenInteractive); + assertEquals(2, callStats.callCount); + assertEquals(2, callStats.recordedCallCount); + } + + @Test + public void testTrackCallingUidDisabled() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setTrackDirectCallerUid(false); + Binder binder = new Binder(); + + bcs.setCallingUid(1); + CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); + bcs.time += 10; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); + + bcs.setCallingUid(2); + callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); + bcs.time += 1000; // shoud be ignored. + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); + + SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); + assertEquals(1, uidEntries.size()); + BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); + Assert.assertNotNull(uidEntry); + assertEquals(2, uidEntry.callCount); + + List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); + assertEquals(1, callStatsList.size()); + BinderCallsStats.CallStat callStats = callStatsList.get(0); + assertEquals(-1, callStats.callingUid); + assertEquals(2, callStats.callCount); + assertEquals(2, callStats.recordedCallCount); + } + + class TestBinderCallsStats extends BinderCallsStats { public int callingUid = CALLING_UID; public long time = 1234; @@ -682,6 +743,8 @@ public class BinderCallsStatsTest { }); setSamplingInterval(1); setAddDebugEntries(false); + setTrackScreenInteractive(true); + setTrackDirectCallerUid(true); if (deviceState != null) { setDeviceState(deviceState.getReadonlyClient()); } @@ -701,6 +764,10 @@ public class BinderCallsStatsTest { protected int getCallingUid() { return callingUid; } + + protected void setCallingUid(int uid) { + callingUid = uid; + } } } diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java index 79b847754311..3edf5f87258b 100644 --- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java @@ -476,6 +476,33 @@ public final class LooperStatsTest { assertThat(debugEntry3.totalLatencyMicros).isAtLeast(0L); } + @Test + public void testScreenStateTrackingDisabled() { + TestableLooperStats looperStats = new TestableLooperStats(1, 100); + looperStats.setTrackScreenInteractive(false); + + Message message = mHandlerFirst.obtainMessage(1000); + message.workSourceUid = 1000; + message.when = looperStats.getSystemUptimeMillis(); + + looperStats.tickUptime(30); + mDeviceState.setScreenInteractive(false); + Object token = looperStats.messageDispatchStarting(); + looperStats.messageDispatched(token, message); + + looperStats.tickUptime(30); + mDeviceState.setScreenInteractive(true); + token = looperStats.messageDispatchStarting(); + looperStats.messageDispatched(token, message); + + List<LooperStats.ExportedEntry> entries = looperStats.getEntries(); + assertThat(entries).hasSize(1); + LooperStats.ExportedEntry entry = entries.get(0); + assertThat(entry.isInteractive).isEqualTo(false); + assertThat(entry.messageCount).isEqualTo(2); + assertThat(entry.recordedMessageCount).isEqualTo(2); + } + private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) { try { r.run(); @@ -501,6 +528,7 @@ public final class LooperStatsTest { super(samplingInterval, sizeCap); mSamplingInterval = samplingInterval; setAddDebugEntries(false); + setTrackScreenInteractive(true); if (deviceState != null) { setDeviceState(deviceState.getReadonlyClient()); } diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 6770ae19ce3d..738221340aba 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -209,21 +209,14 @@ applications that come with the platform <privapp-permissions package="com.android.mainline.networkstack"> <permission name="android.permission.ACCESS_NETWORK_CONDITIONS"/> - <permission name="android.permission.CHANGE_BACKGROUND_DATA_SETTING"/> <permission name="android.permission.CONNECTIVITY_INTERNAL"/> <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/> <permission name="android.permission.CONTROL_VPN"/> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.LOCAL_MAC_ADDRESS"/> - <permission name="android.permission.MANAGE_IPSEC_TUNNELS"/> - <permission name="android.permission.MANAGE_NETWORK_POLICY"/> <permission name="android.permission.MANAGE_SUBSCRIPTION_PLANS"/> <permission name="android.permission.MANAGE_USB"/> - <permission name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"/> - <permission name="android.permission.NETWORK_SETTINGS"/> - <permission name="android.permission.NETWORK_STACK" /> - <permission name="android.permission.NET_TUNNELING"/> <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD"/> - <permission name="android.permission.PEERS_MAC_ADDRESS"/> <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/> <permission name="android.permission.READ_PRECISE_PHONE_STATE"/> <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> @@ -261,6 +254,7 @@ applications that come with the platform <permission name="android.permission.CHANGE_LOWPAN_STATE"/> <permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/> <permission name="android.permission.CLEAR_APP_CACHE"/> + <permission name="android.permission.ACCESS_INSTANT_APPS" /> <permission name="android.permission.CONNECTIVITY_INTERNAL"/> <permission name="android.permission.DELETE_CACHE_FILES"/> <permission name="android.permission.DELETE_PACKAGES"/> diff --git a/core/java/android/os/ParcelFileDescriptor.aidl b/graphics/java/android/graphics/Insets.aidl index c07b98055d5a..e65e72d27f49 100644 --- a/core/java/android/os/ParcelFileDescriptor.aidl +++ b/graphics/java/android/graphics/Insets.aidl @@ -1,20 +1,20 @@ -/* //device/java/android/android/os/ParcelFileDescriptor.aidl +/* //device/java/android/android/graphics/Insets.aidl ** -** Copyright 2007, The Android Open Source Project +** Copyright 2019, 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 +** 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 +** 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 +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and ** limitations under the License. */ -package android.os; +package android.graphics; -parcelable ParcelFileDescriptor cpp_header "binder/ParcelFileDescriptor.h"; +parcelable Insets; diff --git a/graphics/java/android/graphics/Insets.java b/graphics/java/android/graphics/Insets.java index 8258b575d63f..c64c7893564c 100644 --- a/graphics/java/android/graphics/Insets.java +++ b/graphics/java/android/graphics/Insets.java @@ -18,6 +18,8 @@ package android.graphics; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; /** * An Insets instance holds four integer offsets which describe changes to the four @@ -27,7 +29,7 @@ import android.annotation.Nullable; * Insets are immutable so may be treated as values. * */ -public final class Insets { +public final class Insets implements Parcelable { public static final Insets NONE = new Insets(0, 0, 0, 0); public final int left; @@ -73,7 +75,7 @@ public final class Insets { } /** - * Returns a Rect intance with the appropriate values. + * Returns a Rect instance with the appropriate values. * * @hide */ @@ -168,4 +170,29 @@ public final class Insets { ", bottom=" + bottom + '}'; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(left); + out.writeInt(top); + out.writeInt(right); + out.writeInt(bottom); + } + + public static final Parcelable.Creator<Insets> CREATOR = new Parcelable.Creator<Insets>() { + @Override + public Insets createFromParcel(Parcel in) { + return new Insets(in.readInt(), in.readInt(), in.readInt(), in.readInt()); + } + + @Override + public Insets[] newArray(int size) { + return new Insets[size]; + } + }; } diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 7c9529b8ff71..56be05b51d1a 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -175,7 +175,12 @@ public class Typeface { private int[] mSupportedAxes; private static final int[] EMPTY_AXES = {}; - @UnsupportedAppUsage + /** + * Please use font in xml and also your application global theme to change the default Typeface. + * android:textViewStyle and its attribute android:textAppearance can be used in order to change + * typeface and other text related properties. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private static void setDefault(Typeface t) { sDefaultTypeface = t; nativeSetDefault(t.native_instance); diff --git a/graphics/java/android/graphics/drawable/ColorStateListDrawable.java b/graphics/java/android/graphics/drawable/ColorStateListDrawable.java index c0c6a4f424a1..5181d8992be5 100644 --- a/graphics/java/android/graphics/drawable/ColorStateListDrawable.java +++ b/graphics/java/android/graphics/drawable/ColorStateListDrawable.java @@ -157,28 +157,22 @@ public class ColorStateListDrawable extends Drawable implements Drawable.Callbac @Override public void invalidateDrawable(Drawable who) { - final Callback callback = getCallback(); - - if (callback != null) { - callback.invalidateDrawable(who); + if (who == mColorDrawable && getCallback() != null) { + getCallback().invalidateDrawable(this); } } @Override public void scheduleDrawable(Drawable who, Runnable what, long when) { - final Callback callback = getCallback(); - - if (callback != null) { - callback.scheduleDrawable(who, what, when); + if (who == mColorDrawable && getCallback() != null) { + getCallback().scheduleDrawable(this, what, when); } } @Override public void unscheduleDrawable(Drawable who, Runnable what) { - final Callback callback = getCallback(); - - if (callback != null) { - callback.unscheduleDrawable(who, what); + if (who == mColorDrawable && getCallback() != null) { + getCallback().unscheduleDrawable(this, what); } } diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index 991847ad27fa..6ecb62140532 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -44,6 +44,7 @@ import android.graphics.RectF; import android.graphics.Shader; import android.graphics.SweepGradient; import android.graphics.Xfermode; +import android.os.Build; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; @@ -156,12 +157,12 @@ public class GradientDrawable extends Drawable { private static final float DEFAULT_INNER_RADIUS_RATIO = 3.0f; private static final float DEFAULT_THICKNESS_RATIO = 9.0f; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) private GradientState mGradientState; @UnsupportedAppUsage private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051827) private Rect mPadding; @UnsupportedAppUsage private Paint mStrokePaint; // optional, set by the caller @@ -670,7 +671,28 @@ public class GradientDrawable extends Drawable { * @see #setColor(int) */ public void setColors(@ColorInt int[] colors) { + setColors(colors, null); + } + + /** + * Sets the colors and offsets used to draw the gradient. + * <p> + * Each color is specified as an ARGB integer and the array must contain at + * least 2 colors. + * <p> + * <strong>Note</strong>: changing colors will affect all instances of a + * drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing the colors. + * + * @param colors an array containing 2 or more ARGB colors + * @param offsets optional array of floating point parameters representing the positions + * of the colors. Null evenly disperses the colors + * @see #mutate() + * @see #setColors(int[]) + */ + public void setColors(@ColorInt int[] colors, @Nullable float[] offsets) { mGradientState.setGradientColors(colors); + mGradientState.mPositions = offsets; mGradientIsDirty = true; invalidateSelf(); } @@ -849,6 +871,115 @@ public class GradientDrawable extends Drawable { } } + /** + * Inner radius of the ring expressed as a ratio of the ring's width. + * + * @see #getInnerRadiusRatio() + * @attr ref android.R.styleable#GradientDrawable_innerRadiusRatio + */ + public void setInnerRadiusRatio(float innerRadiusRatio) { + mGradientState.mInnerRadiusRatio = innerRadiusRatio; + mPathIsDirty = true; + invalidateSelf(); + } + + /** + * Return the inner radius of the ring expressed as a ratio of the ring's width. + * + * @see #setInnerRadiusRatio(float) + * @attr ref android.R.styleable#GradientDrawable_innerRadiusRatio + */ + public float getInnerRadiusRatio() { + return mGradientState.mInnerRadiusRatio; + } + + /** + * Configure the inner radius of the ring. + * + * @see #getInnerRadius() + * @attr ref android.R.styleable#GradientDrawable_innerRadius + */ + public void setInnerRadius(int innerRadius) { + mGradientState.mInnerRadius = innerRadius; + mPathIsDirty = true; + invalidateSelf(); + } + + /** + * Retrn the inner radius of the ring + * + * @see #setInnerRadius(int) + * @attr ref android.R.styleable#GradientDrawable_innerRadius + */ + public int getInnerRadius() { + return mGradientState.mInnerRadius; + } + + /** + * Configure the thickness of the ring expressed as a ratio of the ring's width. + * + * @see #getThicknessRatio() + * @attr ref android.R.styleable#GradientDrawable_thicknessRatio + */ + public void setThicknessRatio(float thicknessRatio) { + mGradientState.mThicknessRatio = thicknessRatio; + mPathIsDirty = true; + invalidateSelf(); + } + + /** + * Return the thickness ratio of the ring expressed as a ratio of the ring's width. + * + * @see #setThicknessRatio(float) + * @attr ref android.R.styleable#GradientDrawable_thicknessRatio + */ + public float getThicknessRatio() { + return mGradientState.mThicknessRatio; + } + + /** + * Configure the thickness of the ring. + * + * @attr ref android.R.styleable#GradientDrawable_thickness + */ + public void setThickness(int thickness) { + mGradientState.mThickness = thickness; + mPathIsDirty = true; + invalidateSelf(); + } + + /** + * Return the thickness of the ring + * + * @see #setThickness(int) + * @attr ref android.R.styleable#GradientDrawable_thickness + */ + public int getThickness() { + return mGradientState.mThickness; + } + + /** + * Configure the padding of the gradient shape + * @param left Left padding of the gradient shape + * @param top Top padding of the gradient shape + * @param right Right padding of the gradient shape + * @param bottom Bottom padding of the gradient shape + * + * @attr ref android.R.styleable#GradientDrawablePadding_left + * @attr ref android.R.styleable#GradientDrawablePadding_top + * @attr ref android.R.styleable#GradientDrawablePadding_right + * @attr ref android.R.styleable#GradientDrawablePadding_bottom + */ + public void setPadding(int left, int top, int right, int bottom) { + if (mGradientState.mPadding == null) { + mGradientState.mPadding = new Rect(); + } + + mGradientState.mPadding.set(left, top, right, bottom); + mPadding = mGradientState.mPadding; + invalidateSelf(); + } + private Path buildRing(GradientState st) { if (mRingPath != null && (!st.mUseLevelForShape || !mPathIsDirty)) return mRingPath; mPathIsDirty = false; @@ -1814,46 +1945,46 @@ public class GradientDrawable extends Drawable { final static class GradientState extends ConstantState { public @Config int mChangingConfigurations; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public @Shape int mShape = RECTANGLE; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public @GradientType int mGradient = LINEAR_GRADIENT; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public int mAngle = 0; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public Orientation mOrientation; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public ColorStateList mSolidColors; public ColorStateList mStrokeColors; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public @ColorInt int[] mGradientColors; public @ColorInt int[] mTempColors; // no need to copy public float[] mTempPositions; // no need to copy @UnsupportedAppUsage public float[] mPositions; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public int mStrokeWidth = -1; // if >= 0 use stroking. - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public float mStrokeDashWidth = 0.0f; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public float mStrokeDashGap = 0.0f; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public float mRadius = 0.0f; // use this if mRadiusArray is null - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public float[] mRadiusArray = null; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public Rect mPadding = null; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public int mWidth = -1; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public int mHeight = -1; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public float mInnerRadiusRatio = DEFAULT_INNER_RADIUS_RATIO; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050218) public float mThicknessRatio = DEFAULT_THICKNESS_RATIO; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public int mInnerRadius = -1; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050218) public int mThickness = -1; public boolean mDither = false; public Insets mOpticalInsets = Insets.NONE; diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index 5d5e40fd3ac3..eb169be06025 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -18,8 +18,8 @@ package android.security; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; -import android.annotation.WorkerThread; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.WorkerThread; import android.app.Activity; import android.app.PendingIntent; import android.app.Service; @@ -29,7 +29,6 @@ import android.content.Intent; import android.content.ServiceConnection; import android.net.Uri; import android.os.Binder; -import android.os.Build; import android.os.IBinder; import android.os.Looper; import android.os.Process; @@ -38,6 +37,8 @@ import android.os.UserHandle; import android.security.keystore.AndroidKeyStoreProvider; import android.security.keystore.KeyProperties; +import com.android.org.conscrypt.TrustedCertificateStore; + import java.io.ByteArrayInputStream; import java.io.Closeable; import java.io.Serializable; @@ -58,8 +59,6 @@ import java.util.concurrent.LinkedBlockingQueue; import javax.security.auth.x500.X500Principal; -import com.android.org.conscrypt.TrustedCertificateStore; - /** * The {@code KeyChain} class provides access to private keys and * their corresponding certificate chains in credential storage. @@ -214,8 +213,8 @@ public final class KeyChain { * * @deprecated Use {@link #ACTION_KEYCHAIN_CHANGED}, {@link #ACTION_TRUST_STORE_CHANGED} or * {@link #ACTION_KEY_ACCESS_CHANGED}. Apps that target a version higher than - * {@link Build.VERSION_CODES#N_MR1} will only receive this broadcast if they register for it - * at runtime. + * {@link android.os.Build.VERSION_CODES#N_MR1} will only receive this broadcast if they + * register for it at runtime. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED"; @@ -532,8 +531,8 @@ public final class KeyChain { } /** - * Returns the {@code PrivateKey} for the requested alias, or null - * if there is no result. + * Returns the {@code PrivateKey} for the requested alias, or null if the alias does not exist + * or the caller has no permission to access it (see note on exceptions below). * * <p> This method may block while waiting for a connection to another process, and must never * be called from the main thread. @@ -541,6 +540,15 @@ public final class KeyChain { * at any time from the main thread, it is safer to rely on a long-lived context such as one * returned from {@link Context#getApplicationContext()}. * + * <p> If the caller provides a valid alias to which it was not granted access, then the + * caller must invoke {@link #choosePrivateKeyAlias} again to get another valid alias + * or a grant to access the same alias. + * <p>On Android versions prior to Q, when a key associated with the specified alias is + * unavailable, the method will throw a {@code KeyChainException} rather than return null. + * If the exception's cause (as obtained by calling {@code KeyChainException.getCause()}) + * is a throwable of type {@code IllegalStateException} then the caller lacks a grant + * to access the key and certificates associated with this alias. + * * @param alias The alias of the desired private key, typically returned via * {@link KeyChainAliasCallback#alias}. * @throws KeyChainException if the alias was valid but there was some problem accessing it. @@ -591,8 +599,10 @@ public final class KeyChain { } /** - * Returns the {@code X509Certificate} chain for the requested - * alias, or null if there is no result. + * Returns the {@code X509Certificate} chain for the requested alias, or null if the alias + * does not exist or the caller has no permission to access it (see note on exceptions + * in {@link #getPrivateKey}). + * * <p> * <strong>Note:</strong> If a certificate chain was explicitly specified when the alias was * installed, this method will return that chain. If only the client certificate was specified @@ -604,6 +614,9 @@ public final class KeyChain { * <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed * at any time from the main thread, it is safer to rely on a long-lived context such as one * returned from {@link Context#getApplicationContext()}. + * <p> In case the caller specifies an alias for which it lacks a grant, it must call + * {@link #choosePrivateKeyAlias} again. See {@link #getPrivateKey} for more details on + * coping with this scenario. * * @param alias The alias of the desired certificate chain, typically * returned via {@link KeyChainAliasCallback#alias}. diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 81afd937d85e..66d8542553d2 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -203,6 +203,27 @@ const DynamicRefTable* AssetManager2::GetDynamicRefTableForCookie(ApkAssetsCooki return nullptr; } +const std::unordered_map<std::string, std::string>* + AssetManager2::GetOverlayableMapForPackage(uint32_t package_id) const { + + if (package_id >= package_ids_.size()) { + return nullptr; + } + + const size_t idx = package_ids_[package_id]; + if (idx == 0xff) { + return nullptr; + } + + const PackageGroup& package_group = package_groups_[idx]; + if (package_group.packages_.size() == 0) { + return nullptr; + } + + const auto loaded_package = package_group.packages_[0].loaded_package_; + return &loaded_package->GetOverlayableMap(); +} + void AssetManager2::SetConfiguration(const ResTable_config& configuration) { const int diff = configuration_.diff(configuration); configuration_ = configuration; diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp index bdd47061054a..72873abc6a42 100644 --- a/libs/androidfw/LoadedArsc.cpp +++ b/libs/androidfw/LoadedArsc.cpp @@ -598,6 +598,13 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, std::string actor; util::ReadUtf16StringFromDevice(header->actor, arraysize(header->actor), &actor); + if (loaded_package->overlayable_map_.find(name) != + loaded_package->overlayable_map_.end()) { + LOG(ERROR) << "Multiple <overlayable> blocks with the same name '" << name << "'."; + return {}; + } + loaded_package->overlayable_map_.emplace(name, actor); + // Iterate over the overlayable policy chunks contained within the overlayable chunk data ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size()); while (overlayable_iter.HasNext()) { diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index d862182d8960..fc5aa9c7f1b9 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -124,6 +124,9 @@ class AssetManager2 { // This may be nullptr if the APK represented by `cookie` has no resource table. const DynamicRefTable* GetDynamicRefTableForCookie(ApkAssetsCookie cookie) const; + const std::unordered_map<std::string, std::string>* + GetOverlayableMapForPackage(uint32_t package_id) const; + // Sets/resets the configuration for this AssetManager. This will cause all // caches that are related to the configuration change to be invalidated. void SetConfiguration(const ResTable_config& configuration); diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h index b5f4006dbb00..950f5413f550 100644 --- a/libs/androidfw/include/androidfw/LoadedArsc.h +++ b/libs/androidfw/include/androidfw/LoadedArsc.h @@ -20,6 +20,7 @@ #include <memory> #include <set> #include <vector> +#include <unordered_map> #include <unordered_set> #include "android-base/macros.h" @@ -242,6 +243,10 @@ class LoadedPackage { return defines_overlayable_; } + const std::unordered_map<std::string, std::string>& GetOverlayableMap() const { + return overlayable_map_; + } + private: DISALLOW_COPY_AND_ASSIGN(LoadedPackage); @@ -261,6 +266,7 @@ class LoadedPackage { ByteBucketArray<uint32_t> resource_ids_; std::vector<DynamicPackageEntry> dynamic_package_map_; std::vector<const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_; + std::unordered_map<std::string, std::string> overlayable_map_; }; // Read-only view into a resource table. This class validates all data diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp index 447fdf5d306a..40c8e46e4d84 100644 --- a/libs/androidfw/tests/AssetManager2_test.cpp +++ b/libs/androidfw/tests/AssetManager2_test.cpp @@ -71,6 +71,9 @@ class AssetManager2Test : public ::testing::Test { app_assets_ = ApkAssets::Load(GetTestDataPath() + "/app/app.apk"); ASSERT_THAT(app_assets_, NotNull()); + + overlayable_assets_ = ApkAssets::Load(GetTestDataPath() + "/overlayable/overlayable.apk"); + ASSERT_THAT(overlayable_assets_, NotNull()); } protected: @@ -83,6 +86,7 @@ class AssetManager2Test : public ::testing::Test { std::unique_ptr<const ApkAssets> appaslib_assets_; std::unique_ptr<const ApkAssets> system_assets_; std::unique_ptr<const ApkAssets> app_assets_; + std::unique_ptr<const ApkAssets> overlayable_assets_; }; TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) { @@ -703,4 +707,20 @@ TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) { EXPECT_EQ("", resultDisabled); } +TEST_F(AssetManager2Test, GetOverlayableMap) { + ResTable_config desired_config; + memset(&desired_config, 0, sizeof(desired_config)); + + AssetManager2 assetmanager; + assetmanager.SetResourceResolutionLoggingEnabled(true); + assetmanager.SetConfiguration(desired_config); + assetmanager.SetApkAssets({overlayable_assets_.get()}); + + const auto map = assetmanager.GetOverlayableMapForPackage(0x7f); + ASSERT_NE(nullptr, map); + ASSERT_EQ(2, map->size()); + ASSERT_EQ(map->at("OverlayableResources1"), "overlay://theme"); + ASSERT_EQ(map->at("OverlayableResources2"), "overlay://com.android.overlayable"); +} + } // namespace android diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp index b8d3c6bf92fb..d58e8d20c8aa 100644 --- a/libs/androidfw/tests/LoadedArsc_test.cpp +++ b/libs/androidfw/tests/LoadedArsc_test.cpp @@ -331,7 +331,7 @@ TEST(LoadedArscTest, ResourceIdentifierIterator) { const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages(); ASSERT_EQ(1u, packages.size()); - EXPECT_EQ(std::string("com.android.basic"), packages[0]->GetPackageName()); + ASSERT_EQ(std::string("com.android.basic"), packages[0]->GetPackageName()); const auto& loaded_package = packages[0]; auto iter = loaded_package->begin(); @@ -369,6 +369,24 @@ TEST(LoadedArscTest, ResourceIdentifierIterator) { ASSERT_EQ(end, iter); } +TEST(LoadedArscTest, GetOverlayableMap) { + std::string contents; + ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlayable/overlayable.apk", + "resources.arsc", &contents)); + + std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents)); + ASSERT_NE(nullptr, loaded_arsc); + + const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages(); + ASSERT_EQ(1u, packages.size()); + ASSERT_EQ(std::string("com.android.overlayable"), packages[0]->GetPackageName()); + + const auto map = packages[0]->GetOverlayableMap(); + ASSERT_EQ(2, map.size()); + ASSERT_EQ(map.at("OverlayableResources1"), "overlay://theme"); + ASSERT_EQ(map.at("OverlayableResources2"), "overlay://com.android.overlayable"); +} + // structs with size fields (like Res_value, ResTable_entry) should be // backwards and forwards compatible (aka checking the size field against // sizeof(Res_value) might not be backwards compatible. diff --git a/libs/incident/Android.bp b/libs/incident/Android.bp index 0619a9c100dd..905e3039ff88 100644 --- a/libs/incident/Android.bp +++ b/libs/incident/Android.bp @@ -36,7 +36,6 @@ cc_library_shared { srcs: [ ":libincident_aidl", - "proto/android/os/header.proto", "proto/android/os/metadata.proto", "src/IncidentReportArgs.cpp", ], @@ -47,4 +46,4 @@ cc_library_shared { }, export_include_dirs: ["include"], -} +}
\ No newline at end of file diff --git a/libs/incident/include/android/os/IncidentReportArgs.h b/libs/incident/include/android/os/IncidentReportArgs.h index ee1e33c43b89..5e8eac1833ce 100644 --- a/libs/incident/include/android/os/IncidentReportArgs.h +++ b/libs/incident/include/android/os/IncidentReportArgs.h @@ -24,8 +24,6 @@ #include <set> #include <vector> -#include "frameworks/base/libs/incident/proto/android/os/header.pb.h" - namespace android { namespace os { @@ -49,7 +47,7 @@ public: void setAll(bool all); void setDest(int dest); void addSection(int section); - void addHeader(const IncidentHeaderProto& headerProto); + void addHeader(const vector<uint8_t>& headerProto); inline bool all() const { return mAll; } bool containsSection(int section) const; diff --git a/libs/incident/src/IncidentReportArgs.cpp b/libs/incident/src/IncidentReportArgs.cpp index 26261ef929ae..06b7a5b682b1 100644 --- a/libs/incident/src/IncidentReportArgs.cpp +++ b/libs/incident/src/IncidentReportArgs.cpp @@ -161,15 +161,9 @@ IncidentReportArgs::addSection(int section) } void -IncidentReportArgs::addHeader(const IncidentHeaderProto& headerProto) +IncidentReportArgs::addHeader(const vector<uint8_t>& headerProto) { - vector<uint8_t> header; - auto serialized = headerProto.SerializeAsString(); - if (serialized.empty()) return; - for (auto it = serialized.begin(); it != serialized.end(); it++) { - header.push_back((uint8_t)*it); - } - mHeaders.push_back(header); + mHeaders.push_back(headerProto); } bool diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl index 5f6686a88a7e..c038f36206f6 100644 --- a/media/java/android/media/IRingtonePlayer.aidl +++ b/media/java/android/media/IRingtonePlayer.aidl @@ -17,6 +17,7 @@ package android.media; import android.media.AudioAttributes; +import android.media.VolumeShaper; import android.net.Uri; import android.os.ParcelFileDescriptor; import android.os.UserHandle; @@ -27,6 +28,8 @@ import android.os.UserHandle; interface IRingtonePlayer { /** Used for Ringtone.java playback */ oneway void play(IBinder token, in Uri uri, in AudioAttributes aa, float volume, boolean looping); + oneway void playWithVolumeShaping(IBinder token, in Uri uri, in AudioAttributes aa, + float volume, boolean looping, in @nullable VolumeShaper.Configuration volumeShaperConfig); oneway void stop(IBinder token); boolean isPlaying(IBinder token); oneway void setPlaybackProperties(IBinder token, float volume, boolean looping); diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index 751d57bbdc81..4bc3897c4477 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -1614,29 +1614,59 @@ public final class MediaCodecInfo { } /** - * Video performance points are a set of standard performance points defined by pixel rate. + * Video performance points are a set of standard performance points defined by number of + * pixels, pixel rate and frame rate. Performance point represents an upper bound. This + * means that it covers all performance points with fewer pixels, pixel rate and frame + * rate. */ public static final class PerformancePoint { /** - * Frame width in pixels. + * (Maximum) number of macroblocks in the frame. + * + * Video frames are conceptually divided into 16-by-16 pixel blocks called macroblocks. + * Most coding standards operate on these 16-by-16 pixel blocks; thus, codec performance + * is characterized using such blocks. */ - public final int width; + public final int macroBlocks; /** - * Frame height in pixels. + * (Maximum) frame rate in frames per second. */ - public final int height; + public final int frameRate; /** - * Frame rate in frames per second. + * (Maximum) number of macroblocks processed per second. */ - public final int frameRate; + public final long macroBlockRate; /* package private */ - PerformancePoint(int width_, int height_, int frameRate_) { - width = width_; - height = height_; - frameRate = frameRate_; + PerformancePoint(int width_, int height_, int frameRate_, int maxFrameRate_) { + macroBlocks = saturateLongToInt( + ((Math.max(1, (long)width_) + 15) / 16) + * ((Math.max(1, (long)height_) + 15) / 16)); + frameRate = Math.max(1, frameRate_); + macroBlockRate = Math.max(maxFrameRate_, frameRate) * macroBlocks; + } + + /** + * Create a performance point for a given frame size and frame rate. + * + * @param width_ width of the frame in pixels + * @param height_ height of the frame in pixels + * @param frameRate_ frame rate in frames per second + */ + public PerformancePoint(int width_, int height_, int frameRate_) { + this(width_, height_, frameRate_, frameRate_ /* maxFrameRate */); + } + + private int saturateLongToInt(long value) { + if (value < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } else if (value > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } else { + return (int)value; + } } /** @@ -1647,26 +1677,40 @@ public final class MediaCodecInfo { * @return {@code true} if the performance point covers the format. */ public boolean covers(@NonNull MediaFormat format) { - // for simplicity, this code assumes a 16x16 block size. - long macroBlocks = ((width + 15) / 16) * (long)((height + 15) / 16); - long mbps = macroBlocks * frameRate; + PerformancePoint other = new PerformancePoint( + format.getInteger(MediaFormat.KEY_WIDTH, 0), + format.getInteger(MediaFormat.KEY_HEIGHT, 0), + // safely convert ceil(double) to int through float case and Math.round + Math.round((float)( + Math.ceil(format.getNumber(MediaFormat.KEY_FRAME_RATE, 0) + .doubleValue())))); + return covers(other); + } - long formatMacroBlocks = - (long)((format.getInteger(MediaFormat.KEY_WIDTH, 0) + 15) / 16) - * ((format.getInteger(MediaFormat.KEY_HEIGHT, 0) + 15) / 16); - double formatMbps = - Math.ceil(formatMacroBlocks - * format.getNumber(MediaFormat.KEY_FRAME_RATE, 0).doubleValue()); - return formatMacroBlocks > 0 && formatMacroBlocks <= macroBlocks - && formatMbps <= mbps; + /** + * Checks whether the performance point covers another performance point. Use this + * method to determine if a performance point advertised by a codec covers the + * performance point required. This method can also be used for lose ordering as this + * method is transitive. + * + * @param other other performance point considered + * + * @return {@code true} if the performance point covers the other. + */ + public boolean covers(@NonNull PerformancePoint other) { + return (macroBlocks >= other.macroBlocks + && frameRate >= other.frameRate + && macroBlockRate >= other.macroBlockRate); } + @Override public boolean equals(Object o) { if (o instanceof PerformancePoint) { PerformancePoint other = (PerformancePoint)o; - return ((long)width * height) == ((long)other.width * other.height) - && frameRate == other.frameRate; + return (macroBlocks == other.macroBlocks + && frameRate == other.frameRate + && macroBlockRate == other.macroBlockRate); } return false; } @@ -1931,7 +1975,8 @@ public final class MediaCodecInfo { continue; } ret.add(new PerformancePoint( - size.getWidth(), size.getHeight(), range.getLower().intValue())); + size.getWidth(), size.getHeight(), range.getLower().intValue(), + range.getUpper().intValue())); } // check if the component specified no performance point indication if (ret.size() == 0) { @@ -1939,9 +1984,12 @@ public final class MediaCodecInfo { } // sort reversed by area first, then by frame rate - ret.sort((a, b) -> (a.width * a.height != b.width * b.height ? - (b.width * b.height - a.width * a.height) : - (b.frameRate - a.frameRate))); + ret.sort((a, b) -> -((a.macroBlocks != b.macroBlocks) ? + (a.macroBlocks < b.macroBlocks ? -1 : 1) : + (a.macroBlockRate != b.macroBlockRate) ? + (a.macroBlockRate < b.macroBlockRate ? -1 : 1) : + (a.frameRate != b.frameRate) ? + (a.frameRate < b.frameRate ? -1 : 1) : 0)); return ret; } @@ -2363,39 +2411,45 @@ public final class MediaCodecInfo { boolean supported = true; switch (profileLevel.level) { case CodecProfileLevel.AVCLevel1: - MBPS = 1485; FS = 99; BR = 64; DPB = 396; break; + MBPS = 1485; FS = 99; BR = 64; DPB = 396; break; case CodecProfileLevel.AVCLevel1b: - MBPS = 1485; FS = 99; BR = 128; DPB = 396; break; + MBPS = 1485; FS = 99; BR = 128; DPB = 396; break; case CodecProfileLevel.AVCLevel11: - MBPS = 3000; FS = 396; BR = 192; DPB = 900; break; + MBPS = 3000; FS = 396; BR = 192; DPB = 900; break; case CodecProfileLevel.AVCLevel12: - MBPS = 6000; FS = 396; BR = 384; DPB = 2376; break; + MBPS = 6000; FS = 396; BR = 384; DPB = 2376; break; case CodecProfileLevel.AVCLevel13: - MBPS = 11880; FS = 396; BR = 768; DPB = 2376; break; + MBPS = 11880; FS = 396; BR = 768; DPB = 2376; break; case CodecProfileLevel.AVCLevel2: - MBPS = 11880; FS = 396; BR = 2000; DPB = 2376; break; + MBPS = 11880; FS = 396; BR = 2000; DPB = 2376; break; case CodecProfileLevel.AVCLevel21: - MBPS = 19800; FS = 792; BR = 4000; DPB = 4752; break; + MBPS = 19800; FS = 792; BR = 4000; DPB = 4752; break; case CodecProfileLevel.AVCLevel22: - MBPS = 20250; FS = 1620; BR = 4000; DPB = 8100; break; + MBPS = 20250; FS = 1620; BR = 4000; DPB = 8100; break; case CodecProfileLevel.AVCLevel3: - MBPS = 40500; FS = 1620; BR = 10000; DPB = 8100; break; + MBPS = 40500; FS = 1620; BR = 10000; DPB = 8100; break; case CodecProfileLevel.AVCLevel31: - MBPS = 108000; FS = 3600; BR = 14000; DPB = 18000; break; + MBPS = 108000; FS = 3600; BR = 14000; DPB = 18000; break; case CodecProfileLevel.AVCLevel32: - MBPS = 216000; FS = 5120; BR = 20000; DPB = 20480; break; + MBPS = 216000; FS = 5120; BR = 20000; DPB = 20480; break; case CodecProfileLevel.AVCLevel4: - MBPS = 245760; FS = 8192; BR = 20000; DPB = 32768; break; + MBPS = 245760; FS = 8192; BR = 20000; DPB = 32768; break; case CodecProfileLevel.AVCLevel41: - MBPS = 245760; FS = 8192; BR = 50000; DPB = 32768; break; + MBPS = 245760; FS = 8192; BR = 50000; DPB = 32768; break; case CodecProfileLevel.AVCLevel42: - MBPS = 522240; FS = 8704; BR = 50000; DPB = 34816; break; + MBPS = 522240; FS = 8704; BR = 50000; DPB = 34816; break; case CodecProfileLevel.AVCLevel5: - MBPS = 589824; FS = 22080; BR = 135000; DPB = 110400; break; + MBPS = 589824; FS = 22080; BR = 135000; DPB = 110400; break; case CodecProfileLevel.AVCLevel51: - MBPS = 983040; FS = 36864; BR = 240000; DPB = 184320; break; + MBPS = 983040; FS = 36864; BR = 240000; DPB = 184320; break; case CodecProfileLevel.AVCLevel52: - MBPS = 2073600; FS = 36864; BR = 240000; DPB = 184320; break; + MBPS = 2073600; FS = 36864; BR = 240000; DPB = 184320; break; + case CodecProfileLevel.AVCLevel6: + MBPS = 4177920; FS = 139264; BR = 240000; DPB = 696320; break; + case CodecProfileLevel.AVCLevel61: + MBPS = 8355840; FS = 139264; BR = 480000; DPB = 696320; break; + case CodecProfileLevel.AVCLevel62: + MBPS = 16711680; FS = 139264; BR = 800000; DPB = 696320; break; default: Log.w(TAG, "Unrecognized level " + profileLevel.level + " for " + mime); diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index a76cf1f6ba25..12e02e7b73cd 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -1520,6 +1520,7 @@ public final class MediaFormat { * Create a copy of a media format object. */ public MediaFormat(@NonNull MediaFormat other) { + this(); mMap.putAll(other.mMap); } diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java index 73d3d889e464..eb680c8377f4 100644 --- a/media/java/android/media/Ringtone.java +++ b/media/java/android/media/Ringtone.java @@ -381,7 +381,8 @@ public class Ringtone { volume = mVolume; } try { - mRemotePlayer.play(mRemoteToken, canonicalUri, mAudioAttributes, volume, looping); + mRemotePlayer.playWithVolumeShaping(mRemoteToken, canonicalUri, mAudioAttributes, + volume, looping, mVolumeShaperConfig); } catch (RemoteException e) { if (!playFallbackRingtone()) { Log.w(TAG, "Problem playing ringtone: " + e); diff --git a/media/java/android/media/VolumeShaper.aidl b/media/java/android/media/VolumeShaper.aidl new file mode 100644 index 000000000000..e99c13f8a6f3 --- /dev/null +++ b/media/java/android/media/VolumeShaper.aidl @@ -0,0 +1,19 @@ +/* Copyright 2019, 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 VolumeShaper; +parcelable VolumeShaper.Configuration; diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index e08dab48ce39..49066950a9fb 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -17,8 +17,9 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "SoundPool" +#include <chrono> #include <inttypes.h> - +#include <thread> #include <utils/Log.h> #define USE_SHARED_MEM_BUFFER @@ -967,6 +968,12 @@ bool SoundChannel::doStop_l() if (mState != IDLE) { setVolume_l(0, 0); ALOGV("stop"); + // Since we're forcibly halting the previously playing content, + // we sleep here to ensure the volume is ramped down before we stop the track. + // Ideally the sleep time is the mixer period, or an approximation thereof + // (Fast vs Normal tracks are different). + // TODO: consider pausing instead of stop here. + std::this_thread::sleep_for(std::chrono::milliseconds(20)); mAudioTrack->stop(); mPrevSampleID = mSample->sampleID(); mSample.clear(); diff --git a/media/packages/MediaCore/Android.bp.bak b/media/packages/MediaCore/Android.bp.bak deleted file mode 100644 index c7fd58bf933a..000000000000 --- a/media/packages/MediaCore/Android.bp.bak +++ /dev/null @@ -1,21 +0,0 @@ -android_app { - name: "MediaCore", - - srcs: [ - "src/**/*.java", - ], - - static_libs: [ - // TODO: Temporarily statically linked. Should go into "libs" - "media1", - ], - - // System app - platform_apis: true, - - // Privileged app - privileged: true, - - // Make sure that the implementation only relies on SDK or system APIs. - sdk_version: "system_current", -} diff --git a/media/packages/MediaCore/AndroidManifest.xml b/media/packages/MediaCore/AndroidManifest.xml deleted file mode 100644 index 4e2b274511e8..000000000000 --- a/media/packages/MediaCore/AndroidManifest.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* //device/apps/common/AndroidManifest.xml -** -** Copyright 2019, 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. -*/ ---> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.media" coreApp="true" android:sharedUserId="android.uid.system" - android:sharedUserLabel="@string/android_system_label"> - <application android:process="system" - android:persistent="true" - android:directBootAware="true"> - <service android:name="AmlMediaSessionProviderService" android:singleUser="true"> - <intent-filter> - <action android:name="android.media.session.MediaSessionProviderService"/> - </intent-filter> - </service> - </application> -</manifest> diff --git a/media/packages/MediaCore/res/values/strings.xml b/media/packages/MediaCore/res/values/strings.xml deleted file mode 100644 index 59fd635b905f..000000000000 --- a/media/packages/MediaCore/res/values/strings.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2019 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. ---> - -<resources> - <!-- Label for the Android system components when they are shown to the user. --> - <string name="android_system_label" translatable="false">Android System</string> -</resources> - diff --git a/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java b/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java deleted file mode 100644 index 43b95ab7ebdb..000000000000 --- a/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2019 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.media; - -import android.content.Context; -import android.media.session.MediaSessionProviderService; -import android.os.PowerManager; -import android.util.Log; - -/** - * System implementation of MediaSessionProviderService - */ -public class AmlMediaSessionProviderService extends MediaSessionProviderService { - private static final String TAG = "AmlMediaSessionProviderS"; - static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private Context mContext; - - public AmlMediaSessionProviderService(Context context) { - mContext = context; - PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - } -} diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index 51afbc7d91b0..730c409a91fb 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -230,6 +230,7 @@ LIBANDROID { ASurfaceTransaction_reparent; # introduced=29 ASurfaceTransaction_setBuffer; # introduced=29 ASurfaceTransaction_setBufferAlpha; # introduced=29 + ASurfaceTransaction_setBufferDataSpace; # introduced=29 ASurfaceTransaction_setBufferTransparency; # introduced=29 ASurfaceTransaction_setColor; # introduced=29 ASurfaceTransaction_setDamageRegion; # introduced=29 diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index 7d2934b8554e..d07052bb3b3f 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -440,6 +440,20 @@ void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* aSurfaceTransaction transaction->setAlpha(surfaceControl, alpha); } +void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* aSurfaceTransaction, + ASurfaceControl* aSurfaceControl, + ADataSpace aDataSpace) { + CHECK_NOT_NULL(aSurfaceTransaction); + CHECK_NOT_NULL(aSurfaceControl); + + sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); + LOG_ALWAYS_FATAL_IF(!isDataSpaceValid(surfaceControl, aDataSpace), "invalid dataspace"); + + Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); + + transaction->setDataspace(surfaceControl, static_cast<ui::Dataspace>(aDataSpace)); +} + void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl, struct AHdrMetadata_smpte2086* metadata) { diff --git a/packages/CaptivePortalLogin/res/values-gl/strings.xml b/packages/CaptivePortalLogin/res/values-gl/strings.xml index f6f4aea0c639..64195168f76f 100644 --- a/packages/CaptivePortalLogin/res/values-gl/strings.xml +++ b/packages/CaptivePortalLogin/res/values-gl/strings.xml @@ -13,7 +13,7 @@ <string name="ssl_error_mismatch" msgid="3060364165934822383">"O nome do sitio non coincide co nome que aparece no certificado."</string> <string name="ssl_error_expired" msgid="1501588340716182495">"Este certificado caducou."</string> <string name="ssl_error_not_yet_valid" msgid="8648649030525886924">"Este certificado aínda non é válido."</string> - <string name="ssl_error_date_invalid" msgid="88425990680059223">"Este certificado ten unha data non-válida."</string> + <string name="ssl_error_date_invalid" msgid="88425990680059223">"Este certificado ten unha data non válida."</string> <string name="ssl_error_invalid" msgid="2540546515565633432">"Este certificado non é válido."</string> <string name="ssl_error_unknown" msgid="4405203446079465859">"Produciuse un erro descoñecido relacionado co certificado."</string> <string name="ssl_security_warning_title" msgid="8768539813847504404">"Advertencia de seguranza"</string> diff --git a/packages/CarSystemUI/res/values/colors_car.xml b/packages/CarSystemUI/res/values/colors_car.xml index 2f720f5aba65..08e16cdbe3b3 100644 --- a/packages/CarSystemUI/res/values/colors_car.xml +++ b/packages/CarSystemUI/res/values/colors_car.xml @@ -26,6 +26,4 @@ <color name="car_user_switcher_add_user_background_color">@color/car_dark_blue_grey_600</color> <color name="car_user_switcher_add_user_add_sign_color">@color/car_body1_light</color> - <!-- colors for volume dialog tint --> - <color name="car_volume_dialog_tint">@color/car_tint</color> </resources> diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java index 85dab57b5f21..10a0ae5a924c 100644 --- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java +++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java @@ -554,8 +554,7 @@ public class CarVolumeDialogImpl implements VolumeDialog { // Adding the items which are not coming from the default item. VolumeItem volumeItem = mAvailableVolumeItems.get(groupId); if (volumeItem.defaultItem) { - // Set progress here due to the progress of seekbar may not be updated. - volumeItem.listItem.setProgress(volumeItem.progress); + updateDefaultVolumeItem(volumeItem.listItem); } else { addSeekbarListItem(volumeItem, groupId, 0, null); } @@ -572,8 +571,7 @@ public class CarVolumeDialogImpl implements VolumeDialog { if (!volumeItem.defaultItem) { itr.remove(); } else { - // Set progress here due to the progress of seekbar may not be updated. - seekbarListItem.setProgress(volumeItem.progress); + updateDefaultVolumeItem(seekbarListItem); } } inAnimator = AnimatorInflater.loadAnimator( @@ -595,6 +593,21 @@ public class CarVolumeDialogImpl implements VolumeDialog { mPagedListAdapter.notifyDataSetChanged(); } + private void updateDefaultVolumeItem(SeekbarListItem seekbarListItem){ + VolumeItem volumeItem = findVolumeItem(seekbarListItem); + + // When volume dialog is expanded or collapsed the default list item is never + // reset. Whereas all other list items are removed when the dialog is collapsed and then + // added when the dialog is expanded using {@link CarVolumeDialogImpl#addSeekbarListItem}. + // This sets the progressbar and the tint color of icons for all items other than default + // if they were changed. For default list item it should be done manually here. + int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint); + Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon); + primaryIcon.mutate().setTint(color); + volumeItem.listItem.setPrimaryActionIcon(primaryIcon); + volumeItem.listItem.setProgress(volumeItem.progress); + } + private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener { private final int mVolumeGroupId; diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java index b6b229c770b2..c5e598d8ce46 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java @@ -230,6 +230,10 @@ public class Assistant extends NotificationAssistantService { NotificationEntry entry = new NotificationEntry(mPackageManager, sbn, channel, mSmsHelper); SmartActionsHelper.SmartSuggestions suggestions = mSmartActionsHelper.suggest(entry); + if (DEBUG) { + Log.d(TAG, String.format("Creating Adjustment for %s, with %d actions, and %d replies.", + sbn.getKey(), suggestions.actions.size(), suggestions.replies.size())); + } return createEnqueuedNotificationAdjustment( entry, suggestions.actions, suggestions.replies); } diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java index 08cc39fc4935..f372fe55dfb0 100644 --- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java +++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java @@ -21,6 +21,7 @@ import android.app.Notification; import android.app.Person; import android.app.RemoteAction; import android.content.Context; +import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.Parcelable; import android.os.Process; @@ -42,6 +43,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Deque; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; public class SmartActionsHelper { @@ -120,6 +122,12 @@ public class SmartActionsHelper { if (messages.isEmpty()) { return Collections.emptyList(); } + // Do not generate smart actions if the last message is from the local user. + ConversationActions.Message lastMessage = messages.get(messages.size() - 1); + if (arePersonsEqual( + ConversationActions.Message.PERSON_USER_SELF, lastMessage.getAuthor())) { + return Collections.emptyList(); + } TextClassifier.EntityConfig.Builder typeConfigBuilder = new TextClassifier.EntityConfig.Builder(); @@ -230,8 +238,11 @@ public class SmartActionsHelper { private Notification.Action createNotificationAction( RemoteAction remoteAction, String actionType) { + Icon icon = remoteAction.shouldShowIcon() + ? remoteAction.getIcon() + : Icon.createWithResource(mContext, com.android.internal.R.drawable.ic_action_open); return new Notification.Action.Builder( - remoteAction.getIcon(), + icon, remoteAction.getTitle(), remoteAction.getActionIntent()) .setContextual(true) @@ -312,13 +323,12 @@ public class SmartActionsHelper { if (message == null) { continue; } + // As per the javadoc of Notification.addMessage, null means local user. Person senderPerson = message.getSenderPerson(); - // Skip encoding once the sender is missing as it is important to distinguish - // local user and remote user when generating replies. if (senderPerson == null) { - break; + senderPerson = localUser; } - Person author = localUser != null && localUser.equals(senderPerson) + Person author = localUser != null && arePersonsEqual(localUser, senderPerson) ? ConversationActions.Message.PERSON_USER_SELF : senderPerson; extractMessages.push(new ConversationActions.Message.Builder(author) .setText(message.getText()) @@ -333,6 +343,12 @@ public class SmartActionsHelper { return new ArrayList<>(extractMessages); } + private static boolean arePersonsEqual(@NonNull Person left, @NonNull Person right) { + return Objects.equals(left.getKey(), right.getKey()) + && Objects.equals(left.getName(), right.getName()) + && Objects.equals(left.getUri(), right.getUri()); + } + static class SmartSuggestions { public final ArrayList<CharSequence> replies; public final ArrayList<Notification.Action> actions; diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java index ebbd961b6f23..74c20fc09df2 100644 --- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java +++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java @@ -222,22 +222,29 @@ public class SmartActionsHelperTest { List<ConversationActions.Message> messages = runSuggestAndCaptureRequest().getConversation(); - assertThat(messages).hasSize(3); + assertThat(messages).hasSize(4); - ConversationActions.Message secondMessage = messages.get(0); + ConversationActions.Message firstMessage = messages.get(0); + MessageSubject.assertThat(firstMessage).hasText("firstMessage"); + MessageSubject.assertThat(firstMessage) + .hasPerson(ConversationActions.Message.PERSON_USER_SELF); + MessageSubject.assertThat(firstMessage) + .hasReferenceTime(createZonedDateTimeFromMsUtc(1000)); + + ConversationActions.Message secondMessage = messages.get(1); MessageSubject.assertThat(secondMessage).hasText("secondMessage"); MessageSubject.assertThat(secondMessage) .hasPerson(ConversationActions.Message.PERSON_USER_SELF); MessageSubject.assertThat(secondMessage) .hasReferenceTime(createZonedDateTimeFromMsUtc(2000)); - ConversationActions.Message thirdMessage = messages.get(1); + ConversationActions.Message thirdMessage = messages.get(2); MessageSubject.assertThat(thirdMessage).hasText("thirdMessage"); MessageSubject.assertThat(thirdMessage).hasPerson(userA); MessageSubject.assertThat(thirdMessage) .hasReferenceTime(createZonedDateTimeFromMsUtc(3000)); - ConversationActions.Message fourthMessage = messages.get(2); + ConversationActions.Message fourthMessage = messages.get(3); MessageSubject.assertThat(fourthMessage).hasText("fourthMessage"); MessageSubject.assertThat(fourthMessage).hasPerson(userB); MessageSubject.assertThat(fourthMessage) @@ -245,6 +252,28 @@ public class SmartActionsHelperTest { } @Test + public void testSuggest_lastMessageLocalUser() { + Person me = new Person.Builder().setName("Me").build(); + Person userA = new Person.Builder().setName("A").build(); + Notification.MessagingStyle style = + new Notification.MessagingStyle(me) + .addMessage("firstMessage", 1000, userA) + .addMessage("secondMessage", 2000, me); + Notification notification = + mNotificationBuilder + .setContentText("You have two new messages") + .setStyle(style) + .setActions(createReplyAction()) + .build(); + when(mStatusBarNotification.getNotification()).thenReturn(notification); + + mSmartActionsHelper.suggest(createNotificationEntry()); + + verify(mTextClassifier, never()) + .suggestConversationActions(any(ConversationActions.Request.class)); + } + + @Test public void testSuggest_messageStyle_noPerson() { Person me = new Person.Builder().setName("Me").build(); Notification.MessagingStyle style = diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml index ac55bfa1aed7..e4d35915c77c 100644 --- a/packages/NetworkStack/AndroidManifest.xml +++ b/packages/NetworkStack/AndroidManifest.xml @@ -27,8 +27,8 @@ <uses-permission android:name="android.permission.NETWORK_SETTINGS" /> <!-- Signature permission defined in NetworkStackStub --> <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" /> - <!-- Launch captive portal app as specific user --> - <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> + <!-- Send latency broadcast as current user --> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <uses-permission android:name="android.permission.NETWORK_STACK" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <application diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java index 0d6d080b6dc2..2e72d8296a37 100644 --- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java @@ -500,7 +500,7 @@ public class NetworkMonitor extends StateMachine { private void showProvisioningNotification(String action) { try { - mCallback.showProvisioningNotification(action); + mCallback.showProvisioningNotification(action, mContext.getPackageName()); } catch (RemoteException e) { Log.e(TAG, "Error showing provisioning notification", e); } diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java index d11bb64213c3..b98b0f798fe3 100644 --- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java +++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java @@ -482,7 +482,7 @@ public class NetworkMonitorTest { nm.notifyNetworkConnected(); verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)) - .showProvisioningNotification(any()); + .showProvisioningNotification(any(), any()); // Check that startCaptivePortalApp sends the expected intent. nm.launchCaptivePortalApp(); diff --git a/packages/SettingsLib/res/drawable/ic_system_update.xml b/packages/SettingsLib/res/drawable/ic_system_update.xml new file mode 100644 index 000000000000..3325fdd5c01a --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_system_update.xml @@ -0,0 +1,25 @@ +<!-- + Copyright (C) 2017 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0" + android:tint="?android:attr/colorControlNormal"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM16,12.5l-4,4l-4,-4l1.41,-1.41L11,12.67V8.5V8h2v0.5v4.17l1.59,-1.59L16,12.5z"/> +</vector> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index d6448336e402..f5d58d8a2004 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -337,6 +337,9 @@ <string name="data_usage_uninstalled_apps">Removed apps</string> <!-- Title of data usage item that represents all uninstalled applications or removed users. [CHAR LIMIT=48] --> <string name="data_usage_uninstalled_apps_users">Removed apps and users</string> + <!-- Title of data usage item that represents system updates (OTAs). [CHAR LIMIT=48] --> + <string name="data_usage_ota">System updates</string> + <!-- Tethering controls, item title to go into the tethering settings --> <!-- Tethering controls, item title to go into the tethering settings when only USB tethering is available [CHAR LIMIT=25]--> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index e28c894ff8f3..ab95910a77b5 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -167,7 +167,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> // This is to ensure all the profiles are disconnected as some CK/Hs do not // disconnect PBAP connection when HF connection is brought down PbapServerProfile PbapProfile = mProfileManager.getPbapProfile(); - if (PbapProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED) + if (PbapProfile != null && isConnectedProfile(PbapProfile)) { PbapProfile.disconnect(mDevice); } diff --git a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java index c14f5588cddf..e3516158daac 100644 --- a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java +++ b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java @@ -28,6 +28,7 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.TrafficStats; +import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -111,7 +112,7 @@ public class UidDetailProvider { // handle special case labels switch (uid) { - case android.os.Process.SYSTEM_UID: + case Process.SYSTEM_UID: detail.label = res.getString(R.string.process_kernel_label); detail.icon = pm.getDefaultActivityIcon(); return detail; @@ -127,6 +128,10 @@ public class UidDetailProvider { detail.label = res.getString(Utils.getTetheringLabel(cm)); detail.icon = pm.getDefaultActivityIcon(); return detail; + case Process.OTA_UPDATE_UID: + detail.label = res.getString(R.string.data_usage_ota); + detail.icon = mContext.getDrawable(R.drawable.ic_system_update); + return detail; } final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java index 88adcdb16edc..5c9a06f91e6a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java @@ -20,6 +20,7 @@ import android.os.Looper; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; public class ThreadUtils { @@ -59,12 +60,14 @@ public class ThreadUtils { /** * Posts runnable in background using shared background thread pool. + * + * @Return A future of the task that can be monitored for updates or cancelled. */ - public static void postOnBackgroundThread(Runnable runnable) { + public static Future postOnBackgroundThread(Runnable runnable) { if (sSingleThreadExecutor == null) { sSingleThreadExecutor = Executors.newSingleThreadExecutor(); } - sSingleThreadExecutor.execute(runnable); + return sSingleThreadExecutor.submit(runnable); } /** diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index dbeee1c4b2ca..26ea6ab2e8be 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -220,4 +220,7 @@ <!-- Default for Settings.Secure.CHARGING_SOUNDS_ENABLED --> <bool name="def_charging_sounds_enabled">true</bool> + + <!-- Default for Settings.Secure.NOTIFICATION_BUBBLES --> + <bool name="def_notification_bubbles">true</bool> </resources> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 6152b8cbd562..3caa139ab998 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -718,6 +718,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.GAME_DRIVER_WHITELIST, GlobalSettingsProto.Gpu.GAME_DRIVER_WHITELIST); + dumpSetting(s, p, + Settings.Global.GAME_DRIVER_BLACKLISTS, + GlobalSettingsProto.Gpu.GAME_DRIVER_BLACKLISTS); p.end(gpuToken); final long hdmiToken = p.start(GlobalSettingsProto.HDMI); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 23e5f0eea46d..a7ad2239b402 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -3232,7 +3232,7 @@ public class SettingsProvider extends ContentProvider { } private final class UpgradeController { - private static final int SETTINGS_VERSION = 173; + private static final int SETTINGS_VERSION = 174; private final int mUserId; @@ -4252,6 +4252,24 @@ public class SettingsProvider extends ContentProvider { currentVersion = 173; } + if (currentVersion == 173) { + // Version 173: Set the default value for Secure Settings: NOTIFICATION_BUBBLES + + final SettingsState secureSettings = getSecureSettingsLocked(userId); + + final Setting bubblesSetting = secureSettings.getSettingLocked( + Secure.NOTIFICATION_BUBBLES); + + if (bubblesSetting.isNull()) { + secureSettings.insertSettingLocked(Secure.NOTIFICATION_BUBBLES, + getContext().getResources().getBoolean( + R.bool.def_notification_bubbles) ? "1" : "0", null, + true, SettingsState.SYSTEM_PACKAGE_NAME); + } + + currentVersion = 174; + } + // vXXX: Add new settings above this point. if (currentVersion != newVersion) { diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index e8c728d358ea..0da3b10778e9 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -82,6 +82,7 @@ <uses-permission android:name="android.permission.MOVE_PACKAGE" /> <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" /> <uses-permission android:name="android.permission.CLEAR_APP_CACHE" /> + <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS" /> <uses-permission android:name="android.permission.DELETE_CACHE_FILES" /> <uses-permission android:name="android.permission.DELETE_PACKAGES" /> <uses-permission android:name="android.permission.MANAGE_ROLLBACKS" /> diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java index ac6904300f71..38bf77d5eb0e 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java @@ -55,9 +55,16 @@ public interface ClockPlugin extends Plugin { void setTextColor(int color); /** + * Sets the color palette for the clock face. + * @param supportsDarkText Whether dark text can be displayed. + * @param colors Colors that should be used on the clock face, ordered from darker to lighter. + */ + default void setColorPalette(boolean supportsDarkText, int[] colors) {} + + /** * Notifies that time tick alarm from doze service fired. */ - default void dozeTimeTick() { } + default void dozeTimeTick() {} /** * Set the amount (ratio) that the device has transitioned to doze. diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java new file mode 100644 index 000000000000..3ee69b4c3224 --- /dev/null +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2019 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.systemui.plugins.statusbar; + +import com.android.systemui.plugins.annotations.DependsOn; +import com.android.systemui.plugins.annotations.ProvidesInterface; +import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; + + +/** + * Sends updates to {@link StateListener}s about changes to the status bar state and dozing state + */ +@ProvidesInterface(version = StatusBarStateController.VERSION) +@DependsOn(target = StatusBarStateController.StateListener.class) +public interface StatusBarStateController { + int VERSION = 1; + + /** + * Current status bar state + */ + int getState(); + + /** + * Is device dozing + */ + boolean isDozing(); + + /** + * Adds a state listener + */ + void addCallback(StateListener listener); + + /** + * Removes callback from listeners + */ + void removeCallback(StateListener listener); + + /** + * Get amount of doze + */ + float getDozeAmount(); + + /** + * Listener for StatusBarState updates + */ + @ProvidesInterface(version = StateListener.VERSION) + public interface StateListener { + int VERSION = 1; + + /** + * Callback before the new state is applied, for those who need to preempt the change. + */ + default void onStatePreChange(int oldState, int newState) { + } + + /** + * Callback after all listeners have had a chance to update based on the state change + */ + default void onStatePostChange() { + } + + /** + * Required callback. Get the new state and do what you will with it. Keep in mind that + * other listeners are typically unordered and don't rely on your work being done before + * other peers. + * + * Only called if the state is actually different. + */ + default void onStateChanged(int newState) { + } + + /** + * Callback to be notified when Dozing changes. Dozing is stored separately from state. + */ + default void onDozingChanged(boolean isDozing) {} + + /** + * Callback to be notified when the doze amount changes. Useful for animations. + * Note: this will be called for each animation frame. Please be careful to avoid + * performance regressions. + */ + default void onDozeAmountChanged(float linear, float eased) {} + } +} diff --git a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml index 6f7f39810608..c8dc8e43893c 100644 --- a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml +++ b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml @@ -19,9 +19,21 @@ android:layout_width="match_parent" android:layout_height="match_parent" > - <include + <TextClock android:id="@+id/digital_clock" - layout="@layout/text_clock" + android:layout_marginLeft="20dp" + android:layout_marginTop="72dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="top|left" + android:textSize="44dp" + android:letterSpacing="0.05" + android:textColor="?attr/wallpaperTextColor" + android:singleLine="true" + style="@style/widget_big" + android:format12Hour="@string/keyguard_widget_12_hours_format" + android:format24Hour="@string/keyguard_widget_24_hours_format" + android:elegantTextHeight="false" /> <com.android.keyguard.clock.ImageClock android:id="@+id/analog_clock" diff --git a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml index 64b676f55fd6..116a044a7075 100644 --- a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml +++ b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml @@ -19,9 +19,21 @@ android:layout_width="match_parent" android:layout_height="match_parent" > - <include + <TextClock android:id="@+id/digital_clock" - layout="@layout/text_clock" + android:layout_marginLeft="20dp" + android:layout_marginTop="72dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="top|left" + android:textSize="44dp" + android:letterSpacing="0.05" + android:textColor="?attr/wallpaperTextColor" + android:singleLine="true" + style="@style/widget_big" + android:format12Hour="@string/keyguard_widget_12_hours_format" + android:format24Hour="@string/keyguard_widget_24_hours_format" + android:elegantTextHeight="false" /> <com.android.keyguard.clock.StretchAnalogClock android:id="@+id/analog_clock" diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml index da11db39bd02..54537e5ee7a2 100644 --- a/packages/SystemUI/res-keyguard/values-af/strings.xml +++ b/packages/SystemUI/res-keyguard/values-af/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM is nou gedeaktiveer. Voer PUK-kode in om voort te gaan. Jy het <xliff:g id="_NUMBER_1">%d</xliff:g> pogings oor voordat die SIM permanent onbruikbaar word. Kontak die diensverskaffer vir besonderhede.</item> <item quantity="one">SIM is nou gedeaktiveer. Voer PUK-kode in om voort te gaan. Jy het <xliff:g id="_NUMBER_0">%d</xliff:g> poging oor voordat die SIM permanent onbruikbaar word. Kontak die diensverskaffer vir besonderhede.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Dit is"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Twaalf"</item> <item msgid="7389464214252023751">"Een"</item> diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml index 0d154f552e19..379838dc2a61 100644 --- a/packages/SystemUI/res-keyguard/values-am/strings.xml +++ b/packages/SystemUI/res-keyguard/values-am/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">ሲም አሁን ተሰናክሏል። ለመቀጠል የPUK ኮድ ያስገቡ። ሲም እስከመጨረሻው መጠቀም የማይቻል ከመሆኑ በፊት <xliff:g id="_NUMBER_1">%d</xliff:g> ሙከራዎች ይቀረዎታል። ዝርዝሮችን ለማግኘት የአገልግሎት አቅራቢን ያነጋግሩ።</item> <item quantity="other">ሲም አሁን ተሰናክሏል። ለመቀጠል የPUK ኮድ ያስገቡ። ሲም እስከመጨረሻው መጠቀም የማይቻል ከመሆኑ በፊት <xliff:g id="_NUMBER_1">%d</xliff:g> ሙከራዎች ይቀረዎታል። ዝርዝሮችን ለማግኘት የአገልግሎት አቅራቢን ያነጋግሩ።</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"ነው"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"አስራ ሁለት"</item> <item msgid="7389464214252023751">"አንድ"</item> diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml index 826f2f05f2ad..2fef0270b15c 100644 --- a/packages/SystemUI/res-keyguard/values-ar/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml @@ -182,7 +182,7 @@ <item quantity="other">تم إيقاف شريحة SIM الآن. أدخل رمز PUK للمتابعة، وتتبقى لديك <xliff:g id="_NUMBER_1">%d</xliff:g> محاولة قبل أن تصبح شريحة SIM غير صالحة للاستخدام نهائيًا. ويمكنك الاتصال بمشغل شبكة الجوّال لمعرفة التفاصيل.</item> <item quantity="one">تم إيقاف شريحة SIM الآن. أدخل رمز PUK للمتابعة، وتتبقى لديك محاولة واحدة (<xliff:g id="_NUMBER_0">%d</xliff:g>) قبل أن تصبح شريحة SIM غير صالحة للاستخدام نهائيًا. ويمكنك الاتصال بمشغل شبكة الجوّال لمعرفة التفاصيل.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"الساعة"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"الثانية عشرة"</item> <item msgid="7389464214252023751">"الواحدة"</item> diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml index f67e009ca58e..63d0512ca870 100644 --- a/packages/SystemUI/res-keyguard/values-as/strings.xml +++ b/packages/SystemUI/res-keyguard/values-as/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">ছিমখন অক্ষম হ’ল। অব্যাহত ৰাখিবলৈ PUK দিয়ক। ছিমখন স্থায়ীভাৱে ব্যৱহাৰৰ অনুপযোগী হোৱাৰ পূৰ্বে আপোনাৰ হাতত <xliff:g id="_NUMBER_1">%d</xliff:g>টা প্ৰয়াস বাকী আছে। সবিশেষ জানিবলৈ বাহকৰ সৈতে যোগাযোগ কৰক।</item> <item quantity="other">ছিমখন অক্ষম হ’ল। অব্যাহত ৰাখিবলৈ PUK দিয়ক। ছিমখন স্থায়ীভাৱে ব্যৱহাৰৰ অনুপযোগী হোৱাৰ পূৰ্বে আপোনাৰ হাতত <xliff:g id="_NUMBER_1">%d</xliff:g>টা প্ৰয়াস বাকী আছে। সবিশেষ জানিবলৈ বাহকৰ সৈতে যোগাযোগ কৰক।</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"সময়"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"বাৰ"</item> <item msgid="7389464214252023751">"এক"</item> diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml index 50f1b1f3d7bc..3714ec6e98ca 100644 --- a/packages/SystemUI/res-keyguard/values-az/strings.xml +++ b/packages/SystemUI/res-keyguard/values-az/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM indi deaktivdir. Davam etmək üçün PUK kodunu daxil edin. SIM birdəfəlik yararsız olmadan öncə <xliff:g id="_NUMBER_1">%d</xliff:g> cəhdiniz qalır. Ətraflı məlumat üçün operatorla əlaqə saxlayın.</item> <item quantity="one">SIM indi deaktivdir. Davam etmək üçün PUK kodunu daxil edin. SIM birdəfəlik yararsız olmadan öncə <xliff:g id="_NUMBER_0">%d</xliff:g> cəhdiniz qalır. Ətraflı məlumat üçün operatorla əlaqə saxlayın.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Saat"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"On iki"</item> <item msgid="7389464214252023751">"Bir"</item> diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml index a5fceef4f97b..327231305c3c 100644 --- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml @@ -158,7 +158,7 @@ <item quantity="few">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja pre nego što SIM postane trajno neupotrebljiv. Detaljne informacije potražite od mobilnog operatera.</item> <item quantity="other">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja pre nego što SIM postane trajno neupotrebljiv. Detaljne informacije potražite od mobilnog operatera.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Sada je"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"dvanaest"</item> <item msgid="7389464214252023751">"jedan"</item> diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml index 872cd7b997cd..aaa4cb65d37d 100644 --- a/packages/SystemUI/res-keyguard/values-be/strings.xml +++ b/packages/SystemUI/res-keyguard/values-be/strings.xml @@ -166,7 +166,7 @@ <item quantity="many">SIM-карта заблакіравана. Каб працягнуць, увядзіце PUK-код. У вас ёсць яшчэ <xliff:g id="_NUMBER_1">%d</xliff:g> спроб, пасля чаго SIM-карта будзе заблакіравана назаўсёды. Звярніцеся да аператара, каб даведацца больш.</item> <item quantity="other">SIM-карта заблакіравана. Каб працягнуць, увядзіце PUK-код. У вас ёсць яшчэ <xliff:g id="_NUMBER_1">%d</xliff:g> спробы, пасля чаго SIM-карта будзе заблакіравана назаўсёды. Звярніцеся да аператара, каб даведацца больш.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Зараз"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Дванаццаць"</item> <item msgid="7389464214252023751">"Адна"</item> diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml index 741834feca3c..d89dd41c0f72 100644 --- a/packages/SystemUI/res-keyguard/values-bg/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM картата вече е деактивирана. Въведете PUK кода, за да продължите. Остават ви <xliff:g id="_NUMBER_1">%d</xliff:g> опита, преди SIM картата да стане неизползваема завинаги. Свържете се с оператора за подробности.</item> <item quantity="one">SIM картата вече е деактивирана. Въведете PUK кода, за да продължите. Остава ви <xliff:g id="_NUMBER_0">%d</xliff:g> опит, преди SIM картата да стане неизползваема завинаги. Свържете се с оператора за подробности.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Часът е"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"дванайсет"</item> <item msgid="7389464214252023751">"един"</item> diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml index 25346a53a049..d0794c3e2995 100644 --- a/packages/SystemUI/res-keyguard/values-bn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">সিম অক্ষম করা হয়েছে। চালিয়ে যেতে PUK কোড লিখুন। আপনি আর <xliff:g id="_NUMBER_1">%d</xliff:g> বার চেষ্টা করতে পারবেন, তারপরে এই সিমটি আর একেবারেই ব্যবহার করা যাবে না। বিশদে জানতে পরিষেবা প্রদানকারীর সাথে যোগাযোগ করুন।</item> <item quantity="other">সিম অক্ষম করা হয়েছে। চালিয়ে যেতে PUK কোড লিখুন। আপনি আর <xliff:g id="_NUMBER_1">%d</xliff:g> বার চেষ্টা করতে পারবেন, তারপরে এই সিমটি আর একেবারেই ব্যবহার করা যাবে না। বিশদে জানতে পরিষেবা প্রদানকারীর সাথে যোগাযোগ করুন।</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"এখন"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"বারো"</item> <item msgid="7389464214252023751">"এক"</item> diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml index 9396ef1ff411..72e4603ba8db 100644 --- a/packages/SystemUI/res-keyguard/values-bs/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml @@ -158,7 +158,7 @@ <item quantity="few">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Za više informacija kontaktirajte mobilnog operatera.</item> <item quantity="other">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Za više informacija kontaktirajte mobilnog operatera.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Sada je"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Dvanaest"</item> <item msgid="7389464214252023751">"Jedan"</item> diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml index 2fa08975cd8a..185a3f3e39ed 100644 --- a/packages/SystemUI/res-keyguard/values-ca/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">La targeta SIM s\'ha desactivat. Introdueix el codi PUK per continuar. Et queden <xliff:g id="_NUMBER_1">%d</xliff:g> intents; si no l\'encertes, la SIM no es podrà tornar a fer servir. Contacta amb l\'operador de telefonia mòbil per obtenir-ne més informació.</item> <item quantity="one">La targeta SIM s\'ha desactivat. Introdueix el codi PUK per continuar. Et queda <xliff:g id="_NUMBER_0">%d</xliff:g> intent; si no l\'encertes, la SIM no es podrà tornar a fer servir. Contacta amb l\'operador de telefonia mòbil per obtenir-ne més informació.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Són les"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"i dotze"</item> <item msgid="7389464214252023751">"Una"</item> diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml index 2708f8f439f8..bb01b7e91852 100644 --- a/packages/SystemUI/res-keyguard/values-cs/strings.xml +++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml @@ -166,7 +166,7 @@ <item quantity="other">SIM karta je teď zablokována. Chcete-li pokračovat, zadejte kód PUK. Máte ještě <xliff:g id="_NUMBER_1">%d</xliff:g> pokusů, poté bude SIM karta natrvalo zablokována. Podrobnosti vám poskytne operátor.</item> <item quantity="one">SIM karta je teď zablokována. Chcete-li pokračovat, zadejte kód PUK. Máte ještě <xliff:g id="_NUMBER_0">%d</xliff:g> pokus, poté bude SIM karta natrvalo zablokována. Podrobnosti vám poskytne operátor.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Je"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Dvanáct"</item> <item msgid="7389464214252023751">"Jedna"</item> diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml index 34c248d5c6f6..fbdaf0f5eb7e 100644 --- a/packages/SystemUI/res-keyguard/values-da/strings.xml +++ b/packages/SystemUI/res-keyguard/values-da/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">SIM-kortet er nu deaktiveret. Angiv PUK-koden for at fortsætte. Du har <xliff:g id="_NUMBER_1">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver permanent ubrugeligt. Kontakt dit mobilselskab for at få flere oplysninger.</item> <item quantity="other">SIM-kortet er nu deaktiveret. Angiv PUK-koden for at fortsætte. Du har <xliff:g id="_NUMBER_1">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver permanent ubrugeligt. Kontakt dit mobilselskab for at få flere oplysninger.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Den er"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Tolv"</item> <item msgid="7389464214252023751">"Et"</item> diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml index d8daf83f34d9..b6127df02f1d 100644 --- a/packages/SystemUI/res-keyguard/values-de/strings.xml +++ b/packages/SystemUI/res-keyguard/values-de/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">Die SIM-Karte ist jetzt deaktiviert. Gib den PUK-Code ein, um fortzufahren. Du hast noch <xliff:g id="_NUMBER_1">%d</xliff:g> Versuche, bevor die SIM-Karte endgültig gesperrt wird. Weitere Informationen erhältst du von deinem Mobilfunkanbieter.</item> <item quantity="one">Die SIM-Karte ist jetzt deaktiviert. Gib den PUK-Code ein, um fortzufahren. Du hast noch <xliff:g id="_NUMBER_0">%d</xliff:g> Versuch, bevor die SIM-Karte endgültig gesperrt wird. Weitere Informationen erhältst du von deinem Mobilfunkanbieter.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Es ist"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"zwölf Uhr"</item> <item msgid="7389464214252023751">"ein Uhr"</item> diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml index 6c0916c1d912..402e29765a3a 100644 --- a/packages/SystemUI/res-keyguard/values-el/strings.xml +++ b/packages/SystemUI/res-keyguard/values-el/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">Η κάρτα SIM απενεργοποιήθηκε. Καταχωρίστε τον κωδικό PUK, για να συνεχίσετε. Απομένουν <xliff:g id="_NUMBER_1">%d</xliff:g> ακόμη προσπάθειες προτού να μην είναι πλέον δυνατή η χρήση της κάρτας SIM. Επικοινωνήστε με την εταιρεία κινητής τηλεφωνίας για λεπτομέρειες.</item> <item quantity="one">Η κάρτα SIM απενεργοποιήθηκε. Καταχωρίστε τον κωδικό PUK, για να συνεχίσετε. Απομένει <xliff:g id="_NUMBER_0">%d</xliff:g> ακόμη προσπάθεια προτού να μην είναι πλέον δυνατή η χρήση της κάρτας SIM. Επικοινωνήστε με την εταιρεία κινητής τηλεφωνίας για λεπτομέρειες.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Είναι"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Δώδεκα"</item> <item msgid="7389464214252023751">"Μία"</item> diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml index 80c9b82e984a..72b8085c9da3 100644 --- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item> <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"It’s"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Twelve"</item> <item msgid="7389464214252023751">"One"</item> diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml index 20c4d56bf2eb..ecc0f71ffcd5 100644 --- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item> <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"It’s"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Twelve"</item> <item msgid="7389464214252023751">"One"</item> diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml index 80c9b82e984a..72b8085c9da3 100644 --- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item> <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"It’s"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Twelve"</item> <item msgid="7389464214252023751">"One"</item> diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml index 80c9b82e984a..72b8085c9da3 100644 --- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item> <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"It’s"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Twelve"</item> <item msgid="7389464214252023751">"One"</item> diff --git a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml index a33d81741256..501dcb755b57 100644 --- a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item> <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact carrier for details.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"It’s"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Twelve"</item> <item msgid="7389464214252023751">"One"</item> diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml index 98453a7c2a79..f93d93305621 100644 --- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml +++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">Se inhabilitó la SIM. Para continuar, ingresa el código PUK. Te quedan <xliff:g id="_NUMBER_1">%d</xliff:g> intentos más antes de que la SIM quede inutilizable permanentemente. Comunícate con tu proveedor para obtener más detalles.</item> <item quantity="one">Se inhabilitó la SIM. Para continuar, ingresa el código PUK. Te queda <xliff:g id="_NUMBER_0">%d</xliff:g> intento más antes de que la SIM quede inutilizable permanentemente. Comunícate con tu proveedor para obtener más detalles.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Son las"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Doce"</item> <item msgid="7389464214252023751">"Una"</item> diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml index 00bdd913a582..9c189d9f1245 100644 --- a/packages/SystemUI/res-keyguard/values-es/strings.xml +++ b/packages/SystemUI/res-keyguard/values-es/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">La tarjeta SIM está inhabilitada. Introduce el código PUK para continuar. Te quedan <xliff:g id="_NUMBER_1">%d</xliff:g> intentos para que la tarjeta SIM quede inservible de forma permanente. Ponte en contacto con tu operador para obtener más información.</item> <item quantity="one">La tarjeta SIM está inhabilitada. Introduce el código PUK para continuar. Te queda <xliff:g id="_NUMBER_0">%d</xliff:g> intento para que la tarjeta SIM quede inservible de forma permanente. Ponte en contacto con tu operador para obtener más información.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Son las"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Doce"</item> <item msgid="7389464214252023751">"Uno"</item> diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml index e77880403b79..759453732db9 100644 --- a/packages/SystemUI/res-keyguard/values-et/strings.xml +++ b/packages/SystemUI/res-keyguard/values-et/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM-kaart on nüüd keelatud. Jätkamiseks sisestage PUK-kood. Teil on jäänud veel <xliff:g id="_NUMBER_1">%d</xliff:g> katset enne, kui SIM-kaart püsivalt lukustatakse. Lisateavet küsige operaatorilt.</item> <item quantity="one">SIM-kaart on nüüd keelatud. Jätkamiseks sisestage PUK-kood. Teil on jäänud veel <xliff:g id="_NUMBER_0">%d</xliff:g> katse enne, kui SIM-kaart püsivalt lukustatakse. Lisateavet küsige operaatorilt.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Kell on"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Kaksteist"</item> <item msgid="7389464214252023751">"Üks"</item> diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml index 3ebb536d0394..8b1284d7c535 100644 --- a/packages/SystemUI/res-keyguard/values-eu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">Desgaitu egin da SIM txartela. Aurrera egiteko, idatzi PUK kodea. <xliff:g id="_NUMBER_1">%d</xliff:g> saiakera geratzen zaizkizu SIM txartela betiko erabilgaitz geratu aurretik. Xehetasunak lortzeko, jarri operadorearekin harremanetan.</item> <item quantity="one">Desgaitu egin da SIM txartela. Aurrera egiteko, idatzi PUK kodea. <xliff:g id="_NUMBER_0">%d</xliff:g> saiakera geratzen zaizu SIM txartela betiko erabilgaitz geratu aurretik. Xehetasunak lortzeko, jarri operadorearekin harremanetan.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Ordua:"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Hamabiak"</item> <item msgid="7389464214252023751">"Ordu bata"</item> diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml index 0c30d03cc14c..183152e37ff8 100644 --- a/packages/SystemUI/res-keyguard/values-fa/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">سیمکارت اکنون غیرفعال است. برای ادامه دادن کد PUK را وارد کنید. <xliff:g id="_NUMBER_1">%d</xliff:g> تلاش دیگر باقی مانده است و پس از آن سیمکارت برای همیشه غیرقابلاستفاده میشود. برای اطلاع از جزئیات با شرکت مخابراتی تماس بگیرید.</item> <item quantity="other">سیمکارت اکنون غیرفعال است. برای ادامه دادن کد PUK را وارد کنید. <xliff:g id="_NUMBER_1">%d</xliff:g> تلاش دیگر باقی مانده است و پس از آن سیمکارت برای همیشه غیرقابلاستفاده میشود. برای اطلاع از جزئیات با شرکت مخابراتی تماس بگیرید.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"ساعت:"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"دوازده"</item> <item msgid="7389464214252023751">"یک"</item> diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml index 60923722fa56..ec3c596f31bf 100644 --- a/packages/SystemUI/res-keyguard/values-fi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM-kortti on nyt lukittu. Anna PUK-koodi, niin voit jatkaa. Sinulla on <xliff:g id="_NUMBER_1">%d</xliff:g> yritystä jäljellä, ennen kuin SIM-kortti poistuu pysyvästi käytöstä. Pyydä lisätietoja operaattoriltasi.</item> <item quantity="one">SIM-kortti on nyt lukittu. Anna PUK-koodi, niin voit jatkaa. Sinulla on <xliff:g id="_NUMBER_0">%d</xliff:g> yritys jäljellä, ennen kuin SIM-kortti poistuu pysyvästi käytöstä. Pyydä lisätietoja operaattoriltasi.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Kello on"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Kaksitoista"</item> <item msgid="7389464214252023751">"Yksi"</item> diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml index 8e92ffc91db6..73705c876091 100644 --- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM devienne définitivement inutilisable. Pour obtenir plus de détails, communiquez avec votre fournisseur de services.</item> <item quantity="other">La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM devienne définitivement inutilisable. Pour obtenir plus de détails, communiquez avec votre fournisseur de services.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Il est"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"douze h."</item> <item msgid="7389464214252023751">"Une h."</item> diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml index cde5e682224f..cf4f2d001d83 100644 --- a/packages/SystemUI/res-keyguard/values-fr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">La carte SIM est maintenant désactivée. Saisissez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM ne devienne définitivement inutilisable. Pour de plus amples informations, veuillez contacter votre opérateur.</item> <item quantity="other">La carte SIM est maintenant désactivée. Saisissez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM ne devienne définitivement inutilisable. Pour de plus amples informations, veuillez contacter votre opérateur.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Il est"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"douze heures"</item> <item msgid="7389464214252023751">"une heure"</item> diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml index 6d85cdba5ce3..810a75ba034b 100644 --- a/packages/SystemUI/res-keyguard/values-gl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">A SIM está desactivada. Introduce o código PUK para continuar. Quédanche <xliff:g id="_NUMBER_1">%d</xliff:g> intentos antes de que a SIM quede inutilizable para sempre. Contacta co operador para obter información.</item> <item quantity="one">A SIM está desactivada. Introduce o código PUK para continuar. Quédache <xliff:g id="_NUMBER_0">%d</xliff:g> intento antes de que a SIM quede inutilizable para sempre. Contacta co operador para obter información.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Hora:"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Doce"</item> <item msgid="7389464214252023751">"Unha"</item> diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml index d9fdf03d4a17..538b10081a83 100644 --- a/packages/SystemUI/res-keyguard/values-gu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">સિમ હવે બંધ કરેલ છે. ચાલુ રાખવા માટે PUK કોડ દાખલ કરો. સિમ કાયમીરૂપે બિનઉપયોગી બની જાય એ પહેલાં તમારી પાસે <xliff:g id="_NUMBER_1">%d</xliff:g> પ્રયાસ બાકી છે. વિગતો માટે કૅરિઅરનો સંપર્ક કરો.</item> <item quantity="other">સિમ હવે બંધ કરેલ છે. ચાલુ રાખવા માટે PUK કોડ દાખલ કરો. સિમ કાયમીરૂપે બિનઉપયોગી બની જાય એ પહેલાં તમારી પાસે <xliff:g id="_NUMBER_1">%d</xliff:g> પ્રયાસો બાકી છે. વિગતો માટે કૅરિઅરનો સંપર્ક કરો.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"સમય છે"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"બાર"</item> <item msgid="7389464214252023751">"એક"</item> diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml index b004cdec4045..f03ddd44cb3b 100644 --- a/packages/SystemUI/res-keyguard/values-hi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">सिम बंद कर दिया गया है. जारी रखने के लिए PUK कोड डालें. आपके पास <xliff:g id="_NUMBER_1">%d</xliff:g> मौके बचे हैं, उसके बाद, सिम हमेशा के लिए काम करना बंद कर देगा. जानकारी के लिए, मोबाइल और इंटरनेट सेवा देने वाली कंपनी से संपर्क करें.</item> <item quantity="other">सिम बंद कर दिया गया है. जारी रखने के लिए PUK कोड डालें. आपके पास <xliff:g id="_NUMBER_1">%d</xliff:g> मौके बचे हैं, उसके बाद, सिम हमेशा के लिए काम करना बंद कर देगा. जानकारी के लिए, मोबाइल और इंटरनेट सेवा देने वाली कंपनी से संपर्क करें.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"यह"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"बारह"</item> <item msgid="7389464214252023751">"एक"</item> diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml index c99b646b7682..28394538d8bb 100644 --- a/packages/SystemUI/res-keyguard/values-hr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml @@ -158,7 +158,7 @@ <item quantity="few">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Više informacija zatražite od mobilnog operatera.</item> <item quantity="other">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Više informacija zatražite od mobilnog operatera.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Sada je"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Dvanaest"</item> <item msgid="7389464214252023751">"Jedan"</item> diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml index 4eb8bc886d0d..de22c02df0df 100644 --- a/packages/SystemUI/res-keyguard/values-hu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">A SIM-kártya le van tiltva. A folytatáshoz adja meg a PUK-kódot. Még <xliff:g id="_NUMBER_1">%d</xliff:g> próbálkozása van, mielőtt végleg használhatatlanná válik a SIM-kártya. További információért forduljon a szolgáltatóhoz.</item> <item quantity="one">A SIM-kártya le van tiltva. A folytatáshoz adja meg a PUK-kódot. Még <xliff:g id="_NUMBER_0">%d</xliff:g> próbálkozása van, mielőtt végleg használhatatlanná válik a SIM-kártya. További információért forduljon a szolgáltatóhoz.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Az idő:"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Tizenkettő"</item> <item msgid="7389464214252023751">"Egy"</item> diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml index 5d9a2c0c3fcf..2c104371faa5 100644 --- a/packages/SystemUI/res-keyguard/values-hy/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">SIM քարտն անջատված է: Շարունակելու համար մուտքագրեք PUK կոդը: Մնացել է <xliff:g id="_NUMBER_1">%d</xliff:g> փորձ, որից հետո SIM քարտն այլևս հնարավոր չի լինի օգտագործել: Մանրամասների համար դիմեք օպերատորին:</item> <item quantity="other">SIM քարտն անջատված է: Շարունակելու համար մուտքագրեք PUK կոդը: Մնացել է <xliff:g id="_NUMBER_1">%d</xliff:g> փորձ, որից հետո SIM քարտն այլևս հնարավոր չի լինի օգտագործել: Մանրամասների համար դիմեք օպերատորին:</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Ժամն է՝"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"տասներկու"</item> <item msgid="7389464214252023751">"մեկ"</item> diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml index 603b4c25e9d0..0cd138250fad 100644 --- a/packages/SystemUI/res-keyguard/values-in/strings.xml +++ b/packages/SystemUI/res-keyguard/values-in/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM kini dinonaktifkan. Masukkan kode PUK untuk melanjutkan. Tersisa <xliff:g id="_NUMBER_1">%d</xliff:g> percobaan sebelum SIM tidak dapat digunakan secara permanen. Hubungi operator untuk mengetahui detailnya.</item> <item quantity="one">SIM kini dinonaktifkan. Masukkan kode PUK untuk melanjutkan. Tersisa <xliff:g id="_NUMBER_0">%d</xliff:g> percobaan sebelum SIM tidak dapat digunakan secara permanen. Hubungi operator untuk mengetahui detailnya.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Pukul"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Dua Belas"</item> <item msgid="7389464214252023751">"Satu"</item> diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml index 71f2078a6010..dd9785d976a4 100644 --- a/packages/SystemUI/res-keyguard/values-is/strings.xml +++ b/packages/SystemUI/res-keyguard/values-is/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">SIM-kortið er nú óvirkt. Sláðu inn PUK-númer til að halda áfram. Það er <xliff:g id="_NUMBER_1">%d</xliff:g> tilraun eftir þar til SIM-kortið verður ónothæft til frambúðar. Hafðu samband við símafyrirtækið til að fá upplýsingar.</item> <item quantity="other">SIM-kortið er nú óvirkt. Sláðu inn PUK-númer til að halda áfram. Það eru <xliff:g id="_NUMBER_1">%d</xliff:g> tilraunir eftir þar til SIM-kortið verður ónothæft til frambúðar. Hafðu samband við símafyrirtækið til að fá upplýsingar.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Hún er"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Tólf"</item> <item msgid="7389464214252023751">"Eitt"</item> diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml index e0b55b37fe23..ac2375fd8c34 100644 --- a/packages/SystemUI/res-keyguard/values-it/strings.xml +++ b/packages/SystemUI/res-keyguard/values-it/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.</item> <item quantity="one">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Ora"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Dodici"</item> <item msgid="7389464214252023751">"Una"</item> diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml index 509c4637ab92..0fadaffa5c9e 100644 --- a/packages/SystemUI/res-keyguard/values-iw/strings.xml +++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml @@ -166,7 +166,7 @@ <item quantity="other">כרטיס ה-SIM מושבת כעת. יש להזין קוד PUK כדי להמשיך. נותרו לך <xliff:g id="_NUMBER_1">%d</xliff:g> ניסיונות נוספים לפני שכרטיס ה-SIM ינעל לצמיתות. למידע נוסף, ניתן לפנות לספק שלך.</item> <item quantity="one">כרטיס ה-SIM מושבת כעת. יש להזין קוד PUK כדי להמשיך. נותר לך <xliff:g id="_NUMBER_0">%d</xliff:g> ניסיון נוסף לפני שכרטיס ה-SIM ינעל לצמיתות. למידע נוסף, ניתן לפנות לספק שלך.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"השעה"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"שתים-עשרה"</item> <item msgid="7389464214252023751">"אחת"</item> diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml index 343d557e50c7..b0514ef4d741 100644 --- a/packages/SystemUI/res-keyguard/values-ja/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM が無効になりました。続行するには PUK コードを入力してください。入力できるのはあと <xliff:g id="_NUMBER_1">%d</xliff:g> 回です。この回数を超えると SIM は完全に使用できなくなります。詳しくは携帯通信会社にお問い合わせください。</item> <item quantity="one">SIM が無効になりました。続行するには PUK コードを入力してください。入力できるのはあと <xliff:g id="_NUMBER_0">%d</xliff:g> 回です。この回数を超えると SIM は完全に使用できなくなります。詳しくは携帯通信会社にお問い合わせください。</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"時刻:"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"12"</item> <item msgid="7389464214252023751">"1"</item> diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml index 9118e5666d5b..9290874557df 100644 --- a/packages/SystemUI/res-keyguard/values-ka/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM ბარათი ახლა დეაქტივირებულია. გასაგრძელებლად შეიყვანეთ PUK-კოდი. თქვენ დაგრჩათ <xliff:g id="_NUMBER_1">%d</xliff:g> მცდელობა, სანამ SIM სამუდამოდ გამოუსადეგარი გახდება. დეტალური ინფორმაციისთვის დაუკავშირდით თქვენს ოპერატორს.</item> <item quantity="one">SIM ბარათი ახლა დეაქტივირებულია. გასაგრძელებლად შეიყვანეთ PUK-კოდი. თქვენ დაგრჩათ <xliff:g id="_NUMBER_0">%d</xliff:g> მცდელობა, სანამ SIM სამუდამოდ გამოუსადეგარი გახდება. დეტალური ინფორმაციისთვის დაუკავშირდით თქვენს ოპერატორს.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"ახლაა"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"თორმეტი"</item> <item msgid="7389464214252023751">"ერთი"</item> diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml index 2270c92da0aa..f1d64499ac45 100644 --- a/packages/SystemUI/res-keyguard/values-kk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM картасы өшірілді. Жалғастыру үшін PUK кодын енгізіңіз. <xliff:g id="_NUMBER_1">%d</xliff:g> мүмкіндік қалды, одан кейін SIM картасы біржола құлыпталады. Толығырақ мәліметті оператордан алыңыз.</item> <item quantity="one">SIM картасы өшірілді. Жалғастыру үшін PUK кодын енгізіңіз. <xliff:g id="_NUMBER_0">%d</xliff:g> мүмкіндік қалды, одан кейін SIM картасы біржола құлыпталады. Толығырақ мәліметті оператордан алыңыз.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Қазір"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Он екі"</item> <item msgid="7389464214252023751">"Бір"</item> diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml index 80b124ad47de..f4795b6e79dd 100644 --- a/packages/SystemUI/res-keyguard/values-km/strings.xml +++ b/packages/SystemUI/res-keyguard/values-km/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">ឥឡូវនេះស៊ីមត្រូវបានបិទ។ សូមបញ្ចូលកូដ PUK ដើម្បីបន្ត។ អ្នកនៅសល់ការព្យាយាម <xliff:g id="_NUMBER_1">%d</xliff:g> ដងទៀតមុនពេលស៊ីមមិនអាចប្រើបានជាអចិន្ត្រៃយ៍។ ទាក់ទងទៅក្រុមហ៊ុនសេវាទូរសព្ទសម្រាប់ព័ត៌មានលម្អិត។</item> <item quantity="one">ឥឡូវនេះស៊ីមត្រូវបានបិទ។ សូមបញ្ចូលកូដ PUK ដើម្បីបន្ត។ អ្នកនៅសល់ការព្យាយាម <xliff:g id="_NUMBER_0">%d</xliff:g> ដងទៀតមុនពេលស៊ីមមិនអាចប្រើបានជាអចិន្ត្រៃយ៍។ ទាក់ទងទៅក្រុមហ៊ុនសេវាទូរសព្ទសម្រាប់ព័ត៌មានលម្អិត។</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"វាជា"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"ដប់ពីរ"</item> <item msgid="7389464214252023751">"មួយ"</item> diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml index f48d6060b2a6..6f83dde04176 100644 --- a/packages/SystemUI/res-keyguard/values-kn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">ಸಿಮ್ ಅನ್ನು ಈಗ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ. ಮುಂದುವರಿಸಲು PUK ಕೋಡ್ ನಮೂದಿಸಿ. ಸಿಮ್ ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಪ್ರಯೋಜಕವಾಗುವ ಮುನ್ನ ನಿಮ್ಮಲ್ಲಿ <xliff:g id="_NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ. ವಿವರಗಳಿಗಾಗಿ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಿ.</item> <item quantity="other">ಸಿಮ್ ಅನ್ನು ಈಗ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ. ಮುಂದುವರಿಸಲು PUK ಕೋಡ್ ನಮೂದಿಸಿ. ಸಿಮ್ ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಪ್ರಯೋಜಕವಾಗುವ ಮುನ್ನ ನಿಮ್ಮಲ್ಲಿ <xliff:g id="_NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ. ವಿವರಗಳಿಗಾಗಿ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಿ.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"ಇದು"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"ಹನ್ನೆರಡು"</item> <item msgid="7389464214252023751">"ಒಂದು"</item> diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml index 046600911eae..1651be742a3d 100644 --- a/packages/SystemUI/res-keyguard/values-ko/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM이 사용 중지되었습니다. 계속하려면 PUK 코드를 입력하세요. <xliff:g id="_NUMBER_1">%d</xliff:g>번 더 실패하면 SIM을 완전히 사용할 수 없게 됩니다. 자세한 내용은 이동통신사에 문의하세요.</item> <item quantity="one">SIM이 사용 중지되었습니다. 계속하려면 PUK 코드를 입력하세요. <xliff:g id="_NUMBER_0">%d</xliff:g>번 더 실패하면 SIM을 완전히 사용할 수 없게 됩니다. 자세한 내용은 이동통신사에 문의하세요.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"현재 시각:"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"열두 시"</item> <item msgid="7389464214252023751">"한 시"</item> diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml index eca9b2214b96..6d0f2ff635dd 100644 --- a/packages/SystemUI/res-keyguard/values-ky/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM-карта азыр жарактан чыкты. Улантуу үчүн PUK-кодду киргизиңиз. SIM-картанын биротоло жарактан чыгарына <xliff:g id="_NUMBER_1">%d</xliff:g> аракет калды. Чоо-жайын билүү үчүн байланыш операторуна кайрылыңыз.</item> <item quantity="one">SIM-карта азыр жарактан чыкты. Улантуу үчүн PUK-кодду киргизиңиз. SIM-картанын биротоло жарактан чыгаарына <xliff:g id="_NUMBER_0">%d</xliff:g> аракет калды. Чоо-жайын билүү үчүн байланыш операторуна кайрылыңыз.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Саат"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Он эки"</item> <item msgid="7389464214252023751">"Бир"</item> diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml index bd6e53df924b..23f179e049d4 100644 --- a/packages/SystemUI/res-keyguard/values-lo/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">ຕອນນີ້ປິດການນຳໃຊ້ SIM ແລ້ວ. ໃສ່ລະຫັດ PUK ເພື່ອດຳເນີນການຕໍ່. ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="_NUMBER_1">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຈະບໍ່ສາມາດໃຊ້ໄດ້ຖາວອນ. ກະລຸນາຕິດຕໍ່ຜູ້ໃຫ້ບໍລິການສຳລັບລາຍລະອຽດ.</item> <item quantity="one">ຕອນນີ້ປິດການນຳໃຊ້ SIM ແລ້ວ. ໃສ່ລະຫັດ PUK ເພື່ອດຳເນີນການຕໍ່. ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="_NUMBER_0">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຈະບໍ່ສາມາດໃຊ້ໄດ້ຖາວອນ. ກະລຸນາຕິດຕໍ່ຜູ້ໃຫ້ບໍລິການສຳລັບລາຍລະອຽດ.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"ມັນແມ່ນ"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"ສິບສອງ"</item> <item msgid="7389464214252023751">"ໜຶ່ງ"</item> diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml index 6df93d8d4838..9e4d169129bc 100644 --- a/packages/SystemUI/res-keyguard/values-lt/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml @@ -166,7 +166,7 @@ <item quantity="many">SIM kortelė dabar yra išjungta. Jei norite tęsti, įveskite PUK kodą. Jums liko <xliff:g id="_NUMBER_1">%d</xliff:g> bandymo. Paskui visiškai nebegalėsite naudoti SIM kortelės. Jei reikia išsamios informacijos, susisiekite su operatoriumi.</item> <item quantity="other">SIM kortelė dabar yra išjungta. Jei norite tęsti, įveskite PUK kodą. Jums liko <xliff:g id="_NUMBER_1">%d</xliff:g> bandymų. Paskui visiškai nebegalėsite naudoti SIM kortelės. Jei reikia išsamios informacijos, susisiekite su operatoriumi.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Dabar"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Dvylika"</item> <item msgid="7389464214252023751">"Pirma"</item> diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml index d9061763e083..9ea4143f2e6e 100644 --- a/packages/SystemUI/res-keyguard/values-lv/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml @@ -158,7 +158,7 @@ <item quantity="one">SIM karte tagad ir atspējota. Ievadiet PUK kodu, lai turpinātu. Varat mēģināt vēl <xliff:g id="_NUMBER_1">%d</xliff:g> reizi. Kļūdas gadījumā SIM karti vairs nevarēs izmantot. Lai iegūtu detalizētu informāciju, sazinieties ar mobilo sakaru operatoru.</item> <item quantity="other">SIM karte tagad ir atspējota. Ievadiet PUK kodu, lai turpinātu. Varat mēģināt vēl <xliff:g id="_NUMBER_1">%d</xliff:g> reizes. Kļūdas gadījumā SIM karti vairs nevarēs izmantot. Lai iegūtu detalizētu informāciju, sazinieties ar mobilo sakaru operatoru.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Laiks:"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Divpadsmit"</item> <item msgid="7389464214252023751">"Viens"</item> diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml index 221b99748291..e48b93d4fb46 100644 --- a/packages/SystemUI/res-keyguard/values-mk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">SIM-картичката сега е оневозможена. Внесете PUK-код за да продолжите. Ви преостанува уште <xliff:g id="_NUMBER_1">%d</xliff:g> обид пред SIM-картичката да стане трајно неупотреблива. Контактирајте го операторот за детали.</item> <item quantity="other">SIM-картичката сега е оневозможена. Внесете PUK-код за да продолжите. Ви преостануваат уште <xliff:g id="_NUMBER_1">%d</xliff:g> обиди пред SIM-картичката да стане трајно неупотреблива. Контактирајте го операторот за детали.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Сега е"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Дванаесет"</item> <item msgid="7389464214252023751">"Еден"</item> diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml index e6642884b343..37ce00710b3f 100644 --- a/packages/SystemUI/res-keyguard/values-ml/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">സിം ഇപ്പോൾ പ്രവർത്തനരഹിതമാക്കി. തുടരുന്നതിന് PUK കോഡ് നൽകുക. സിം ശാശ്വതമായി ഉപയോഗശൂന്യമാകുന്നതിന് മുമ്പായി <xliff:g id="_NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി ശേഷിക്കുന്നു. വിശദാംശങ്ങൾക്ക് കാരിയറുമായി ബന്ധപ്പെടുക.</item> <item quantity="one">സിം ഇപ്പോൾ പ്രവർത്തനരഹിതമാക്കി. തുടരുന്നതിന് PUK കോഡ് നൽകുക. സിം ശാശ്വതമായി ഉപയോഗശൂന്യമാകുന്നതിന് മുമ്പായി <xliff:g id="_NUMBER_0">%d</xliff:g> ശ്രമം കൂടി ശേഷിക്കുന്നു. വിശദാംശങ്ങൾക്ക് കാരിയറുമായി ബന്ധപ്പെടുക.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"സമയം"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"പന്ത്രണ്ട്"</item> <item msgid="7389464214252023751">"ഒന്ന്"</item> diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml index e4187316143a..86da6889249a 100644 --- a/packages/SystemUI/res-keyguard/values-mn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM-г идэвхгүй болголоо. Үргэлжлүүлэхийн тулд PUK кодыг оруулна уу. Таны SIM бүрмөсөн хүчингүй болох хүртэл <xliff:g id="_NUMBER_1">%d</xliff:g> оролдлого үлдлээ. Дэлгэрэнгүй мэдээлэл авахын тулд оператор компанитайгаа холбогдоно уу.</item> <item quantity="one">SIM-г идэвхгүй болголоо. Үргэлжлүүлэхийн тулд PUK кодыг оруулна уу. Таны SIM бүрмөсөн хүчингүй болох хүртэл <xliff:g id="_NUMBER_0">%d</xliff:g> оролдлого үлдлээ. Дэлгэрэнгүй мэдээлэл авахын тулд оператор компанитайгаа холбогдоно уу.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Одоо"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Арван хоёр"</item> <item msgid="7389464214252023751">"Нэг"</item> diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml index 9d83e93b5e68..ea0c0bb7737d 100644 --- a/packages/SystemUI/res-keyguard/values-mr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">सिम आता बंद केलेले आहे. सुरू ठेवण्यासाठी PUK कोड टाका. सिम कायमचे बंद होण्याआधी तुमच्याकडे <xliff:g id="_NUMBER_1">%d</xliff:g> प्रयत्न शिल्लक आहे. तपशीलांसाठी वाहकाशी संपर्क साधा.</item> <item quantity="other">सिम आता बंद केलेले आहे. सुरू ठेवण्यासाठी PUK कोड टाका. सिम कायमचे बंद होण्याआधी तुमच्याकडे <xliff:g id="_NUMBER_1">%d</xliff:g> प्रयत्न शिल्लक आहेत. तपशीलांसाठी वाहकाशी संपर्क साधा.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"हे आहे"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"बारा"</item> <item msgid="7389464214252023751">"एक"</item> diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml index 1c82f7c1bda6..03dca91c5d4e 100644 --- a/packages/SystemUI/res-keyguard/values-ms/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">Kini SIM dilumpuhkan. Masukkan kod PUK untuk meneruskan. Tinggal <xliff:g id="_NUMBER_1">%d</xliff:g> percubaan sebelum SIM tidak boleh digunakan secara kekal. Hubungi pembawa untuk mendapatkan butiran.</item> <item quantity="one">Kini SIM dilumpuhkan. Masukkan kod PUK untuk meneruskan. Tinggal <xliff:g id="_NUMBER_0">%d</xliff:g> percubaan sebelum SIM tidak boleh digunakan secara kekal. Hubungi pembawa untuk mendapatkan butiran.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Pukul"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Dua bls"</item> <item msgid="7389464214252023751">"Satu"</item> diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml index efdd779beae6..a468a852d787 100644 --- a/packages/SystemUI/res-keyguard/values-my/strings.xml +++ b/packages/SystemUI/res-keyguard/values-my/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">ဆင်းမ်ကဒ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် PUK ကုဒ်ကို ထည့်ပါ။ ဆင်းမ်ကဒ် အပြီးပိတ်မသွားမီ သင့်တွင် <xliff:g id="_NUMBER_1">%d</xliff:g> ကြိမ် စမ်းသပ်ခွင့် ကျန်ပါသေးသည်။ အသေးစိတ်အချက်များအတွက် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ပါ။</item> <item quantity="one">ဆင်းမ်ကဒ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် PUK ကုဒ်ကို ထည့်ပါ။ ဆင်းမ်ကဒ် အပြီးပိတ်မသွားမီ သင့်တွင် <xliff:g id="_NUMBER_0">%d</xliff:g> ကြိမ် စမ်းသပ်ခွင့် ကျန်ပါသေးသည်။ အသေးစိတ်အချက်များအတွက် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ပါ။</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"ယခု"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"ဆယ့်နှစ်"</item> <item msgid="7389464214252023751">"တစ်"</item> diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml index 17704c4402d2..fcf06eb7b543 100644 --- a/packages/SystemUI/res-keyguard/values-nb/strings.xml +++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM-kortet er deaktivert nå. Skriv inn PUK-koden for å fortsette. Du har <xliff:g id="_NUMBER_1">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig. Kontakt operatøren for å få vite mer.</item> <item quantity="one">SIM-kortet er deaktivert nå. Skriv inn PUK-koden for å fortsette. Du har <xliff:g id="_NUMBER_0">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig. Kontakt operatøren for å få vite mer.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Klokken"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Tolv"</item> <item msgid="7389464214252023751">"Ett"</item> diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml index 77bc11337672..c3d92ab18a15 100644 --- a/packages/SystemUI/res-keyguard/values-ne/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM लाई असक्षम पारिएको छ। जारी राख्न PUK कोड प्रविष्टि गर्नुहोस्। तपाईंसँग <xliff:g id="_NUMBER_1">%d</xliff:g> प्रयासहरू बाँकी छन्, त्यसपछि SIM सदाका लागि प्रयोग गर्न नमिल्ने हुन्छ। विवरणहरूका लागि सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।</item> <item quantity="one">SIM लाई असक्षम पारिएको छ। जारी राख्न PUK कोड प्रविष्टि गर्नुहोस्। तपाईंसँग <xliff:g id="_NUMBER_0">%d</xliff:g> प्रयास बाँकी छ, त्यसपछि SIM सदाका लागि प्रयोग गर्न नमिल्ने हुन्छ। विवरणहरूका लागि सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"समय:"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"बाह्र"</item> <item msgid="7389464214252023751">"एक"</item> diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml index 3bbbb53e2a6b..b3d65bb7e9b4 100644 --- a/packages/SystemUI/res-keyguard/values-nl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">De simkaart is nu uitgeschakeld. Geef de pukcode op om door te gaan. Je hebt nog <xliff:g id="_NUMBER_1">%d</xliff:g> pogingen over voordat de simkaart definitief onbruikbaar wordt. Neem contact op met je provider voor meer informatie.</item> <item quantity="one">De simkaart is nu uitgeschakeld. Geef de pukcode op om door te gaan. Je hebt nog <xliff:g id="_NUMBER_0">%d</xliff:g> poging over voordat de simkaart definitief onbruikbaar wordt. Neem contact op met je provider voor meer informatie.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Het is"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Twaalf"</item> <item msgid="7389464214252023751">"Eén"</item> diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml index 0db20aa6881a..94c42c4ccf79 100644 --- a/packages/SystemUI/res-keyguard/values-or/strings.xml +++ b/packages/SystemUI/res-keyguard/values-or/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM କାର୍ଡକୁ ବର୍ତ୍ତମାନ ଅକ୍ଷମ କରିଦିଆଯାଇଛି। ଜାରି ରଖିବାକୁ PUK କୋଡ୍ ଲେଖନ୍ତୁ। ଆଉ <xliff:g id="_NUMBER_1">%d</xliff:g> ଥର ଭୁଲ କୋଡ୍ ଲେଖିବା ପରେ SIM କାର୍ଡ ସ୍ଥାୟୀ ଭାବେ ଅନୁପଯୋଗୀ ହୋଇଯିବ। ବିବରଣୀ ପାଇଁ କେରିଅର୍ର ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।</item> <item quantity="one">SIM କାର୍ଡକୁ ବର୍ତ୍ତମାନ ଅକ୍ଷମ କରିଦିଆଯାଇଛି। ଜାରି ରଖିବାକୁ PUK କୋଡ୍ ଲେଖନ୍ତୁ। ଆଉ <xliff:g id="_NUMBER_0">%d</xliff:g> ଥର ଭୁଲ କୋଡ୍ ଲେଖିବା ପରେ SIM କାର୍ଡ ସ୍ଥାୟୀ ଭାବେ ଅନୁପଯୋଗୀ ହୋଇଯିବ। ବିବରଣୀ ପାଇଁ କେରିଅର୍ର ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"ଏବେ"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"ବାର"</item> <item msgid="7389464214252023751">"ଏକ"</item> diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml index 9fd9b197c25e..9b4e28d36ecc 100644 --- a/packages/SystemUI/res-keyguard/values-pa/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">ਸਿਮ ਹੁਣ ਬੰਦ ਹੋ ਗਿਆ ਹੈ। ਜਾਰੀ ਰੱਖਣ ਲਈ PUK ਕੋਡ ਦਾਖਲ ਕਰੋ। ਸਿਮ ਦੇ ਪੱਕੇ ਤੌਰ \'ਤੇ ਬੇਕਾਰ ਹੋ ਜਾਣ ਤੋਂ ਪਹਿਲਾਂ ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="_NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ ਬਾਕੀ ਹੈ। ਵੇਰਵਿਆਂ ਲਈ ਕੈਰੀਅਰ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।</item> <item quantity="other">ਸਿਮ ਹੁਣ ਬੰਦ ਹੋ ਗਿਆ ਹੈ। ਜਾਰੀ ਰੱਖਣ ਲਈ PUK ਕੋਡ ਦਾਖਲ ਕਰੋ। ਸਿਮ ਦੇ ਪੱਕੇ ਤੌਰ \'ਤੇ ਬੇਕਾਰ ਹੋ ਜਾਣ ਤੋਂ ਪਹਿਲਾਂ ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="_NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਕੀ ਹਨ। ਵੇਰਵਿਆਂ ਲਈ ਕੈਰੀਅਰ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"ਸਮਾਂ"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"ਬਾਰਾਂ"</item> <item msgid="7389464214252023751">"ਇੱਕ"</item> diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml index 106fab363270..229443089359 100644 --- a/packages/SystemUI/res-keyguard/values-pl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml @@ -166,7 +166,7 @@ <item quantity="other">Karta SIM została wyłączona. Wpisz kod PUK, by przejść dalej. Masz jeszcze <xliff:g id="_NUMBER_1">%d</xliff:g> próby, zanim karta SIM zostanie trwale zablokowana. Aby uzyskać szczegółowe informacje, skontaktuj się z operatorem.</item> <item quantity="one">Karta SIM została wyłączona. Wpisz kod PUK, by przejść dalej. Masz jeszcze <xliff:g id="_NUMBER_0">%d</xliff:g> próbę, zanim karta SIM zostanie trwale zablokowana. Aby uzyskać szczegółowe informacje, skontaktuj się z operatorem.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Jest"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Dwanaście"</item> <item msgid="7389464214252023751">"Jeden"</item> diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml index 3c6a37252ba0..56815ca95d19 100644 --- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativa restante antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item> <item quantity="other">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas restantes antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"São"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Doze"</item> <item msgid="7389464214252023751">"Uma"</item> diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml index 4f601878e958..4e09dc79d237 100644 --- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item> <item quantity="one">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"São"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Doze"</item> <item msgid="7389464214252023751">"Google One"</item> diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml index 3c6a37252ba0..56815ca95d19 100644 --- a/packages/SystemUI/res-keyguard/values-pt/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativa restante antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item> <item quantity="other">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas restantes antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"São"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Doze"</item> <item msgid="7389464214252023751">"Uma"</item> diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml index 9e4170ec3d6b..23be62ca44f1 100644 --- a/packages/SystemUI/res-keyguard/values-ro/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml @@ -158,7 +158,7 @@ <item quantity="other">Cardul SIM este dezactivat acum. Introduceți codul PUK pentru a continua. V-au mai rămas <xliff:g id="_NUMBER_1">%d</xliff:g> de încercări până când cardul SIM va deveni inutilizabil definitiv. Contactați operatorul pentru detalii.</item> <item quantity="one">Cardul SIM este dezactivat acum. Introduceți codul PUK pentru a continua. V-a mai rămas <xliff:g id="_NUMBER_0">%d</xliff:g> încercare până când cardul SIM va deveni inutilizabil definitiv. Contactați operatorul pentru detalii.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Este"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Douăsprezece"</item> <item msgid="7389464214252023751">"Unu"</item> diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml index dd9bc6a80e4d..f093748d852d 100644 --- a/packages/SystemUI/res-keyguard/values-ru/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml @@ -166,7 +166,7 @@ <item quantity="many">SIM-карта отключена. Чтобы продолжить, введите PUK-код. Осталось <xliff:g id="_NUMBER_1">%d</xliff:g> попыток. После этого SIM-карта будет заблокирована навсегда. За подробной информацией обратитесь к оператору связи.</item> <item quantity="other">SIM-карта отключена. Чтобы продолжить, введите PUK-код. Осталось <xliff:g id="_NUMBER_1">%d</xliff:g> попытки. После этого SIM-карта будет заблокирована навсегда. За подробной информацией обратитесь к оператору связи.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Сейчас"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"двенадцать"</item> <item msgid="7389464214252023751">"один"</item> diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml index 59d2a067bd40..17122a575612 100644 --- a/packages/SystemUI/res-keyguard/values-si/strings.xml +++ b/packages/SystemUI/res-keyguard/values-si/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">SIM දැන් අබල කර ඇත. දිගටම කරගෙන යාමට PUK කේතය ඇතුළු කරන්න. SIM ස්ථිරවම භාවිත කළ නොහැකි බවට පත් වීමට පෙර ඔබ සතුව උත්සාහයන් <xliff:g id="_NUMBER_1">%d</xliff:g>ක් ඉතිරිව ඇත. විස්තර සඳහා වාහක සම්බන්ධ කර ගන්න.</item> <item quantity="other">SIM දැන් අබල කර ඇත. දිගටම කරගෙන යාමට PUK කේතය ඇතුළු කරන්න. SIM ස්ථිරවම භාවිත කළ නොහැකි බවට පත් වීමට පෙර ඔබ සතුව උත්සාහයන් <xliff:g id="_NUMBER_1">%d</xliff:g>ක් ඉතිරිව ඇත. විස්තර සඳහා වාහක සම්බන්ධ කර ගන්න.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"ඒ"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"දොළහ"</item> <item msgid="7389464214252023751">"එක"</item> diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml index 0cd5f78ece65..c9919033af61 100644 --- a/packages/SystemUI/res-keyguard/values-sk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml @@ -166,7 +166,7 @@ <item quantity="other">SIM karta je deaktivovaná. Pokračujte zadaním kódu PUK. Zostáva vám <xliff:g id="_NUMBER_1">%d</xliff:g> pokusov, potom sa SIM karta natrvalo zablokuje. Podrobnosti vám poskytne operátor.</item> <item quantity="one">SIM karta je deaktivovaná. Pokračujte zadaním kódu PUK. Zostáva vám <xliff:g id="_NUMBER_0">%d</xliff:g> pokus, potom sa SIM karta natrvalo zablokuje. Podrobnosti vám poskytne operátor.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Práve je"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Dvanásť"</item> <item msgid="7389464214252023751">"Jedna"</item> diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml index 52b9d6020ddb..1aba2aae2c71 100644 --- a/packages/SystemUI/res-keyguard/values-sl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml @@ -166,7 +166,7 @@ <item quantity="few">Kartica SIM je zdaj onemogočena. Če želite nadaljevati, vnesite kodo PUK. Na voljo imate še <xliff:g id="_NUMBER_1">%d</xliff:g> poskuse. Potem bo kartica SIM postala trajno neuporabna. Za podrobnosti se obrnite na operaterja.</item> <item quantity="other">Kartica SIM je zdaj onemogočena. Če želite nadaljevati, vnesite kodo PUK. Na voljo imate še <xliff:g id="_NUMBER_1">%d</xliff:g> poskusov. Potem bo kartica SIM postala trajno neuporabna. Za podrobnosti se obrnite na operaterja.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Ura je"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Dvanajst"</item> <item msgid="7389464214252023751">"Ena"</item> diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml index 1dfb8fd8b1db..29819e22df88 100644 --- a/packages/SystemUI/res-keyguard/values-sq/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">Karta SIM tani është çaktivizuar. Fut kodin PUK për të vazhduar. Të kanë mbetur edhe <xliff:g id="_NUMBER_1">%d</xliff:g> përpjekje përpara se karta SIM të bëhet përgjithmonë e papërdorshme. Kontakto me operatorin për detaje.</item> <item quantity="one">Karta SIM tani është çaktivizuar. Fut kodin PUK për të vazhduar. Të ka mbetur edhe <xliff:g id="_NUMBER_0">%d</xliff:g> përpjekje përpara se karta SIM të bëhet përgjithmonë e papërdorshme. Kontakto me operatorin për detaje.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Ora është"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Dymbëdhjetë"</item> <item msgid="7389464214252023751">"Një"</item> diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml index 7bb41e9767fb..d572f9692ac7 100644 --- a/packages/SystemUI/res-keyguard/values-sr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml @@ -158,7 +158,7 @@ <item quantity="few">SIM је сада онемогућен. Унесите PUK кôд да бисте наставили. Имате још <xliff:g id="_NUMBER_1">%d</xliff:g> покушаја пре него што SIM постане трајно неупотребљив. Детаљне информације потражите од мобилног оператера.</item> <item quantity="other">SIM је сада онемогућен. Унесите PUK кôд да бисте наставили. Имате још <xliff:g id="_NUMBER_1">%d</xliff:g> покушаја пре него што SIM постане трајно неупотребљив. Детаљне информације потражите од мобилног оператера.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Сада је"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"дванаест"</item> <item msgid="7389464214252023751">"један"</item> diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml index 2475dc1c72b8..6608addcfb19 100644 --- a/packages/SystemUI/res-keyguard/values-sv/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM-kortet är inaktiverat. Ange PUK-koden om du vill fortsätta. <xliff:g id="_NUMBER_1">%d</xliff:g> försök återstår innan SIM-kortet blir obrukbart. Kontakta operatören för mer information.</item> <item quantity="one">SIM-kortet är inaktiverat. Ange PUK-koden om du vill fortsätta. <xliff:g id="_NUMBER_0">%d</xliff:g> försök återstår innan SIM-kortet blir obrukbart. Kontakta operatören för mer information.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Hon är"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Tolv"</item> <item msgid="7389464214252023751">"En"</item> diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml index 0a1acf2f577b..102db535e5d4 100644 --- a/packages/SystemUI/res-keyguard/values-sw/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">Sasa SIM imefungwa. Weka msimbo wa PUK ili uendelee. Umesalia na majaribio <xliff:g id="_NUMBER_1">%d</xliff:g> kabla ya SIM kuacha kufanya kazi kabisa. Wasiliana na mtoa huduma kwa maelezo.</item> <item quantity="one">Sasa SIM imefungwa. Weka msimbo wa PUK ili uendelee. Umesalia na jaribio <xliff:g id="_NUMBER_0">%d</xliff:g> kabla ya SIM kuacha kufanya kazi kabisa. Wasiliana na mtoa huduma kwa maelezo.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Ni saa"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Sita"</item> <item msgid="7389464214252023751">"Saba"</item> diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml index 57a614a0cfa6..009fb2da2e98 100644 --- a/packages/SystemUI/res-keyguard/values-ta/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">சிம் தற்போது முடக்கப்பட்டுள்ளது. தொடர்வதற்கு, PUK குறியீட்டை உள்ளிடவும். நீங்கள் <xliff:g id="_NUMBER_1">%d</xliff:g> முறை மட்டுமே முயற்சிக்க முடியும். அதன்பிறகு சிம் நிரந்தரமாக முடக்கப்படும். விவரங்களுக்கு, மொபைல் நிறுவனத்தைத் தொடர்புகொள்ளவும்.</item> <item quantity="one">சிம் தற்போது முடக்கப்பட்டுள்ளது. தொடர்வதற்கு, PUK குறியீட்டை உள்ளிடவும். நீங்கள் <xliff:g id="_NUMBER_0">%d</xliff:g> முறை மட்டுமே முயற்சிக்க முடியும். அதன்பிறகு சிம் நிரந்தரமாக முடக்கப்படும். விவரங்களுக்கு, மொபைல் நிறுவனத்தைத் தொடர்புகொள்ளவும்.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"அதன்"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"பன்னிரண்டு"</item> <item msgid="7389464214252023751">"ஒன்று"</item> diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml index 58880c45cb76..8f4000f84615 100644 --- a/packages/SystemUI/res-keyguard/values-te/strings.xml +++ b/packages/SystemUI/res-keyguard/values-te/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM ఇప్పుడు నిలిపివేయబడింది. PUK కోడ్ను నమోదు చేయండి. SIM శాశ్వతంగా నిరుపయోగం కాకుండా ఉండటానికి మీకు <xliff:g id="_NUMBER_1">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి. వివరాల కోసం కారియర్ను సంప్రదించండి.</item> <item quantity="one">SIM ఇప్పుడు నిలిపివేయబడింది. PUK కోడ్ను నమోదు చేయండి. SIM శాశ్వతంగా నిరుపయోగం కాకుండా ఉండటానికి మీకు <xliff:g id="_NUMBER_0">%d</xliff:g> ప్రయత్నం మిగిలి ఉంది వివరాల కోసం కారియర్ను సంప్రదించండి.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"ఇప్పుడు"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"పన్నెండు"</item> <item msgid="7389464214252023751">"ఒకటి"</item> diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml index bb52a7f2bdef..bb58e2092721 100644 --- a/packages/SystemUI/res-keyguard/values-th/strings.xml +++ b/packages/SystemUI/res-keyguard/values-th/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">ซิมถูกปิดใช้งานในขณะนี้ โปรดป้อนรหัส PUK เพื่อทำต่อ คุณพยายามได้อีก <xliff:g id="_NUMBER_1">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร โปรดติดต่อสอบถามรายละเอียดจากผู้ให้บริการ</item> <item quantity="one">ซิมถูกปิดใช้งานในขณะนี้ โปรดป้อนรหัส PUK เพื่อทำต่อ คุณพยายามได้อีก <xliff:g id="_NUMBER_0">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร โปรดติดต่อสอบถามรายละเอียดจากผู้ให้บริการ</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"เวลา"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"สิบสอง"</item> <item msgid="7389464214252023751">"หนึ่ง"</item> diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml index 1f480f40379f..ec7b924969a3 100644 --- a/packages/SystemUI/res-keyguard/values-tl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">Naka-disable na ang SIM. Ilagay ang PUK code upang magpatuloy. Mayroon kang <xliff:g id="_NUMBER_1">%d</xliff:g> natitirang pagsubok bago tuluyang hindi magamit ang SIM. Makipag-ugnayan sa carrier para sa mga detalye.</item> <item quantity="other">Naka-disable na ang SIM. Ilagay ang PUK code upang magpatuloy. Mayroon kang <xliff:g id="_NUMBER_1">%d</xliff:g> na natitirang pagsubok bago tuluyang hindi magamit ang SIM. Makipag-ugnayan sa carrier para sa mga detalye.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Oras ay"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Twelve"</item> <item msgid="7389464214252023751">"One"</item> diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml index 8ff1d88ee83a..92b3fb37d6f7 100644 --- a/packages/SystemUI/res-keyguard/values-tr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM artık devre dışı. Devam etmek için PUK kodunu girin. SIM kalıcı olarak kullanım dışı kalmadan önce <xliff:g id="_NUMBER_1">%d</xliff:g> deneme hakkınız kaldı. Ayrıntılı bilgi için operatörünüzle iletişim kurun.</item> <item quantity="one">SIM artık devre dışı. Devam etmek için PUK kodunu girin. SIM kalıcı olarak kullanım dışı kalmadan önce <xliff:g id="_NUMBER_0">%d</xliff:g> deneme hakkınız kaldı. Ayrıntılı bilgi için operatörünüzle iletişim kurun.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Saat"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"On İki"</item> <item msgid="7389464214252023751">"Bir"</item> diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml index 3f0982fe5d47..2772d0738334 100644 --- a/packages/SystemUI/res-keyguard/values-uk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml @@ -166,7 +166,7 @@ <item quantity="many">SIM-карту заблоковано. Щоб продовжити, введіть PUK-код. Залишилося <xliff:g id="_NUMBER_1">%d</xliff:g> спроб. Після цього SIM-карту буде назавжди заблоковано. Щоб дізнатися більше, зверніться до свого оператора.</item> <item quantity="other">SIM-карту заблоковано. Щоб продовжити, введіть PUK-код. Залишилося <xliff:g id="_NUMBER_1">%d</xliff:g> спроби. Після цього SIM-карту буде назавжди заблоковано. Щоб дізнатися більше, зверніться до свого оператора.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Зараз"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"дванадцята"</item> <item msgid="7389464214252023751">"перша"</item> diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml index 3c520f955b93..e9e67097cfa8 100644 --- a/packages/SystemUI/res-keyguard/values-ur/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM اب غیر فعال ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ SIM کے مستقل طور پر ناقابل استعمال ہونے سے پہلے آپ کے پاس <xliff:g id="_NUMBER_1">%d</xliff:g> کوششیں بچی ہیں۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔</item> <item quantity="one">SIM اب غیر فعال ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ SIM کے مستقل طور پر ناقابل استعمال ہونے سے پہلے آپ کے پاس <xliff:g id="_NUMBER_0">%d</xliff:g> کوشش بچی ہے۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"وقت/ابھی"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"بارہ"</item> <item msgid="7389464214252023751">"ایک"</item> diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml index 640a98760f2f..676f7bb97de6 100644 --- a/packages/SystemUI/res-keyguard/values-uz/strings.xml +++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml @@ -152,7 +152,7 @@ <item quantity="other">SIM karta faolsizlantirildi. Davom etish uchun PUK kodni kiriting. Yana <xliff:g id="_NUMBER_1">%d</xliff:g> marta xato qilsangiz, SIM kartangiz butunlay qulflanadi. Batafsil axborot olish uchun tarmoq operatoriga murojaat qiling.</item> <item quantity="one">SIM karta faolsizlantirildi. Davom etish uchun PUK kodni kiriting. Yana <xliff:g id="_NUMBER_0">%d</xliff:g> marta xato qilsangiz, SIM kartangiz butunlay qulflanadi. Batafsil axborot olish uchun tarmoq operatoriga murojaat qiling.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Hozir"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Oʻn ikki"</item> <item msgid="7389464214252023751">"Bir"</item> diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml index 2a62fb878231..f2cfb2a2a23e 100644 --- a/packages/SystemUI/res-keyguard/values-vi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM hiện đã bị tắt. Hãy nhập mã PUK để tiếp tục. Bạn còn <xliff:g id="_NUMBER_1">%d</xliff:g> lần thử trước khi SIM vĩnh viễn không sử dụng được. Hãy liên hệ với nhà cung cấp dịch vụ để biết chi tiết.</item> <item quantity="one">SIM hiện đã bị tắt. Hãy nhập mã PUK để tiếp tục. Bạn còn <xliff:g id="_NUMBER_0">%d</xliff:g> lần thử trước khi SIM vĩnh viễn không thể sử dụng được. Hãy liên hệ với nhà cung cấp dịch vụ để biết chi tiết.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Hiện là"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Mười hai"</item> <item msgid="7389464214252023751">"Một"</item> diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml index 80fac9030fe0..efa5fc35ff1c 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM 卡现已停用,请输入 PUK 码继续使用。您还可以尝试 <xliff:g id="_NUMBER_1">%d</xliff:g> 次。如果仍不正确,该 SIM 卡将永远无法使用。有关详情,请联系您的运营商。</item> <item quantity="one">SIM 卡现已停用,请输入 PUK 码继续使用。您还可以尝试 <xliff:g id="_NUMBER_0">%d</xliff:g> 次。如果仍不正确,该 SIM 卡将永远无法使用。有关详情,请联系您的运营商。</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"时间是"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"十二"</item> <item msgid="7389464214252023751">"一"</item> diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml index 926d601ebb5a..eeff66acd9a8 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM 卡已停用。請輸入 PUK 碼以繼續進行。您還可以再試 <xliff:g id="_NUMBER_1">%d</xliff:g> 次。如果仍然輸入錯誤,SIM 卡將永久無法使用。詳情請與流動網絡供應商聯絡。</item> <item quantity="one">SIM 卡已停用。請輸入 PUK 碼以繼續進行。您還可以再試 <xliff:g id="_NUMBER_0">%d</xliff:g> 次。如果仍然輸入錯誤,SIM 卡將永久無法使用。詳情請與流動網絡供應商聯絡。</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"現在是"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"十二"</item> <item msgid="7389464214252023751">"一"</item> diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml index 728f1a97996f..961ef39f3809 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml @@ -150,7 +150,7 @@ <item quantity="other">SIM 卡現在已遭停用。請輸入 PUK 碼以繼續進行。你還可以再試 <xliff:g id="_NUMBER_1">%d</xliff:g> 次,如果仍然失敗,SIM 卡將永久無法使用。詳情請與電信業者聯絡。</item> <item quantity="one">SIM 卡現在已遭停用。請輸入 PUK 碼以繼續進行。你還可以再試 <xliff:g id="_NUMBER_0">%d</xliff:g> 次,如果仍然失敗,SIM 卡將永久無法使用。詳情請與電信業者聯絡。</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"時間是"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"十二"</item> <item msgid="7389464214252023751">"一"</item> diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml index 7e0a03c02c94..2e948b485276 100644 --- a/packages/SystemUI/res-keyguard/values-zu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml @@ -150,7 +150,7 @@ <item quantity="one">I-SIM manje ikhutshaziwe. Faka ikhodi ye-PUK ukuze uqhubeke. Unemizamo engu-<xliff:g id="_NUMBER_1">%d</xliff:g> esele ngaphambi kokuthi i-SIM ingasebenziseki unaphakade. Xhumana nenkampani yenethiwekhi ngemininingwane.</item> <item quantity="other">I-SIM manje ikhutshaziwe. Faka ikhodi ye-PUK ukuze uqhubeke. Unemizamo engu-<xliff:g id="_NUMBER_1">%d</xliff:g> esele ngaphambi kokuthi i-SIM ingasebenziseki unaphakade. Xhumana nenkampani yenethiwekhi ngemininingwane.</item> </plurals> - <string name="type_clock_header" msgid="4786545441902447636">"Kuyi-"</string> + <!-- no translation found for type_clock_header (6782840450655632763) --> <string-array name="type_clock_hours"> <item msgid="3543074812389379830">"Ishumi nambili"</item> <item msgid="7389464214252023751">"Kunye"</item> diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index 94481e7fe456..5714556ae8a3 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -64,6 +64,9 @@ charged, say that it is charged. --> <string name="keyguard_charged">Fully charged</string> + <!-- When the lock screen is showing and the phone plugged in, and the battery is not fully charged, say that it's wirelessly charging. [CHAR LIMIT=50] --> + <string name="keyguard_plugged_in_wireless"><xliff:g id="percentage" example="20%">%s</xliff:g> • Wirelessly Charging</string> + <!-- When the lock screen is showing and the phone plugged in, and the battery is not fully charged, say that it's charging. --> <string name="keyguard_plugged_in"><xliff:g id="percentage">%s</xliff:g> • Charging</string> diff --git a/packages/SystemUI/res/drawable/privacy_chip_bg.xml b/packages/SystemUI/res/drawable/privacy_chip_bg.xml index 36d06591460b..f1158ef11ccc 100644 --- a/packages/SystemUI/res/drawable/privacy_chip_bg.xml +++ b/packages/SystemUI/res/drawable/privacy_chip_bg.xml @@ -17,6 +17,7 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#4a4a4a" /> - <padding android:padding="@dimen/ongoing_appops_chip_bg_padding" /> + <padding android:paddingTop="@dimen/ongoing_appops_chip_bg_padding" + android:paddingBottom="@dimen/ongoing_appops_chip_bg_padding"/> <corners android:radius="@dimen/ongoing_appops_chip_bg_corner_radius" /> </shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index d502baa956b0..91353d7fb8ba 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -71,18 +71,38 @@ android:maxLines="1" android:layout_centerVertical="true" android:layout_toEndOf="@id/pkg_divider" /> - <!-- 24 dp icon with 16 dp padding all around to mirror notification content margins --> - <ImageButton - android:id="@+id/info" - android:layout_width="56dp" - android:layout_height="56dp" - android:layout_alignParentEnd="true" + <LinearLayout + android:id="@+id/info_and_settings" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_centerVertical="true" - android:background="@drawable/ripple_drawable" - android:contentDescription="@string/notification_more_settings" - android:padding="16dp" - android:src="@drawable/ic_info" - android:tint="?android:attr/colorAccent" /> + android:layout_alignParentEnd="true" + android:paddingHorizontal="16dp" + android:orientation="horizontal"> + <!-- Optional link to app. Only appears if the channel is not disabled and the app +asked for it --> + <ImageButton + android:id="@+id/app_settings" + android:layout_width="40dp" + android:layout_height="56dp" + android:layout_centerVertical="true" + android:paddingRight="16dp" + android:visibility="gone" + android:background="@drawable/ripple_drawable" + android:contentDescription="@string/notification_app_settings" + android:src="@drawable/ic_settings" + android:tint="?android:attr/colorAccent" /> + <!-- 24 dp icon with 16 dp padding all around to mirror notification content margins --> + <ImageButton + android:id="@+id/info" + android:layout_width="24dp" + android:layout_height="56dp" + android:layout_centerVertical="true" + android:background="@drawable/ripple_drawable" + android:contentDescription="@string/notification_more_settings" + android:src="@drawable/ic_info" + android:tint="?android:attr/colorAccent" /> + </LinearLayout> </RelativeLayout> <LinearLayout @@ -143,50 +163,61 @@ </LinearLayout> <!-- Settings and Done buttons --> - <LinearLayout + <RelativeLayout android:id="@+id/block_or_minimize" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/notification_guts_button_spacing" android:layout_marginStart="@dimen/notification_guts_button_side_margin" android:layout_marginEnd="@dimen/notification_guts_button_side_margin" - android:gravity="end" - android:orientation="horizontal"> - - <!-- Optional link to app. Only appears if the channel is not disabled and the app - asked for it --> + android:clipChildren="false" + android:clipToPadding="false"> <TextView - android:id="@+id/app_settings" - android:text="@string/notification_app_settings" + android:id="@+id/done" + android:text="@string/inline_done_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:visibility="gone" - android:ellipsize="end" - android:maxLines="1" + android:layout_centerVertical="true" style="@style/TextAppearance.NotificationInfo.Button"/> - <TextView - android:id="@+id/block" - android:text="@string/inline_stop_button" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing" - style="@style/TextAppearance.NotificationInfo.Button"/> - <TextView - android:id="@+id/minimize" - android:text="@string/inline_minimize_button" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing" - style="@style/TextAppearance.NotificationInfo.Button" /> - <TextView - android:id="@+id/keep" - android:minWidth="48dp" - android:text="@string/inline_keep_button" + + <LinearLayout + android:id="@+id/block_buttons" android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing" - style="@style/TextAppearance.NotificationInfo.Button"/> - </LinearLayout> + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_alignParentEnd="true" + android:orientation="horizontal"> + <TextView + android:id="@+id/deliver_silently" + android:text="@string/inline_deliver_silently_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing" + android:paddingRight="24dp" + style="@style/TextAppearance.NotificationInfo.Button"/> + <TextView + android:id="@+id/block" + android:text="@string/inline_block_button" + android:minWidth="48dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing" + style="@style/TextAppearance.NotificationInfo.Button"/> + <TextView + android:id="@+id/minimize" + android:text="@string/inline_minimize_button" + android:minWidth="48dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing" + style="@style/TextAppearance.NotificationInfo.Button"/> + </LinearLayout> + + + </RelativeLayout> <LinearLayout android:id="@+id/interruptiveness_settings" android:layout_width="match_parent" diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml index cbdd51b24388..58fe81109731 100644 --- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml +++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml @@ -29,14 +29,25 @@ android:orientation="horizontal" android:paddingStart="@dimen/ongoing_appops_chip_side_padding" android:paddingEnd="@dimen/ongoing_appops_chip_side_padding" - android:background="@drawable/privacy_chip_bg" android:focusable="true"> + <TextView + android:id="@+id/in_use_text" + android:layout_height="match_parent" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical|start" + android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin_collapsed" + android:gravity="center_vertical" + android:textAppearance="@style/TextAppearance.StatusBar.Clock" + android:textColor="@color/status_bar_clock_color" + android:text="@string/ongoing_privacy_chip_in_use" + /> + <LinearLayout android:id="@+id/icons_container" android:layout_height="match_parent" android:layout_width="wrap_content" - android:layout_gravity="center_vertical|start" + android:layout_gravity="center_vertical" android:gravity="center_vertical" /> @@ -51,7 +62,7 @@ android:gravity="center_vertical" android:textAppearance="@style/TextAppearance.StatusBar.Clock" android:textColor="@color/status_bar_clock_color" - android:layout_marginStart="@dimen/ongoing_appops_chip_icon_margin" - android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin" + android:layout_marginStart="@dimen/ongoing_appops_chip_icon_margin_collapsed" + android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin_collapsed" /> </com.android.systemui.privacy.OngoingPrivacyChip>
\ No newline at end of file diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 053371a0e527..9b765f824859 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> program gebruik jou <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Het dit"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privaatheidsinstellings"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Program wat jou <xliff:g id="TYPES_LIST">%s</xliff:g> gebruik"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Programme wat jou <xliff:g id="TYPES_LIST">%s</xliff:g> gebruik"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors is af"</string> <string name="device_services" msgid="1191212554435440592">"Toesteldienste"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Titelloos"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Maak <xliff:g id="APP_NAME">%1$s</xliff:g> oop"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Maak kennisgewinginstellings oop vir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 8acd1b832ed3..d12ba4ca08a4 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -879,8 +879,7 @@ <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> መተግበሪያዎች የእርስዎን <xliff:g id="TYPE_5">%2$s</xliff:g> እየተጠቀሙ ነው።</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"ገባኝ"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"የግላዊነት ቅንብሮች"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"የእርስዎን <xliff:g id="TYPES_LIST">%s</xliff:g> የሚጠቀሙ መተግበሪያዎች"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"የእርስዎን <xliff:g id="TYPES_LIST">%s</xliff:g> የሚጠቀሙ መተግበሪያዎች"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"፣ "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"ዳሳሾች ጠፍተዋል"</string> <string name="device_services" msgid="1191212554435440592">"የመሣሪያ አገልግሎቶች"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"ርዕስ የለም"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> ክፈት"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"የማስታወቂያ ቅንብሮች ለ <xliff:g id="APP_NAME">%1$s</xliff:g> ክፈት"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 0312adf36f23..7c08783e365d 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -907,8 +907,7 @@ <item quantity="one">هناك تطبيق واحد (<xliff:g id="NUM_APPS_0">%1$d</xliff:g>) يستخدِم <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"حسنًا"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"إعدادات الخصوصية"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"التطبيق الذي يستخدِم <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"التطبيقات التي تستخدِم <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"، "</string> @@ -927,8 +926,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"إيقاف أجهزة الاستشعار"</string> <string name="device_services" msgid="1191212554435440592">"خدمات الأجهزة"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"بلا عنوان"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"فتح <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"فتح إعدادات الإشعارات في <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index fbaad96d0454..c782d1be3da9 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 70608a17531d..896fe3408235 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> tətbiq <xliff:g id="TYPE_1">%2$s</xliff:g> tətbiqindən istifadə edir.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Anladım"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Məxfilik ayarları"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"<xliff:g id="TYPES_LIST">%s</xliff:g> tətbiqindən istifadə edən tətbiq"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"<xliff:g id="TYPES_LIST">%s</xliff:g> tətbiqindən istifadə edən tətbiqlər"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorlar deaktivdir"</string> <string name="device_services" msgid="1191212554435440592">"Cihaz Xidmətləri"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Başlıq yoxdur"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqini açın"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün bildiriş ayarlarını açın"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 8a754f3425fc..14ab0a4422b0 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -886,8 +886,7 @@ <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplikacija koristi dozvolu <xliff:g id="TYPE_5">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Važi"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Podešav. privatnosti"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikacija koja koristi dozvole <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikacije koje koriste dozvole <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -903,8 +902,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori su isključeni"</string> <string name="device_services" msgid="1191212554435440592">"Usluge za uređaje"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Bez naslova"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otvorite <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otvorite podešavanja obaveštenja za <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 3390fcbf8ad7..0e724fa02954 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -917,4 +917,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 00454ddda7e3..c44b3ad957ee 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> приложение използва <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Разбрах"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Поверит.: Настройки"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Приложение, което използва <xliff:g id="TYPES_LIST">%s</xliff:g> ви"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Приложения, които използват <xliff:g id="TYPES_LIST">%s</xliff:g> ви"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Сензорите са изключени"</string> <string name="device_services" msgid="1191212554435440592">"Услуги за устройството"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Няма заглавие"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Отваряне на „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Отваряне на настройките за известията за „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index b864206c6084..ec7ff6d7d110 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index d1528316b0ae..77069b2c4e2b 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -888,8 +888,7 @@ <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplikacija koristi <xliff:g id="TYPE_5">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Razumijem"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Postavke privatnosti"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikacija koristi odobrenja <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikacije koriste odobrenja <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -905,8 +904,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori su isključeni"</string> <string name="device_services" msgid="1191212554435440592">"Usluge uređaja"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Bez naslova"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otvorite aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otvorite postavke obavijesti za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index f41ea3cd5b83..1c52610722cb 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 4bdc271df52b..735b476a4583 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -915,4 +915,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 0c3c253434da..615338dbcef3 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -879,8 +879,7 @@ <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> apps anvender din/dit <xliff:g id="TYPE_5">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privatlivsindstill."</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App, der anvender din/dit <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps, der anvender din/dit <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Deaktiver sensorer"</string> <string name="device_services" msgid="1191212554435440592">"Enhedstjenester"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Ingen titel"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Åbn <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Åbn notifikationsindstillingerne for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index c21288dbfadc..4e2e1e134905 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -441,7 +441,7 @@ <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduzierung der Leistung und Hintergrunddaten"</string> <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Energiesparmodus deaktivieren"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> nimmt alle auf deinem Bildschirm angezeigten Aktivitäten auf."</string> - <string name="media_projection_remember_text" msgid="3103510882172746752">"Nicht erneut anzeigen"</string> + <string name="media_projection_remember_text" msgid="3103510882172746752">"Nicht mehr anzeigen"</string> <string name="clear_all_notifications_text" msgid="814192889771462828">"Alle löschen"</string> <string name="manage_notifications_text" msgid="2386728145475108753">"Verwalten"</string> <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Benachrichtigungen durch \"Bitte nicht stören\" pausiert"</string> @@ -883,8 +883,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> App verwendet gerade: <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Datenschutzeinst."</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App, die <xliff:g id="TYPES_LIST">%s</xliff:g> verwendet"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps, die <xliff:g id="TYPES_LIST">%s</xliff:g> verwenden"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -899,8 +898,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensoren aus"</string> <string name="device_services" msgid="1191212554435440592">"Gerätedienste"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Kein Titel"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> öffnen"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Benachrichtigungseinstellungen für <xliff:g id="APP_NAME">%1$s</xliff:g> öffnen"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 23818956b18e..1a0df6bcbda3 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> εφαρμογή χρησιμοποιεί το <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Κατάλαβα"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Ρυθμίσεις απορρήτου"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Εφαρμογή που χρησιμοποιεί τις λειτουργίες <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Εφαρμογές που χρησιμοποιούν τις λειτουργίες <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Αισθητήρες ανενεργοί"</string> <string name="device_services" msgid="1191212554435440592">"Υπηρεσίες συσκευής"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Χωρίς τίτλο"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Άνοιγμα <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Άνοιγμα ρυθμίσεων ειδοποιήσεων για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 63f677319abd..95c1349b76e4 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> application is using your <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Got it"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacy settings"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string> <string name="device_services" msgid="1191212554435440592">"Device Services"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Open notification settings for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index d6539e7bcd20..6d55c5a6227a 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> application is using your <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Got it"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacy settings"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string> <string name="device_services" msgid="1191212554435440592">"Device Services"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Open notification settings for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 63f677319abd..95c1349b76e4 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> application is using your <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Got it"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacy settings"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string> <string name="device_services" msgid="1191212554435440592">"Device Services"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Open notification settings for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 63f677319abd..95c1349b76e4 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> application is using your <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Got it"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacy settings"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string> <string name="device_services" msgid="1191212554435440592">"Device Services"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Open notification settings for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 36ef6479415e..266faa85f960 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> application is using your <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Got it"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacy settings"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string> <string name="device_services" msgid="1191212554435440592">"Device Services"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Open notification settings for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 81cd300fa200..b1f7068b5876 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplicación está usando tu <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Entendido"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Config. privacidad"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Una app está usando tu <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps que están usando tu <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Se desactivaron los sensores"</string> <string name="device_services" msgid="1191212554435440592">"Servicios del dispositivo"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Sin título"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abrir la configuración de notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 16c182b97d18..b1947fdc46b7 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index b02e45746eb6..8085224caaee 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> rakendus kasutab üksust <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Selge"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privaatsusseaded"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Rakendus, mis kasutab üksusi <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Rakendused, mis kasutavad üksusi <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Andurid on välja lülitatud"</string> <string name="device_services" msgid="1191212554435440592">"Seadme teenused"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Pealkiri puudub"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Ava <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Ava rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> märguandeseaded"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index b2d29c12faaf..7f9bffa37c8d 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplikazio ari da <xliff:g id="TYPE_1">%2$s</xliff:g> erabiltzen.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ados"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Pribatutasun-ezarpenak"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"<xliff:g id="TYPES_LIST">%s</xliff:g> erabiltzen ari den aplikazioa"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"<xliff:g id="TYPES_LIST">%s</xliff:g> erabiltzen ari diren aplikazioak"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sentsoreak desaktibatuta daude"</string> <string name="device_services" msgid="1191212554435440592">"Gailuetarako zerbitzuak"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Ez du izenik"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Ireki <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Ireki <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren jakinarazpen-ezarpenak"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 4fb889bc2501..018d6d1fd0da 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -879,8 +879,7 @@ <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> برنامه درحال استفاده از <xliff:g id="TYPE_5">%2$s</xliff:g> شما است.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"متوجه شدم"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"تنظیمات حریم خصوصی"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"برنامهای که از <xliff:g id="TYPES_LIST">%s</xliff:g> شما استفاده میکند"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"برنامههایی که از <xliff:g id="TYPES_LIST">%s</xliff:g> شما استفاده میکنند"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"، "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"حسگرها خاموش است"</string> <string name="device_services" msgid="1191212554435440592">"سرویسهای دستگاه"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"بدون عنوان"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"باز کردن <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"تنظیمات اعلان <xliff:g id="APP_NAME">%1$s</xliff:g> را باز کنید"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 1ab48a0855d5..0258ccbf9332 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="TYPE_1">%2$s</xliff:g> on <xliff:g id="NUM_APPS_0">%1$d</xliff:g> sovelluksen käytössä.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Selvä"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Tietosuoja-asetukset"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Sovellus, jolla on <xliff:g id="TYPES_LIST">%s</xliff:g> ‑käyttöoikeus"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Sovellukset, joilla on <xliff:g id="TYPES_LIST">%s</xliff:g> ‑käyttöoikeus"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Anturit pois päältä"</string> <string name="device_services" msgid="1191212554435440592">"Laitepalvelut"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Ei nimeä"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Avaa <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Avaa ilmoitusasetukset (<xliff:g id="APP_NAME">%1$s</xliff:g>)"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 554a22253d93..a3a31356fcfc 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 2e4700059fa3..d1ce32e3a193 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 90b9f87a12af..d76c34a64042 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplicación utiliza o teu dispositivo (<xliff:g id="TYPE_1">%2$s</xliff:g>).</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"De acordo"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Config. privacidade"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplicación que utiliza o seguinte: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplicacións que utilizan o seguinte: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Desactivar sensores"</string> <string name="device_services" msgid="1191212554435440592">"Servizos do dispositivo"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Sen título"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abre a aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abre a configuración de notificacións para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 5717616b706d..c84051cc51bb 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 20b9198e6e21..157f55c9bede 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 79f410a87929..77c3ce3b47b8 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -886,8 +886,7 @@ <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplikacija upotrebljava <xliff:g id="TYPE_5">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Shvaćam"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Postavke privatnosti"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikacije koje upotrebljavaju <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikacije koje upotrebljavaju <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -903,8 +902,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori su isključeni"</string> <string name="device_services" msgid="1191212554435440592">"Usluge uređaja"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Bez naslova"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otvorite aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otvorite postavke obavijesti za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index d0cdfb4601d6..308295a20cc1 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> alkalmazás használja a következőt: <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Értem"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Adatvédelmi beállítások"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"A következőket használó alkalmazás: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"A következőt használó alkalmazások: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Érzékelők kikapcsolva"</string> <string name="device_services" msgid="1191212554435440592">"Eszközszolgáltatások"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Nincs cím"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> megnyitása"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> – az alkalmazás értesítési beállításainak megnyitása"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 41bd378e912e..a3e05ad1cc01 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 98e1c4b3d9a3..2bad55e03d62 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplikasi menggunakan <xliff:g id="TYPE_1">%2$s</xliff:g> Anda.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Oke"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Setelan privasi"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikasi yang menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g> Anda"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikasi yang menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g> Anda"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensor nonaktif"</string> <string name="device_services" msgid="1191212554435440592">"Layanan Perangkat"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Tanpa judul"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Buka <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Buka setelan notifikasi untuk <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index d1ea979f5a2e..35026134445e 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -879,8 +879,7 @@ <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> forrit eru að nota <xliff:g id="TYPE_5">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ég skil"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Persónuvernd"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Forrit sem nota <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Forrit sem nota <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Slökkt á skynjurum"</string> <string name="device_services" msgid="1191212554435440592">"Tækjaþjónusta"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Enginn titill"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Opna <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Opna tilkynningastillingar fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index af22c6d19399..42ff72a59014 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> applicazione sta utilizzando <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Impostazioni privacy"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App che usa <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"App che utilizzano <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensori disattivati"</string> <string name="device_services" msgid="1191212554435440592">"Servizi del dispositivo"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Senza titolo"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Apri <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Apri le impostazioni di notifica dell\'app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index a7d5138cebb7..036b0dfa7f3b 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -519,9 +519,9 @@ <string name="accessibility_volume_collapse" msgid="3609549593031810875">"כווץ"</string> <string name="accessibility_output_chooser" msgid="8185317493017988680">"החלפת מכשיר פלט"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"המסך מוצמד"</string> - <string name="screen_pinning_description" msgid="8909878447196419623">"נשאר בתצוגה עד לביטול ההצמדה. גע בלחצנים \'הקודם\' ו\'סקירה\' והחזק כדי לבטל את ההצמדה."</string> + <string name="screen_pinning_description" msgid="8909878447196419623">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\' כדי לבטל את ההצמדה."</string> <string name="screen_pinning_description_recents_invisible" msgid="8281145542163727971">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'דף הבית\' כדי לבטל את ההצמדה."</string> - <string name="screen_pinning_description_accessible" msgid="426190689254018656">"נשאר בתצוגה עד לביטול ההצמדה. גע בלחצן \'סקירה\' והחזק כדי לבטל את ההצמדה."</string> + <string name="screen_pinning_description_accessible" msgid="426190689254018656">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'סקירה\' כדי לבטל את ההצמדה."</string> <string name="screen_pinning_description_recents_invisible_accessible" msgid="6134833683151189507">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'דף הבית\' כדי לבטל את ההצמדה."</string> <string name="screen_pinning_toast" msgid="2266705122951934150">"כדי לבטל את ההצמדה של מסך זה, יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\'"</string> <string name="screen_pinning_toast_recents_invisible" msgid="8252402309499161281">"כדי לבטל את ההצמדה של מסך זה, יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'דף הבית\'"</string> @@ -915,4 +915,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 9095fd1a8cdd..7aa7fbf39661 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> 個のアプリが <xliff:g id="TYPE_1">%2$s</xliff:g> を使用しています。</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"プライバシー設定"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"<xliff:g id="TYPES_LIST">%s</xliff:g>を使用しているアプリ"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"<xliff:g id="TYPES_LIST">%s</xliff:g>を使用しているアプリ"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"、 "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"センサー OFF"</string> <string name="device_services" msgid="1191212554435440592">"デバイス サービス"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"タイトルなし"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> を開く"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> の通知設定を開く"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 92368300422a..4fec28473a7f 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -879,8 +879,7 @@ <item quantity="one">თქვენი <xliff:g id="TYPE_1">%2$s</xliff:g> გამოიყენება <xliff:g id="NUM_APPS_0">%1$d</xliff:g> აპლიკაციის მიერ.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"გასაგებია"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"კონფიდ. პარამეტრები"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"აპი, რომლის მიერაც გამოიყენება თქვენი <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"აპები, რომელთა მიერაც გამოიყენება თქვენი <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"სენსორების გამორთვა"</string> <string name="device_services" msgid="1191212554435440592">"მოწყობილობის სერვისები"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"უსათაურო"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის გახსნა"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის შეტყობინების პარამეტრების გახსნა"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 3b46364d8faf..c5022b55cacd 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 6811072ef0ff..c03dddd43ba6 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 273470ada54e..aa0e63f855be 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index ca45e4ddedc6..eb949037461e 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 82d709b52359..14d93e498e8f 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index ed0540780031..467a2dc77b67 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index a136772baad4..c79743ffdbd0 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -893,8 +893,7 @@ <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> programų naudoja jūsų <xliff:g id="TYPE_5">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Supratau"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privatumo nustatymai"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Programa, kuri naudoja: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Programos, kurios naudoja: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -911,8 +910,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Jutikliai išjungti"</string> <string name="device_services" msgid="1191212554435440592">"Įrenginio paslaugos"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Nėra pavadinimo"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Atidaryti „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Atidaryti „<xliff:g id="APP_NAME">%1$s</xliff:g>“ pranešimų nustatymus"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index fec4fe8ca672..d6dc8f34c6dc 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -886,8 +886,7 @@ <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> lietojumprogrammās tiek izmantots: <xliff:g id="TYPE_5">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Labi"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Konfidencialitāte"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Lietotne, kurā tiek izmantots: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Lietotnes, kurās tiek izmantots: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -903,8 +902,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensori izslēgti"</string> <string name="device_services" msgid="1191212554435440592">"Ierīces pakalpojumi"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Nav nosaukuma"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Atvērt lietotni <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Atvērt paziņojumu iestatījumus lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 6b3e8cc111e5..03e31f745794 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 37d4b8c85f96..f25ae1d0e1d8 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 42cb765369b1..0e5dbb71d39a 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -879,8 +879,7 @@ <item quantity="one">Таны <xliff:g id="TYPE_1">%2$s</xliff:g>-г <xliff:g id="NUM_APPS_0">%1$d</xliff:g> апп ашиглаж байна.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ойлголоо"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Нууцлалын тохиргоо"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Апп таны <xliff:g id="TYPES_LIST">%s</xliff:g>-г ашиглаж байна"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Аппууд таны <xliff:g id="TYPES_LIST">%s</xliff:g>-г ашиглаж байна"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Мэдрэгчийг унтраах"</string> <string name="device_services" msgid="1191212554435440592">"Төхөөрөмжийн үйлчилгээ"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Гарчиггүй"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г нээх"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н мэдэгдлийн тохиргоог нээх"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 44d8c4e8f3ff..1b81062cc247 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index eee6b25bcddf..df10b2ffa438 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index b341bea7d19b..f8278059919d 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -684,7 +684,7 @@ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"ဂဏန်းကွက်<xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"စနစ်"</string> <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ပင်မ"</string> - <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"မကြာသေးခင်က"</string> + <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"လတ်တလော"</string> <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"နောက်သို့"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"အကြောင်းကြားချက်များ"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ကီးဘုတ် ဖြတ်လမ်းများ"</string> @@ -879,8 +879,7 @@ <item quantity="one">အပလီကေးရှင်း <xliff:g id="NUM_APPS_0">%1$d</xliff:g> ခုက သင်၏ <xliff:g id="TYPE_1">%2$s</xliff:g> ကို အသုံးပြုနေသည်။</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"ရပါပြီ"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"ကန့်သတ်ဆက်တင်များ"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"သင့် <xliff:g id="TYPES_LIST">%s</xliff:g> ကို အသုံးပြုနေသော အက်ပ်"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"သင့် <xliff:g id="TYPES_LIST">%s</xliff:g> ကို အသုံးပြုနေသော အက်ပ်များ"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"၊ "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"အာရုံခံကိရိယာများ ပိတ်ထားသည်"</string> <string name="device_services" msgid="1191212554435440592">"စက်ပစ္စည်းဝန်ဆောင်မှုများ"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"ခေါင်းစဉ် မရှိပါ"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကိုဖွင့်ရန်"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> အတွက် အကြောင်းကြားချက်ဆက်တင်များကို ဖွင့်ရန်"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index a27addba20de..1370468c32e5 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 1bb366481b25..08f3cef84582 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 8075ef4cd6af..7cb4b5a359c0 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -792,7 +792,7 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g>-instellingen openen."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Volgorde van instellingen bewerken."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string> - <string name="tuner_lock_screen" msgid="5755818559638850294">"Scherm vergrendelen"</string> + <string name="tuner_lock_screen" msgid="5755818559638850294">"Vergrendelingsscherm"</string> <string name="pip_phone_expand" msgid="5889780005575693909">"Uitvouwen"</string> <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimaliseren"</string> <string name="pip_phone_close" msgid="8416647892889710330">"Sluiten"</string> @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> app gebruikt je <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacyinstellingen"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App die je <xliff:g id="TYPES_LIST">%s</xliff:g> gebruikt"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps die je <xliff:g id="TYPES_LIST">%s</xliff:g> gebruiken"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensoren uit"</string> <string name="device_services" msgid="1191212554435440592">"Apparaatservices"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Geen titel"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> openen"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Instellingen voor meldingen voor <xliff:g id="APP_NAME">%1$s</xliff:g> openen"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 337b15d219f7..b9b4ea8f8360 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 4d8e3f11ceab..5432975a7320 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index d955236c3b09..b69204593082 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -893,8 +893,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplikacja używa: <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Ustawienia prywatności"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikacje, które używają: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikacje, które używają: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -911,8 +910,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Wyłącz czujniki"</string> <string name="device_services" msgid="1191212554435440592">"Usługi urządzenia"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Bez tytułu"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otwórz: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otwórz ustawienia powiadomień z aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index d2219d259522..fcd7f85cf6f4 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -879,8 +879,7 @@ <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplicativos estão usando <xliff:g id="TYPE_5">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ok"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Config. de privacidade"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App usando <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps usando <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desativados"</string> <string name="device_services" msgid="1191212554435440592">"Serviços do dispositivo"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Sem título"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abra as configurações de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 0866ffc7acea..6579645c83b9 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplicação está a utilizar o(a) <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Compreendi"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Def. de privacidade"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplicações que utilizam o(a) <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplicações que utilizam o(a) <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desativados"</string> <string name="device_services" msgid="1191212554435440592">"Serviços do dispositivo"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Sem título"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abrir a aplicação <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abrir as definições de notificação da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index d2219d259522..fcd7f85cf6f4 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -879,8 +879,7 @@ <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplicativos estão usando <xliff:g id="TYPE_5">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ok"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Config. de privacidade"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App usando <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps usando <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desativados"</string> <string name="device_services" msgid="1191212554435440592">"Serviços do dispositivo"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Sem título"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abra as configurações de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index e04048458ea6..144bfc38f677 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -886,8 +886,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplicație folosește <xliff:g id="TYPE_1">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Setări de confidențialitate"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplicație care folosește <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplicații care folosesc <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -903,8 +902,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori dezactivați"</string> <string name="device_services" msgid="1191212554435440592">"Servicii pentru dispozitiv"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Fără titlu"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Accesați <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Deschideți setările pentru notificări pentru aplicația <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 338ce14764a0..6d65592ad549 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -893,8 +893,7 @@ <item quantity="other">Функцию \"<xliff:g id="TYPE_5">%2$s</xliff:g>\" используют <xliff:g id="NUM_APPS_4">%1$d</xliff:g> приложения.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"ОК"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Конфиденциальность"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Приложение, в котором используются операции <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Приложения, в которых используются операции <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -911,8 +910,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Датчики отключены"</string> <string name="device_services" msgid="1191212554435440592">"Сервисы устройства"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Без названия"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Открыть приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Настройки уведомлений приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 3a0b3a4200ba..2529f19370c0 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -879,8 +879,7 @@ <item quantity="other">යෙදුම් <xliff:g id="NUM_APPS_4">%1$d</xliff:g>ක් ඔබේ <xliff:g id="TYPE_5">%2$s</xliff:g> භාවිත කරමින් සිටිති.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"තේරුණා"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"පෞද්ගලිකත්ව සැකසීම්"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"ඔබගේ <xliff:g id="TYPES_LIST">%s</xliff:g> භාවිත කරන යෙදුම්"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"ඔබගේ <xliff:g id="TYPES_LIST">%s</xliff:g> භාවිත කරන යෙදුම්"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"සංවේදක ක්රියාවිරහිතයි"</string> <string name="device_services" msgid="1191212554435440592">"උපාංග සේවා"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"මාතෘකාවක් නැත"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> විවෘත කරන්න"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> සඳහා දැනුම්දීම් සැකසීම් විවෘත කරන්න"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 883243e65496..923384f93511 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -893,8 +893,7 @@ <item quantity="one"><xliff:g id="TYPE_1">%2$s</xliff:g> používa <xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplikácia.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Dobre"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Nastavenia ochrany súkromia"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikácia používajúca <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikácie používajúce <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -911,8 +910,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzory sú vypnuté"</string> <string name="device_services" msgid="1191212554435440592">"Služby zariadenia"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Bez názvu"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otvoriť <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otvoriť nastavenia upozornení pre <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index db40b44c4d17..d497f26926de 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -915,4 +915,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index ad6113e74c2b..db905cebb30d 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 768ae7fa2a2d..264698a779b7 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -886,8 +886,7 @@ <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> апликација користи дозволу <xliff:g id="TYPE_5">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Важи"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Подешав. приватности"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Апликација која користи дозволе <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Апликације које користе дозволе <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -903,8 +902,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Сензори су искључени"</string> <string name="device_services" msgid="1191212554435440592">"Услуге за уређаје"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Без наслова"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Отворите <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Отворите подешавања обавештења за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 0f36517ccce0..7e8446e1a427 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index a11e4d44e1c0..eb658ff17cfb 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index a8587c121815..5bcc6fec7d39 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index a512c0c0adc4..cb9b70d6bbdf 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index b8a840eedaad..6a126ff00684 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -879,8 +879,7 @@ <item quantity="one">มี <xliff:g id="NUM_APPS_0">%1$d</xliff:g> แอปพลิเคชันกำลังใช้<xliff:g id="TYPE_1">%2$s</xliff:g></item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"รับทราบ"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"การตั้งค่าความเป็นส่วนตัว"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"มีแอปกำลังใช้<xliff:g id="TYPES_LIST">%s</xliff:g>ของคุณ"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"มีหลายแอปกำลังใช้<xliff:g id="TYPES_LIST">%s</xliff:g>ของคุณ"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"เซ็นเซอร์ปิดอยู่"</string> <string name="device_services" msgid="1191212554435440592">"บริการของอุปกรณ์"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"ไม่มีชื่อ"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"เปิด <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"เปิดการตั้งค่าการแจ้งเตือนสำหรับ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 72c5eacf806c..1550787b4b27 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -879,8 +879,7 @@ <item quantity="other">Ginagamit ng <xliff:g id="NUM_APPS_4">%1$d</xliff:g> na application ang iyong <xliff:g id="TYPE_5">%2$s</xliff:g>.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Mga setting ng privacy"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App na gumagamit ng iyong <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Mga app na gumagamit ng iyong <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Naka-off ang mga sensor"</string> <string name="device_services" msgid="1191212554435440592">"Mga Serbisyo ng Device"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Walang pamagat"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Buksan ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Buksan ang mga setting ng notification para sa <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 5cd4e4c5f39f..93671558e3ef 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index b231c581b212..a850f213ca94 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -915,4 +915,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 90447d777794..c7bf3b0e4e0a 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> ایپلیکیشن آپ کی <xliff:g id="TYPE_1">%2$s</xliff:g> کا استعمال کر رہی ہے۔</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"سمجھ آ گئی"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"رازداری کی ترتیبات"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"ایپ آپ کی <xliff:g id="TYPES_LIST">%s</xliff:g> کا استعمال کر رہی ہیں"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"ایپس آپ کی <xliff:g id="TYPES_LIST">%s</xliff:g> کا استعمال کر رہی ہیں"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"، "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"سینسرز آف ہیں"</string> <string name="device_services" msgid="1191212554435440592">"آلہ کی سروس"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"کوئی عنوان نہیں ہے"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> کھولیں"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لئے اطلاع کی ترتیبات کھولیں"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 4a7af622bc64..48532fad0c1d 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> ta ilova <xliff:g id="TYPE_1">%2$s</xliff:g> ishlatmoqda.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Maxfiylik sozlama-ri"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"<xliff:g id="TYPES_LIST">%s</xliff:g> ishlatayotgan ilova"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Ilovalar <xliff:g id="TYPES_LIST">%s</xliff:g> ishlatmoqda"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorlar nofaol"</string> <string name="device_services" msgid="1191212554435440592">"Qurilma xizmatlari"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Nomsiz"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Ochish: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirishnoma sozlamalarini ochish"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index ad8d17cc23c1..b796503bbf3d 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -879,8 +879,7 @@ <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> ứng dụng đang dùng <xliff:g id="TYPE_1">%2$s</xliff:g> của bạn.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Cài đặt quyền riêng tư"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Ứng dụng đang sử dụng <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Các ứng dụng đang sử dụng <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Tắt cảm biến"</string> <string name="device_services" msgid="1191212554435440592">"Dịch vụ cho thiết bị"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Không có tiêu đề"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Mở <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Mở mục cài đặt thông báo dành cho <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 0330edf023e0..3a5dd5cda55d 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -899,4 +899,10 @@ <skip /> <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> <skip /> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> + <skip /> + <!-- no translation found for yes_bubbles (668809525728633841) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 01797fb83fd2..8d67f5c7a5dc 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -879,8 +879,7 @@ <item quantity="one">有 <xliff:g id="NUM_APPS_0">%1$d</xliff:g> 個應用程式正在使用您的<xliff:g id="TYPE_1">%2$s</xliff:g>。</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"知道了"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"隱私權設定"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"使用<xliff:g id="TYPES_LIST">%s</xliff:g>的應用程式"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"使用<xliff:g id="TYPES_LIST">%s</xliff:g>的應用程式"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"、 "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"感應器已關閉"</string> <string name="device_services" msgid="1191212554435440592">"裝置服務"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"無標題"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"開啟「<xliff:g id="APP_NAME">%1$s</xliff:g>」"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"開啟「<xliff:g id="APP_NAME">%1$s</xliff:g>」的通知設定"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 62b7cb667937..d8d0c07bcbc0 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -879,8 +879,7 @@ <item quantity="one">有 <xliff:g id="NUM_APPS_0">%1$d</xliff:g> 個應用程式正在使用你的<xliff:g id="TYPE_1">%2$s</xliff:g>。</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"我知道了"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"隱私權設定"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"使用<xliff:g id="TYPES_LIST">%s</xliff:g>的應用程式"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"使用<xliff:g id="TYPES_LIST">%s</xliff:g>的應用程式"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"、 "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"已關閉感應器"</string> <string name="device_services" msgid="1191212554435440592">"裝置服務"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"無標題"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"開啟「<xliff:g id="APP_NAME">%1$s</xliff:g>」"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"開啟「<xliff:g id="APP_NAME">%1$s</xliff:g>」的通知設定"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index f8bf2e39d748..2e0efcc863c7 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -879,8 +879,7 @@ <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> izinhlelo zokusebenza zisebenzisa i-<xliff:g id="TYPE_5">%2$s</xliff:g> yakho.</item> </plurals> <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ngiyezwa"</string> - <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) --> - <skip /> + <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Izilungiselelo zobumfihlo"</string> <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Uhlelo lokusebenza olusebenzisa i-<xliff:g id="TYPES_LIST">%s</xliff:g> yakho"</string> <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Izinhlelo zokusebenza ezisebenzisa i-<xliff:g id="TYPES_LIST">%s</xliff:g> yakho"</string> <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string> @@ -895,8 +894,12 @@ <string name="sensor_privacy_mode" msgid="8982771253020769598">"Izinzwa zivaliwe"</string> <string name="device_services" msgid="1191212554435440592">"Amasevisi edivayisi"</string> <string name="music_controls_no_title" msgid="5236895307087002011">"Asikho isihloko"</string> - <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) --> + <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Vula i-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="1940331766151865776">"VUla izilungiselelo zesaziso ze-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for bubbles_prompt (2684301469286150276) --> + <skip /> + <!-- no translation found for no_bubbles (7173621233904687258) --> <skip /> - <!-- no translation found for bubbles_settings_button_description (1940331766151865776) --> + <!-- no translation found for yes_bubbles (668809525728633841) --> <skip /> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 03445352e330..1e1245fe0d86 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -967,7 +967,7 @@ <!-- Height and width of App Opp icons in Ongoing App Ops dialog --> <dimen name="ongoing_appops_dialog_icon_size">24dp</dimen> <!-- Left margin of App Opp icons in Ongoing App Ops dialog --> - <dimen name="ongoing_appops_dialog_icon_margin">8dp</dimen> + <dimen name="ongoing_appops_dialog_icon_margin">12dp</dimen> <!-- Height and width of Application icons in Ongoing App Ops dialog --> <dimen name="ongoing_appops_dialog_app_icon_size">32dp</dimen> <!-- Height and width of Plus sign in Ongoing App Ops dialog --> @@ -988,12 +988,14 @@ <dimen name="ongoing_appops_chip_side_padding">6dp</dimen> <!-- Padding between background of Ongoing App Ops chip and content --> <dimen name="ongoing_appops_chip_bg_padding">0dp</dimen> - <!-- Margin between icons of Ongoing App Ops chip --> - <dimen name="ongoing_appops_chip_icon_margin">4dp</dimen> + <!-- Margin between icons of Ongoing App Ops chip when QQS--> + <dimen name="ongoing_appops_chip_icon_margin_collapsed">0dp</dimen> + <!-- Margin between icons of Ongoing App Ops chip when QS--> + <dimen name="ongoing_appops_chip_icon_margin_expanded">8dp</dimen> <!-- Icon size of Ongoing App Ops chip --> <dimen name="ongoing_appops_chip_icon_size">18dp</dimen> <!-- Radius of Ongoing App Ops chip corners --> - <dimen name="ongoing_appops_chip_bg_corner_radius">12dp</dimen> + <dimen name="ongoing_appops_chip_bg_corner_radius">4dp</dimen> <!-- Text size for Ongoing App Ops dialog title --> <dimen name="ongoing_appops_dialog_title_size">20sp</dimen> <!-- Text size for Ongoing App Ops dialog items --> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index db4a6cc1d704..7d009b5a9f18 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -955,6 +955,9 @@ <!-- Interruption level: Alarms only. Optimized for narrow two-line display. [CHAR LIMIT=40] --> <string name="interruption_level_alarms_twoline">Alarms\nonly</string> + <!-- Indication on the keyguard that is shown when the device is wirelessly charging. [CHAR LIMIT=80]--> + <string name="keyguard_indication_charging_time_wireless"><xliff:g id="percentage" example="20%">%2$s</xliff:g> • Wirelessly Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%1$s</xliff:g> until full)</string> + <!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=50]--> <string name="keyguard_indication_charging_time"><xliff:g id="percentage">%2$s</xliff:g> • Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%1$s</xliff:g> until full)</string> @@ -1573,12 +1576,18 @@ <string name="inline_blocking_helper">You usually dismiss these notifications. \nKeep showing them?</string> + <!-- Notification Inline controls: button to dismiss the blocking helper [CHAR_LIMIT=25] --> + <string name="inline_done_button">Done</string> + <!-- Notification Inline controls: continue receiving notifications prompt, channel level --> <string name="inline_keep_showing">Keep showing these notifications?</string> <!-- Notification inline controls: block notifications button --> <string name="inline_stop_button">Stop notifications</string> + <!-- Notification inline controls: button to deliver notifications silently from this channel [CHAR_LIMIT=35] --> + <string name="inline_deliver_silently_button">Deliver Silently</string> + <!-- Notification inline controls: button to block notifications from this channel [CHAR_LIMIT=35] --> <string name="inline_block_button">Block</string> @@ -2301,6 +2310,9 @@ <!-- Content description for ongoing privacy chip. Use with multiple apps [CHAR LIMIT=NONE]--> <string name="ongoing_privacy_chip_content_multiple_apps">Applications are using your <xliff:g id="types_list" example="camera, location">%s</xliff:g>.</string> + <!-- Ongoing Privacy "Chip" in use text [CHAR LIMIT=10]--> + <string name="ongoing_privacy_chip_in_use">In use:</string> + <!-- Content description for ongoing privacy chip. Use with multiple apps using same app op[CHAR LIMIT=NONE]--> <plurals name="ongoing_privacy_chip_content_multiple_apps_single_op"> <item quantity="one"><xliff:g id="num_apps" example="1">%1$d</xliff:g> application is using your <xliff:g id="type" example="camera">%2$s</xliff:g>.</item> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java new file mode 100644 index 000000000000..f7ccb816b675 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java @@ -0,0 +1,113 @@ +/** + * Copyright (C) 2019 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.systemui.shared.system; + +import android.os.Looper; +import android.util.Pair; +import android.view.BatchedInputEventReceiver; +import android.view.Choreographer; +import android.view.InputChannel; +import android.view.InputEvent; +import android.view.InputEventSender; + +/** + * @see android.view.InputChannel + */ +public class InputChannelCompat { + + /** + * Callback for receiving event callbacks + */ + public interface InputEventListener { + /** + * @param ev event to be handled + */ + void onInputEvent(InputEvent ev); + } + + /** + * Creates a dispatcher and receiver pair to better handle events across threads. + */ + public static Pair<InputEventDispatcher, InputEventReceiver> createPair(String name, + Looper looper, Choreographer choreographer, InputEventListener listener) { + InputChannel[] channels = InputChannel.openInputChannelPair(name); + + InputEventDispatcher dispatcher = new InputEventDispatcher(channels[0], looper); + InputEventReceiver receiver = new InputEventReceiver(channels[1], looper, choreographer, + listener); + return Pair.create(dispatcher, receiver); + } + + /** + * @see BatchedInputEventReceiver + */ + public static class InputEventReceiver { + + private final BatchedInputEventReceiver mReceiver; + private final InputChannel mInputChannel; + + public InputEventReceiver(InputChannel inputChannel, Looper looper, + Choreographer choreographer, final InputEventListener listener) { + mInputChannel = inputChannel; + mReceiver = new BatchedInputEventReceiver(inputChannel, looper, choreographer) { + + @Override + public void onInputEvent(InputEvent event) { + listener.onInputEvent(event); + finishInputEvent(event, true /* handled */); + } + }; + } + + /** + * @see BatchedInputEventReceiver#dispose() + */ + public void dispose() { + mReceiver.dispose(); + mInputChannel.dispose(); + } + } + + /** + * @see InputEventSender + */ + public static class InputEventDispatcher { + + private final InputChannel mInputChannel; + private final InputEventSender mSender; + + private InputEventDispatcher(InputChannel inputChannel, Looper looper) { + mInputChannel = inputChannel; + mSender = new InputEventSender(inputChannel, looper) { }; + } + + /** + * @see InputEventSender#sendInputEvent(int, InputEvent) + */ + public void dispatch(InputEvent ev) { + mSender.sendInputEvent(ev.getSequenceNumber(), ev); + } + + /** + * @see InputEventSender#dispose() + */ + public void dispose() { + mSender.dispose(); + mInputChannel.dispose(); + } + } +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java index 2bdbf0bf3c22..221782e950d0 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java @@ -20,6 +20,7 @@ import android.app.WindowConfiguration; import android.graphics.Point; import android.graphics.Rect; import android.view.RemoteAnimationTarget; +import android.view.SurfaceControl; /** * @see RemoteAnimationTarget @@ -47,6 +48,8 @@ public class RemoteAnimationTargetCompat { public final boolean isNotInRecents; public final Rect contentInsets; + private final SurfaceControl mStartLeash; + public RemoteAnimationTargetCompat(RemoteAnimationTarget app) { taskId = app.taskId; mode = app.mode; @@ -59,6 +62,8 @@ public class RemoteAnimationTargetCompat { isNotInRecents = app.isNotInRecents; contentInsets = app.contentInsets; activityType = app.windowConfiguration.getActivityType(); + + mStartLeash = app.startLeash; } public static RemoteAnimationTargetCompat[] wrap(RemoteAnimationTarget[] apps) { @@ -69,4 +74,14 @@ public class RemoteAnimationTargetCompat { } return appsCompat; } + + /** + * @see SurfaceControl#release() + */ + public void release() { + leash.mSurfaceControl.release(); + if (mStartLeash != null) { + mStartLeash.release(); + } + } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index d5bd2b202803..1539582ef18b 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -299,8 +299,9 @@ public class CarrierTextController { displayText.toString().split(mSeparator.toString()), anySimReadyAndInService && !missingSimsWithSubs, subsIds); - if (mCarrierTextCallback != null) { - handler.post(() -> mCarrierTextCallback.updateCarrierInfo(info)); + final CarrierTextCallback callback = mCarrierTextCallback; + if (callback != null) { + handler.post(() -> callback.updateCarrierInfo(info)); } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index 7218acf614d4..822920e63460 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -1,5 +1,6 @@ package com.android.keyguard; +import android.app.WallpaperManager; import android.content.Context; import android.graphics.Paint; import android.graphics.Paint.Style; @@ -12,11 +13,13 @@ import android.widget.TextClock; import androidx.annotation.VisibleForTesting; +import com.android.internal.colorextraction.ColorExtractor; import com.android.keyguard.clock.ClockManager; import com.android.systemui.Dependency; +import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.plugins.ClockPlugin; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; import java.util.TimeZone; @@ -50,6 +53,8 @@ public class KeyguardClockSwitch extends RelativeLayout { * Maintain state so that a newly connected plugin can be initialized. */ private float mDarkAmount; + private boolean mSupportsDarkText; + private int[] mColorPalette; private final StatusBarStateController.StateListener mStateListener = new StatusBarStateController.StateListener() { @@ -72,6 +77,21 @@ public class KeyguardClockSwitch extends RelativeLayout { private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin; + /** + * Listener for changes to the color palette. + * + * The color palette changes when the wallpaper is changed. + */ + private SysuiColorExtractor.OnColorsChangedListener mColorsListener = (extractor, which) -> { + if ((which & WallpaperManager.FLAG_LOCK) != 0) { + if (extractor instanceof SysuiColorExtractor) { + updateColors((SysuiColorExtractor) extractor); + } else { + updateColors(Dependency.get(SysuiColorExtractor.class)); + } + } + }; + public KeyguardClockSwitch(Context context) { this(context, null); } @@ -100,6 +120,9 @@ public class KeyguardClockSwitch extends RelativeLayout { super.onAttachedToWindow(); Dependency.get(ClockManager.class).addOnClockChangedListener(mClockChangedListener); Dependency.get(StatusBarStateController.class).addCallback(mStateListener); + SysuiColorExtractor colorExtractor = Dependency.get(SysuiColorExtractor.class); + colorExtractor.addOnColorsChangedListener(mColorsListener); + updateColors(colorExtractor); } @Override @@ -107,6 +130,8 @@ public class KeyguardClockSwitch extends RelativeLayout { super.onDetachedFromWindow(); Dependency.get(ClockManager.class).removeOnClockChangedListener(mClockChangedListener); Dependency.get(StatusBarStateController.class).removeCallback(mStateListener); + Dependency.get(SysuiColorExtractor.class) + .removeOnColorsChangedListener(mColorsListener); } private void setClockPlugin(ClockPlugin plugin) { @@ -149,6 +174,9 @@ public class KeyguardClockSwitch extends RelativeLayout { mClockPlugin.setStyle(getPaint().getStyle()); mClockPlugin.setTextColor(getCurrentTextColor()); mClockPlugin.setDarkAmount(mDarkAmount); + if (mColorPalette != null) { + mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette); + } } /** @@ -159,7 +187,9 @@ public class KeyguardClockSwitch extends RelativeLayout { View bigClockView = mClockPlugin.getBigClockView(); if (bigClockView != null) { container.addView(bigClockView); - container.setVisibility(View.VISIBLE); + if (container.getVisibility() == View.GONE) { + container.setVisibility(View.VISIBLE); + } } } mBigClockContainer = container; @@ -246,6 +276,16 @@ public class KeyguardClockSwitch extends RelativeLayout { } } + private void updateColors(SysuiColorExtractor colorExtractor) { + ColorExtractor.GradientColors colors = colorExtractor.getColors(WallpaperManager.FLAG_LOCK, + true); + mSupportsDarkText = colors.supportsDarkText(); + mColorPalette = colors.getColorPalette(); + if (mClockPlugin != null) { + mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette); + } + } + @VisibleForTesting (otherwise = VisibleForTesting.NONE) ClockManager.ClockChangedListener getClockChangedListener() { return mClockChangedListener; diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java index db6127f1d573..3114708de038 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java @@ -89,7 +89,17 @@ public class BubbleClockController implements ClockPlugin { @Override public void setTextColor(int color) { mLockClock.setTextColor(color); - mDigitalClock.setTextColor(color); + } + + @Override + public void setColorPalette(boolean supportsDarkText, int[] colorPalette) { + if (colorPalette == null || colorPalette.length == 0) { + return; + } + final int length = colorPalette.length; + mDigitalClock.setTextColor(colorPalette[Math.max(0, length - 6)]); + mAnalogClock.setClockColors(colorPalette[Math.max(0, length - 6)], + colorPalette[Math.max(0, length - 3)]); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java index 3591dc82c8ec..4d8cf963ff50 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java @@ -22,6 +22,7 @@ import android.content.res.Resources; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; +import android.widget.FrameLayout.LayoutParams; import com.android.keyguard.R; @@ -80,8 +81,9 @@ public class ClockLayout extends FrameLayout { // Put digital clock in two left corner of the screen. if (mDigitalClock != null) { - mDigitalClock.setX(0.1f * getWidth() + offsetX); - mDigitalClock.setY(0.1f * getHeight() + offsetY); + LayoutParams params = (LayoutParams) mDigitalClock.getLayoutParams(); + mDigitalClock.setX(offsetX + params.leftMargin); + mDigitalClock.setY(offsetY + params.topMargin); } // Put the analog clock in the middle of the screen. diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java index 2c709e0393bd..e35cf113c111 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java @@ -78,6 +78,16 @@ public class ImageClock extends FrameLayout { mTime.setTimeZone(timeZone); } + /** + * Sets the colors to use on the clock face. + * @param dark Darker color obtained from color palette. + * @param light Lighter color obtained from color palette. + */ + public void setClockColors(int dark, int light) { + mHourHand.setColorFilter(dark); + mMinuteHand.setColorFilter(light); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java index 8734754541a6..3c9a4f821c62 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java @@ -76,10 +76,12 @@ public class StretchAnalogClock extends View { } /** - * Set the color of the minute hand. + * Set the colors to use on the clock face. + * @param dark Darker color obtained from color palette. + * @param light Lighter color obtained from color palette. */ - public void setMinuteHandColor(int color) { - mMinutePaint.setColor(color); + public void setClockColor(int dark, int light) { + mHourPaint.setColor(dark); invalidate(); } diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java index 0a39158cd4be..c4651149521c 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java @@ -89,8 +89,17 @@ public class StretchAnalogClockController implements ClockPlugin { @Override public void setTextColor(int color) { mLockClock.setTextColor(color); - mDigitalClock.setTextColor(color); - mAnalogClock.setMinuteHandColor(color); + } + + @Override + public void setColorPalette(boolean supportsDarkText, int[] colorPalette) { + if (colorPalette == null || colorPalette.length == 0) { + return; + } + final int length = colorPalette.length; + mDigitalClock.setTextColor(colorPalette[Math.max(0, length - 5)]); + mAnalogClock.setClockColor(colorPalette[Math.max(0, length - 5)], + colorPalette[Math.max(0, length - 2)]); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java index 17d929dc8a3b..2ea39c40bee2 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java @@ -87,6 +87,15 @@ public class TypeClockController implements ClockPlugin { } @Override + public void setColorPalette(boolean supportsDarkText, int[] colorPalette) { + if (colorPalette == null || colorPalette.length == 0) { + return; + } + final int length = colorPalette.length; + mTypeClock.setClockColor(colorPalette[Math.max(0, length - 5)]); + } + + @Override public void dozeTimeTick() { mTypeClock.onTimeChanged(); } diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java index 8feae53159ac..6f1b59c69865 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java @@ -43,7 +43,7 @@ public class TypographicClock extends TextView { private final Resources mResources; private final String[] mHours; private final String[] mMinutes; - private final int mAccentColor; + private int mAccentColor; private Calendar mTime; private String mDescFormat; private TimeZone mTimeZone; @@ -106,6 +106,13 @@ public class TypographicClock extends TextView { mTime.setTimeZone(timeZone); } + /** + * Sets the accent color used on the clock face. + */ + public void setClockColor(int color) { + mAccentColor = color; + } + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index c3f61eee4930..567207376996 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -42,6 +42,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.PluginDependencyProvider; import com.android.systemui.plugins.VolumeDialogController; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.power.EnhancedEstimates; import com.android.systemui.power.PowerUI; import com.android.systemui.privacy.PrivacyItemController; @@ -55,7 +56,6 @@ import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.SmartReplyController; -import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.NotificationAlertingManager; import com.android.systemui.statusbar.notification.NotificationEntryManager; diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index 9b3d7ed8f045..755d6fcffb43 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -33,6 +33,7 @@ import com.android.systemui.assist.AssistManager; import com.android.systemui.classifier.FalsingManager; import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.DismissCallbackRegistry; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.power.EnhancedEstimates; import com.android.systemui.power.EnhancedEstimatesImpl; import com.android.systemui.statusbar.KeyguardIndicationController; @@ -40,7 +41,7 @@ import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; import com.android.systemui.statusbar.ScrimView; -import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.StatusBarStateControllerImpl; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotificationData; @@ -152,6 +153,15 @@ public class SystemUIFactory { return new VolumeDialogComponent(systemUi, context); } + /** + * Provides status bar state controller implementation + */ + @Singleton + @Provides + public StatusBarStateController provideStatusBarStateController(Context context) { + return new StatusBarStateControllerImpl(); + } + @Singleton @Provides public NotificationData.KeyguardEnvironment provideKeyguardEnvironment(Context context) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 6877f5ed6b26..41bc1b29075c 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -28,6 +28,9 @@ import static com.android.systemui.statusbar.StatusBarState.SHADE; import static com.android.systemui.statusbar.notification.NotificationAlertingManager.alertAgain; import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.app.IActivityTaskManager; import android.app.INotificationManager; import android.app.Notification; import android.app.PendingIntent; @@ -35,11 +38,13 @@ import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.Point; import android.graphics.Rect; +import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.util.Log; import android.util.StatsLog; +import android.view.Display; import android.view.LayoutInflater; import android.view.ViewGroup; import android.view.WindowManager; @@ -51,7 +56,9 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; @@ -60,6 +67,7 @@ import com.android.systemui.statusbar.notification.row.NotificationInflater; import com.android.systemui.statusbar.phone.StatusBarWindowController; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; @@ -93,6 +101,8 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe private final Context mContext; private final NotificationEntryManager mNotificationEntryManager; + private final IActivityTaskManager mActivityTaskManager; + private final BubbleTaskStackListener mTaskStackListener; private BubbleStateChangeListener mStateChangeListener; private BubbleExpandListener mExpandListener; private LayoutInflater mInflater; @@ -176,6 +186,10 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe mStatusBarWindowController = statusBarWindowController; mStatusBarStateListener = new StatusBarStateListener(); Dependency.get(StatusBarStateController.class).addCallback(mStatusBarStateListener); + + mActivityTaskManager = ActivityTaskManager.getService(); + mTaskStackListener = new BubbleTaskStackListener(); + ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); } /** @@ -533,6 +547,64 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe || autoBubbleAll; } + /** + * This task stack listener is responsible for responding to tasks moved to the front + * which are on the default (main) display. When this happens, expanded bubbles must be + * collapsed so the user may interact with the app which was just moved to the front. + * <p> + * This listener is registered with SystemUI's ActivityManagerWrapper which dispatches + * these calls via a main thread Handler. + */ + @MainThread + private class BubbleTaskStackListener extends TaskStackChangeListener { + + @Nullable + private ActivityManager.StackInfo findStackInfo(int taskId) throws RemoteException { + final List<ActivityManager.StackInfo> stackInfoList = + mActivityTaskManager.getAllStackInfos(); + // Iterate through stacks from top to bottom. + final int stackCount = stackInfoList.size(); + for (int stackIndex = 0; stackIndex < stackCount; stackIndex++) { + final ActivityManager.StackInfo stackInfo = stackInfoList.get(stackIndex); + // Iterate through tasks from top to bottom. + for (int taskIndex = stackInfo.taskIds.length - 1; taskIndex >= 0; taskIndex--) { + if (stackInfo.taskIds[taskIndex] == taskId) { + return stackInfo; + } + } + } + return null; + } + + @Override + public void onTaskMovedToFront(int taskId) { + ActivityManager.StackInfo stackInfo = null; + try { + stackInfo = findStackInfo(taskId); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + if (stackInfo != null && stackInfo.displayId == Display.DEFAULT_DISPLAY + && mStackView != null) { + mStackView.collapseStack(); + } + } + + /** + * This is a workaround for the case when the activity had to be created in a new task. + * Existing code in ActivityStackSupervisor checks the display where the activity + * ultimately ended up, displays an error message toast, and calls this method instead of + * onTaskMovedToFront. + */ + // TODO(b/124058588): add requestedDisplayId to this callback, ignore unless matches + @Override + public void onActivityLaunchOnSecondaryDisplayFailed() { + if (mStackView != null) { + mStackView.collapseStack(); + } + } + } + private static boolean shouldAutoBubbleMessages(Context context) { return Settings.Secure.getInt(context.getContentResolver(), ENABLE_AUTO_BUBBLE_MESSAGES, 0) != 0; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index bf9d7ba61189..976a766dcc09 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -34,8 +34,10 @@ import android.graphics.drawable.ShapeDrawable; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Settings; +import android.service.notification.StatusBarNotification; import android.util.AttributeSet; import android.util.Log; +import android.util.StatsLog; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageButton; @@ -234,6 +236,8 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList mStackView.collapseStack(() -> { try { n.contentIntent.send(); + logBubbleClickEvent(mEntry.notification, + StatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_APP); } catch (PendingIntent.CanceledException e) { Log.w(TAG, "Failed to send intent for bubble with key: " + (mEntry != null ? mEntry.key : " null entry")); @@ -242,7 +246,11 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList } else if (id == R.id.settings_button) { Intent intent = getSettingsIntent(mEntry.notification.getPackageName(), mEntry.notification.getUid()); - mStackView.collapseStack(() -> mContext.startActivity(intent)); + mStackView.collapseStack(() -> { + mContext.startActivity(intent); + logBubbleClickEvent(mEntry.notification, + StatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS); + }); } else if (id == R.id.no_bubbles_button) { setBubblesAllowed(false); } else if (id == R.id.yes_bubbles_button) { @@ -262,6 +270,9 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList } else if (mOnBubbleBlockedListener != null) { mOnBubbleBlockedListener.onBubbleBlocked(mEntry); } + logBubbleClickEvent(mEntry.notification, + allowed ? StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_IN : + StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_OUT); } catch (RemoteException e) { Log.w(TAG, e); } @@ -318,4 +329,22 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList */ void onBubbleBlocked(NotificationEntry entry); } + + /** + * Logs bubble UI click event. + * + * @param notification the bubble notification that user is interacting with. + * @param action the user interaction enum. + */ + private void logBubbleClickEvent(StatusBarNotification notification, int action) { + StatsLog.write(StatsLog.BUBBLE_UI_CHANGED, + notification.getPackageName(), + notification.getNotification().getChannelId(), + notification.getId(), + mStackView.getBubbleIndex(mStackView.getExpandedBubble()), + mStackView.getBubbleCount(), + action, + mStackView.getNormalizedXPosition(), + mStackView.getNormalizedYPosition()); + } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 305f86655fcd..2b344f6cf195 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -41,6 +41,7 @@ import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.LinearLayout; +import androidx.annotation.MainThread; import androidx.annotation.Nullable; import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.dynamicanimation.animation.SpringAnimation; @@ -384,7 +385,10 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F /** * Collapses the stack of bubbles. + * <p> + * Must be called from the main thread. */ + @MainThread public void collapseStack() { if (mIsExpanded) { // TODO: Save opened bubble & move it to top of stack @@ -402,7 +406,10 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F /** * Expands the stack fo bubbles. + * <p> + * Must be called from the main thread. */ + @MainThread public void expandStack() { if (!mIsExpanded) { mExpandedBubble = getTopBubble(); @@ -766,7 +773,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F /** * @return the number of bubbles in the stack view. */ - private int getBubbleCount() { + public int getBubbleCount() { return mBubbleContainer.getChildCount(); } @@ -777,14 +784,14 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F * @return the index of the bubble view within the bubble stack. The range of the position * is between 0 and the bubble count minus 1. */ - private int getBubbleIndex(BubbleView bubbleView) { + public int getBubbleIndex(BubbleView bubbleView) { return mBubbleContainer.indexOfChild(bubbleView); } /** * @return the normalized x-axis position of the bubble stack rounded to 4 decimal places. */ - private float getNormalizedXPosition() { + public float getNormalizedXPosition() { return new BigDecimal(getPosition().x / mDisplaySize.x) .setScale(4, RoundingMode.CEILING.HALF_UP) .floatValue(); @@ -793,7 +800,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F /** * @return the normalized y-axis position of the bubble stack rounded to 4 decimal places. */ - private float getNormalizedYPosition() { + public float getNormalizedYPosition() { return new BigDecimal(getPosition().y / mDisplaySize.y) .setScale(4, RoundingMode.CEILING.HALF_UP) .floatValue(); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java index 2c23c0ccf614..74ddc8f6b8fc 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java @@ -22,6 +22,8 @@ import android.app.Notification; import android.app.PendingIntent; import android.content.Context; import android.graphics.Color; +import android.graphics.Insets; +import android.graphics.Point; import android.graphics.PointF; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -32,6 +34,7 @@ import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.ViewGroup; +import android.view.WindowInsets; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; @@ -266,6 +269,24 @@ public class BubbleView extends FrameLayout implements BubbleTouchHandler.Floati } } }); + mActivityView.setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> { + ActivityView activityView = (ActivityView) view; + // Here we assume that the position of the ActivityView on the screen + // remains regardless of IME status. When we move ActivityView, the + // forwardedInsets should be computed not against the current location + // and size, but against the post-moved location and size. + Point displaySize = new Point(); + view.getContext().getDisplay().getSize(displaySize); + int[] windowLocation = view.getLocationOnScreen(); + final int windowBottom = windowLocation[1] + view.getHeight(); + final int keyboardHeight = insets.getSystemWindowInsetBottom() + - insets.getStableInsetBottom(); + final int insetsBottom = Math.max(0, + windowBottom + keyboardHeight - displaySize.y); + activityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom)); + return view.onApplyWindowInsets(insets); + }); + } return mActivityView; } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java index 4ff27b1b64f0..8f215ff47855 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java @@ -35,9 +35,9 @@ import android.view.accessibility.AccessibilityManager; import com.android.systemui.Dependency; import com.android.systemui.UiOffloadThread; import com.android.systemui.analytics.DataCollector; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.util.AsyncSensorManager; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java index fdf18ce24f50..900ea72d856c 100644 --- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java +++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java @@ -48,6 +48,7 @@ import javax.inject.Singleton; @Singleton public class SysuiColorExtractor extends ColorExtractor implements Dumpable { private static final String TAG = "SysuiColorExtractor"; + private final Tonal mTonal; private boolean mWallpaperVisible; private boolean mHasBackdrop; // Colors to return when the wallpaper isn't visible @@ -61,6 +62,7 @@ public class SysuiColorExtractor extends ColorExtractor implements Dumpable { @VisibleForTesting public SysuiColorExtractor(Context context, ExtractionType type, boolean registerVisibility) { super(context, type); + mTonal = type instanceof Tonal ? (Tonal) type : new Tonal(context); mWpHiddenColors = new GradientColors(); WallpaperColors systemColors = getWallpaperColors(WallpaperManager.FLAG_SYSTEM); @@ -94,7 +96,7 @@ public class SysuiColorExtractor extends ColorExtractor implements Dumpable { } private void updateDefaultGradients(WallpaperColors colors) { - Tonal.applyFallback(colors, mWpHiddenColors); + mTonal.applyFallback(colors, mWpHiddenColors); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java index c4c8bc703802..684175cf4212 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java @@ -51,8 +51,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.R; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.NextAlarmControllerImpl; import com.android.systemui.statusbar.policy.ZenModeController; diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java index ddd9cbf209d6..aebadf936e0c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java +++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java @@ -16,6 +16,7 @@ package com.android.systemui.media; +import android.annotation.Nullable; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; @@ -24,6 +25,7 @@ import android.media.AudioAttributes; import android.media.IAudioService; import android.media.IRingtonePlayer; import android.media.Ringtone; +import android.media.VolumeShaper; import android.net.Uri; import android.os.Binder; import android.os.IBinder; @@ -78,11 +80,16 @@ public class RingtonePlayer extends SystemUI { private final Ringtone mRingtone; public Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa) { + this(token, uri, user, aa, null); + } + + Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa, + @Nullable VolumeShaper.Configuration volumeShaperConfig) { mToken = token; mRingtone = new Ringtone(getContextForUser(user), false); mRingtone.setAudioAttributes(aa); - mRingtone.setUri(uri); + mRingtone.setUri(uri, volumeShaperConfig); } @Override @@ -99,6 +106,12 @@ public class RingtonePlayer extends SystemUI { @Override public void play(IBinder token, Uri uri, AudioAttributes aa, float volume, boolean looping) throws RemoteException { + playWithVolumeShaping(token, uri, aa, volume, looping, null); + } + @Override + public void playWithVolumeShaping(IBinder token, Uri uri, AudioAttributes aa, float volume, + boolean looping, @Nullable VolumeShaper.Configuration volumeShaperConfig) + throws RemoteException { if (LOGD) { Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid=" + Binder.getCallingUid() + ")"); @@ -108,7 +121,7 @@ public class RingtonePlayer extends SystemUI { client = mClients.get(token); if (client == null) { final UserHandle user = Binder.getCallingUserHandle(); - client = new Client(token, uri, user, aa); + client = new Client(token, uri, user, aa, volumeShaperConfig); token.linkToDeath(client, 0); mClients.put(token, client); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index 82aa4737af99..9c65994425ed 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -79,6 +79,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call private static final int MSG_RESIZE_IMMEDIATE = 1; private static final int MSG_RESIZE_ANIMATE = 2; + private static final int MSG_OFFSET_ANIMATE = 3; private Context mContext; private IActivityManager mActivityManager; @@ -360,9 +361,20 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call /** * Animates the PiP to offset it from the IME or shelf. */ - void animateToOffset(Rect toBounds) { + void animateToOffset(Rect originalBounds, int offset) { cancelAnimations(); - resizeAndAnimatePipUnchecked(toBounds, SHIFT_DURATION); + adjustAndAnimatePipOffset(originalBounds, offset, SHIFT_DURATION); + } + + private void adjustAndAnimatePipOffset(Rect originalBounds, int offset, int duration) { + if (offset == 0) { + return; + } + SomeArgs args = SomeArgs.obtain(); + args.arg1 = originalBounds; + args.argi1 = offset; + args.argi2 = duration; + mHandler.sendMessage(mHandler.obtainMessage(MSG_OFFSET_ANIMATE, args)); } /** @@ -549,6 +561,31 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call return true; } + case MSG_OFFSET_ANIMATE: { + SomeArgs args = (SomeArgs) msg.obj; + Rect originalBounds = (Rect) args.arg1; + final int offset = args.argi1; + final int duration = args.argi2; + try { + StackInfo stackInfo = mActivityTaskManager.getStackInfo( + WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED); + if (stackInfo == null) { + // In the case where we've already re-expanded or dismissed the PiP, then + // just skip the resize + return true; + } + + mActivityTaskManager.offsetPinnedStackBounds(stackInfo.stackId, originalBounds, + 0/* xOffset */, offset, duration); + Rect toBounds = new Rect(originalBounds); + toBounds.offset(0, offset); + mBounds.set(toBounds); + } catch (RemoteException e) { + Log.e(TAG, "Could not animate offset pinned stack with offset: " + offset, e); + } + return true; + } + default: return false; } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 6a9f24c619fe..cef1b6b1d93b 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -346,12 +346,11 @@ public class PipTouchHandler { } private void animateToOffset(Rect animatingBounds, Rect toAdjustedBounds) { - final Rect bounds = new Rect(animatingBounds); - bounds.offset(0, toAdjustedBounds.bottom - bounds.top); + int offset = toAdjustedBounds.bottom - animatingBounds.top; // In landscape mode, PIP window can go offset while launching IME. We want to align the // the top of the PIP window with the top of the movement bounds in that case. - bounds.offset(0, Math.max(0, mMovementBounds.top - bounds.top)); - mMotionHelper.animateToOffset(bounds); + offset += Math.max(0, mMovementBounds.top - animatingBounds.top); + mMotionHelper.animateToOffset(animatingBounds, offset); } private void onRegistrationChanged(boolean isRegistered) { diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index f0543454073d..c43f5728aaa2 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -54,6 +54,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.time.Duration; import java.util.Arrays; +import java.util.concurrent.Future; public class PowerUI extends SystemUI { static final String TAG = "PowerUI"; @@ -80,6 +81,7 @@ public class PowerUI extends SystemUI { private Estimate mLastEstimate; private boolean mLowWarningShownThisChargeCycle; private boolean mSevereWarningShownThisChargeCycle; + private Future mLastShowWarningTask; private int mLowBatteryAlertCloseLevel; private final int[] mLowBatteryReminderLevels = new int[2]; @@ -247,7 +249,10 @@ public class PowerUI extends SystemUI { } // Show the correct version of low battery warning if needed - ThreadUtils.postOnBackgroundThread(() -> { + if (mLastShowWarningTask != null) { + mLastShowWarningTask.cancel(true); + } + mLastShowWarningTask = ThreadUtils.postOnBackgroundThread(() -> { maybeShowBatteryWarning( oldBatteryLevel, plugged, oldPlugged, oldBucket, bucket); }); @@ -276,7 +281,7 @@ public class PowerUI extends SystemUI { estimate = mEnhancedEstimates.getEstimate(); mLastEstimate = estimate; } - // Turbo is not always booted once SysUI is running so we have ot make sure we actually + // Turbo is not always booted once SysUI is running so we have to make sure we actually // get data back if (estimate != null) { mTimeRemaining = estimate.estimateMillis; @@ -355,13 +360,26 @@ public class PowerUI extends SystemUI { // Only show the low warning once per charge cycle & no battery saver final boolean canShowWarning = !mLowWarningShownThisChargeCycle && !isPowerSaver && (timeRemaining < mEnhancedEstimates.getLowWarningThreshold() - || mBatteryLevel <= warnLevel); + || mBatteryLevel <= warnLevel); // Only show the severe warning once per charge cycle final boolean canShowSevereWarning = !mSevereWarningShownThisChargeCycle && (timeRemaining < mEnhancedEstimates.getSevereWarningThreshold() - || mBatteryLevel <= critLevel); - + || mBatteryLevel <= critLevel); + + final boolean canShow = canShowWarning || canShowSevereWarning; + if (DEBUG) { + Slog.d(TAG, "Enhanced trigger is: " + canShow + "\nwith values: " + + " mLowWarningShownThisChargeCycle: " + mLowWarningShownThisChargeCycle + + " mSevereWarningShownThisChargeCycle: " + mSevereWarningShownThisChargeCycle + + " mEnhancedEstimates.timeremaining: " + timeRemaining + + " mBatteryLevel: " + mBatteryLevel + + " canShowWarning: " + canShowWarning + + " canShowSevereWarning: " + canShowSevereWarning + + " plugged: " + plugged + + " batteryStatus: " + batteryStatus + + " isPowerSaver: " + isPowerSaver); + } return canShowWarning || canShowSevereWarning; } diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt index 65ed889f34e1..ecbf0246a8ba 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt @@ -16,6 +16,7 @@ package com.android.systemui.privacy import android.content.Context import android.util.AttributeSet +import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.LinearLayout @@ -29,14 +30,25 @@ class OngoingPrivacyChip @JvmOverloads constructor( defStyleRes: Int = 0 ) : LinearLayout(context, attrs, defStyleAttrs, defStyleRes) { - private val iconMargin = - context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_margin) + private val iconMarginExpanded = context.resources.getDimensionPixelSize( + R.dimen.ongoing_appops_chip_icon_margin_expanded) + private val iconMarginCollapsed = context.resources.getDimensionPixelSize( + R.dimen.ongoing_appops_chip_icon_margin_collapsed) private val iconSize = context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_size) - val iconColor = context.resources.getColor( + private val iconColor = context.resources.getColor( R.color.status_bar_clock_color, context.theme) + private val backgroundDrawable = context.getDrawable(R.drawable.privacy_chip_bg) private lateinit var text: TextView private lateinit var iconsContainer: LinearLayout + private lateinit var inUseText: TextView + var expanded = false + set(value) { + if (value != field) { + field = value + updateView() + } + } var builder = PrivacyDialogBuilder(context, emptyList<PrivacyItem>()) var privacyList = emptyList<PrivacyItem>() set(value) { @@ -48,15 +60,18 @@ class OngoingPrivacyChip @JvmOverloads constructor( override fun onFinishInflate() { super.onFinishInflate() + inUseText = findViewById(R.id.in_use_text) text = findViewById(R.id.text_container) iconsContainer = findViewById(R.id.icons_container) } // Should only be called if the builder icons or app changed private fun updateView() { + inUseText.visibility = if (expanded) View.GONE else View.VISIBLE + background = if (expanded) backgroundDrawable else null fun setIcons(dialogBuilder: PrivacyDialogBuilder, iconsContainer: ViewGroup) { iconsContainer.removeAllViews() - dialogBuilder.generateIcons().forEach { + dialogBuilder.generateIcons().forEachIndexed { i, it -> it.mutate() it.setTint(iconColor) val image = ImageView(context).apply { @@ -64,17 +79,19 @@ class OngoingPrivacyChip @JvmOverloads constructor( scaleType = ImageView.ScaleType.CENTER_INSIDE } iconsContainer.addView(image, iconSize, iconSize) - val lp = image.layoutParams as MarginLayoutParams - lp.marginStart = iconMargin - image.layoutParams = lp + if (i != 0) { + val lp = image.layoutParams as MarginLayoutParams + lp.marginStart = if (expanded) iconMarginExpanded else iconMarginCollapsed + image.layoutParams = lp + } } } if (!privacyList.isEmpty()) { generateContentDescription() setIcons(builder, iconsContainer) - text.visibility = if (builder.types.size == 1) VISIBLE else GONE - if (builder.types.size == 1) { + text.visibility = if (builder.types.size == 1 && expanded) VISIBLE else GONE + if (builder.types.size == 1 && expanded) { if (builder.app != null) { text.setText(builder.app?.applicationName) } else { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java index b865ce8d261a..f91c9d944439 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java @@ -189,6 +189,7 @@ public class QSFooterImpl extends FrameLayout implements QSFooter, addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> updateAnimator(right - left)); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + updateEverything(); } private void updateAnimator(int width) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 74e82b270aa0..ee9255c54a62 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -124,6 +124,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements private TintedIconManager mIconManager; private TouchAnimator mStatusIconsAlphaAnimator; private TouchAnimator mHeaderTextContainerAlphaAnimator; + private TouchAnimator mPrivacyChipAlphaAnimator; private View mSystemIconsView; private View mQuickQsStatusIcons; @@ -212,6 +213,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements mNextAlarmTextView = findViewById(R.id.next_alarm_text); mRingerModeIcon = findViewById(R.id.ringer_mode_icon); mRingerModeTextView = findViewById(R.id.ringer_mode_text); + mPrivacyChip = findViewById(R.id.privacy_chip); + mPrivacyChip.setOnClickListener(this); updateResources(); @@ -230,8 +233,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements mClockView = findViewById(R.id.clock); mClockView.setOnClickListener(this); mDateView = findViewById(R.id.date); - mPrivacyChip = findViewById(R.id.privacy_chip); - mPrivacyChip.setOnClickListener(this); mSpace = findViewById(R.id.space); // Tint for the battery icons are handled in setupHost() @@ -383,6 +384,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements updateStatusIconAlphaAnimator(); updateHeaderTextContainerAlphaAnimator(); + updatePrivacyChipAlphaAnimator(); } private void updateStatusIconAlphaAnimator() { @@ -398,6 +400,12 @@ public class QuickStatusBarHeader extends RelativeLayout implements .build(); } + private void updatePrivacyChipAlphaAnimator() { + mPrivacyChipAlphaAnimator = new TouchAnimator.Builder() + .addFloat(mPrivacyChip, "alpha", 1, 0, 1) + .build(); + } + public void setExpanded(boolean expanded) { if (mExpanded == expanded) return; mExpanded = expanded; @@ -431,6 +439,10 @@ public class QuickStatusBarHeader extends RelativeLayout implements if (mHeaderTextContainerAlphaAnimator != null) { mHeaderTextContainerAlphaAnimator.setPosition(keyguardExpansionFraction); } + if (mPrivacyChipAlphaAnimator != null) { + mPrivacyChip.setExpanded(expansionFraction > 0.5); + mPrivacyChipAlphaAnimator.setPosition(keyguardExpansionFraction); + } // Check the original expansion fraction - we don't want to show the tooltip until the // panel is pulled all the way out. diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java index e1a43785b5c4..e275690f70aa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java @@ -58,10 +58,10 @@ import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.State; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.PagedTileLayout.TilePage; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QuickStatusBarHeader; -import com.android.systemui.statusbar.StatusBarStateController; import java.util.ArrayList; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 2811505d738c..164f5826061e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -47,7 +47,8 @@ import com.android.settingslib.Utils; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.phone.KeyguardIndicationTextView; import com.android.systemui.statusbar.phone.LockIcon; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; @@ -423,22 +424,28 @@ public class KeyguardIndicationController implements StateListener { final boolean hasChargingTime = chargingTimeRemaining > 0; int chargingId; - switch (mChargingSpeed) { - case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST: - chargingId = hasChargingTime - ? R.string.keyguard_indication_charging_time_fast - : R.string.keyguard_plugged_in_charging_fast; - break; - case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY: - chargingId = hasChargingTime - ? R.string.keyguard_indication_charging_time_slowly - : R.string.keyguard_plugged_in_charging_slowly; - break; - default: - chargingId = hasChargingTime - ? R.string.keyguard_indication_charging_time - : R.string.keyguard_plugged_in; - break; + if (mPowerPluggedInWired) { + switch (mChargingSpeed) { + case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST: + chargingId = hasChargingTime + ? R.string.keyguard_indication_charging_time_fast + : R.string.keyguard_plugged_in_charging_fast; + break; + case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY: + chargingId = hasChargingTime + ? R.string.keyguard_indication_charging_time_slowly + : R.string.keyguard_plugged_in_charging_slowly; + break; + default: + chargingId = hasChargingTime + ? R.string.keyguard_indication_charging_time + : R.string.keyguard_plugged_in; + break; + } + } else { + chargingId = hasChargingTime + ? R.string.keyguard_indication_charging_time_wireless + : R.string.keyguard_plugged_in_wireless; } String percentage = NumberFormat.getPercentInstance() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index 4f9d4282dae8..6a49b804f5ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -44,8 +44,9 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.recents.OverviewProxyService; -import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.NotificationEntry; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index 98a3a547ed2c..490317b188c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -47,6 +47,7 @@ import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.Interpolators; import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 546b2e9df7b5..01b0bb14c7ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -26,7 +26,6 @@ import android.graphics.Rect; import android.os.SystemProperties; import android.util.AttributeSet; import android.util.Log; -import android.util.MathUtils; import android.view.DisplayCutout; import android.view.View; import android.view.ViewGroup; @@ -38,7 +37,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -118,8 +118,8 @@ public class NotificationShelf extends ActivatableNotificationView implements @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - Dependency.get(StatusBarStateController.class) - .addCallback(this, StatusBarStateController.RANK_SHELF); + ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class)) + .addCallback(this, SysuiStatusBarStateController.RANK_SHELF); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java index f2ff85bb226c..662cf514b977 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java @@ -61,7 +61,7 @@ public class NotificationViewHierarchyManager { protected final NotificationLockscreenUserManager mLockscreenUserManager; protected final NotificationGroupManager mGroupManager; protected final VisualStabilityManager mVisualStabilityManager; - private final StatusBarStateController mStatusBarStateController; + private final StatusBarStateControllerImpl mStatusBarStateController; private final NotificationEntryManager mEntryManager; // Lazy @@ -82,7 +82,7 @@ public class NotificationViewHierarchyManager { NotificationLockscreenUserManager notificationLockscreenUserManager, NotificationGroupManager groupManager, VisualStabilityManager visualStabilityManager, - StatusBarStateController statusBarStateController, + StatusBarStateControllerImpl statusBarStateController, NotificationEntryManager notificationEntryManager, Lazy<ShadeController> shadeController) { mLockscreenUserManager = notificationLockscreenUserManager; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index 54bce1c00354..ad5aa57f12ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2019 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. @@ -11,27 +11,22 @@ * 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 + * limitations under the License. */ package com.android.systemui.statusbar; -import static java.lang.annotation.RetentionPolicy.SOURCE; - import android.animation.ObjectAnimator; import android.animation.ValueAnimator; -import android.annotation.IntDef; import android.util.FloatProperty; import android.view.animation.Interpolator; import com.android.internal.annotations.GuardedBy; import com.android.systemui.Interpolators; -import com.android.systemui.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; -import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.CallbackController; -import java.lang.annotation.Retention; import java.util.ArrayList; import java.util.Comparator; @@ -42,24 +37,25 @@ import javax.inject.Singleton; * Tracks and reports on {@link StatusBarState}. */ @Singleton -public class StatusBarStateController implements CallbackController<StateListener> { +public class StatusBarStateControllerImpl implements SysuiStatusBarStateController, + CallbackController<StateListener> { private static final String TAG = "SbStateController"; private static final int MAX_STATE = StatusBarState.FULLSCREEN_USER_SWITCHER; private static final int MIN_STATE = StatusBarState.SHADE; - private static final Comparator <RankedListener> mComparator - = (o1, o2) -> Integer.compare(o1.rank, o2.rank); - private static final FloatProperty<StatusBarStateController> SET_DARK_AMOUNT_PROPERTY = - new FloatProperty<StatusBarStateController>("mDozeAmount") { + private static final Comparator<RankedListener> sComparator = + Comparator.comparingInt(o -> o.mRank); + private static final FloatProperty<StatusBarStateControllerImpl> SET_DARK_AMOUNT_PROPERTY = + new FloatProperty<StatusBarStateControllerImpl>("mDozeAmount") { @Override - public void setValue(StatusBarStateController object, float value) { + public void setValue(StatusBarStateControllerImpl object, float value) { object.setDozeAmountInternal(value); } @Override - public Float get(StatusBarStateController object) { + public Float get(StatusBarStateControllerImpl object) { return object.mDozeAmount; } }; @@ -95,29 +91,16 @@ public class StatusBarStateController implements CallbackController<StateListene */ private Interpolator mDozeInterpolator = Interpolators.FAST_OUT_SLOW_IN; - // TODO: b/115739177 (remove this explicit ordering if we can) - @Retention(SOURCE) - @IntDef({RANK_STATUS_BAR, RANK_STATUS_BAR_WINDOW_CONTROLLER, RANK_STACK_SCROLLER, RANK_SHELF}) - public @interface SbStateListenerRank {} - // This is the set of known dependencies when updating StatusBarState - public static final int RANK_STATUS_BAR = 0; - public static final int RANK_STATUS_BAR_WINDOW_CONTROLLER = 1; - public static final int RANK_STACK_SCROLLER = 2; - public static final int RANK_SHELF = 3; - @Inject - public StatusBarStateController() { + public StatusBarStateControllerImpl() { } + @Override public int getState() { return mState; } - /** - * Update the status bar state - * @param state see {@link StatusBarState} for valid options - * @return {@code true} if the state changed, else {@code false} - */ + @Override public boolean setState(int state) { if (state > MAX_STATE || state < MIN_STATE) { throw new IllegalArgumentException("Invalid state " + state); @@ -127,40 +110,38 @@ public class StatusBarStateController implements CallbackController<StateListene } synchronized (mListeners) { for (RankedListener rl : new ArrayList<>(mListeners)) { - rl.listener.onStatePreChange(mState, state); + rl.mListener.onStatePreChange(mState, state); } mLastState = mState; mState = state; for (RankedListener rl : new ArrayList<>(mListeners)) { - rl.listener.onStateChanged(mState); + rl.mListener.onStateChanged(mState); } for (RankedListener rl : new ArrayList<>(mListeners)) { - rl.listener.onStatePostChange(); + rl.mListener.onStatePostChange(); } } return true; } + @Override public boolean isDozing() { return mIsDozing; } + @Override public float getDozeAmount() { return mDozeAmount; } + @Override public float getInterpolatedDozeAmount() { return mDozeInterpolator.getInterpolation(mDozeAmount); } - /** - * Update the dozing state from {@link StatusBar}'s perspective - * @param isDozing well, are we dozing? - * @return {@code true} if the state changed, else {@code false} - */ - @SuppressWarnings("UnusedReturnValue") + @Override public boolean setIsDozing(boolean isDozing) { if (mIsDozing == isDozing) { return false; @@ -170,19 +151,14 @@ public class StatusBarStateController implements CallbackController<StateListene synchronized (mListeners) { for (RankedListener rl : new ArrayList<>(mListeners)) { - rl.listener.onDozingChanged(isDozing); + rl.mListener.onDozingChanged(isDozing); } } return true; } - /** - * Changes the current doze amount. - * - * @param dozeAmount New doze/dark amount. - * @param animated If change should be animated or not. This will cancel current animations. - */ + @Override public void setDozeAmount(float dozeAmount, boolean animated) { if (mDarkAnimator != null && mDarkAnimator.isRunning()) { if (animated && mDozeAmountTarget == dozeAmount) { @@ -217,27 +193,32 @@ public class StatusBarStateController implements CallbackController<StateListene float interpolatedAmount = mDozeInterpolator.getInterpolation(dozeAmount); synchronized (mListeners) { for (RankedListener rl : new ArrayList<>(mListeners)) { - rl.listener.onDozeAmountChanged(mDozeAmount, interpolatedAmount); + rl.mListener.onDozeAmountChanged(mDozeAmount, interpolatedAmount); } } } + @Override public boolean goingToFullShade() { return mState == StatusBarState.SHADE && mLeaveOpenOnKeyguardHide; } + @Override public void setLeaveOpenOnKeyguardHide(boolean leaveOpen) { mLeaveOpenOnKeyguardHide = leaveOpen; } + @Override public boolean leaveOpenOnKeyguardHide() { return mLeaveOpenOnKeyguardHide; } + @Override public boolean fromShadeLocked() { return mLastState == StatusBarState.SHADE_LOCKED; } + @Override public void addCallback(StateListener listener) { synchronized (mListeners) { addListenerInternalLocked(listener, Integer.MAX_VALUE); @@ -254,6 +235,8 @@ public class StatusBarStateController implements CallbackController<StateListene * StatusBarState out of StatusBar.java. Any new listeners should be built not to need ranking * (i.e., they are non-dependent on the order of operations of StatusBarState listeners). */ + @Deprecated + @Override public void addCallback(StateListener listener, @SbStateListenerRank int rank) { synchronized (mListeners) { addListenerInternalLocked(listener, rank); @@ -264,91 +247,38 @@ public class StatusBarStateController implements CallbackController<StateListene private void addListenerInternalLocked(StateListener listener, int rank) { // Protect against double-subscribe for (RankedListener rl : mListeners) { - if (rl.listener.equals(listener)) { + if (rl.mListener.equals(listener)) { return; } } - RankedListener rl = new RankedListener(listener, rank); + RankedListener rl = new SysuiStatusBarStateController.RankedListener(listener, rank); mListeners.add(rl); - mListeners.sort(mComparator); + mListeners.sort(sComparator); } + + @Override public void removeCallback(StateListener listener) { synchronized (mListeners) { - mListeners.removeIf((it) -> it.listener.equals(listener)); + mListeners.removeIf((it) -> it.mListener.equals(listener)); } } + @Override public void setKeyguardRequested(boolean keyguardRequested) { mKeyguardRequested = keyguardRequested; } + @Override public boolean isKeyguardRequested() { return mKeyguardRequested; } - public static String describe(int state) { - return StatusBarState.toShortString(state); - } - - private class RankedListener { - private final StateListener listener; - private final int rank; - - private RankedListener(StateListener l, int r) { - listener = l; - rank = r; - } - } - /** - * Listener for StatusBarState updates + * Returns String readable state of status bar from {@link StatusBarState} */ - public interface StateListener { - - /** - * Callback before the new state is applied, for those who need to preempt the change. - * - * @param oldState state before the change - * @param newState new state to be applied in {@link #onStateChanged} - */ - public default void onStatePreChange(int oldState, int newState) { - } - - /** - * Callback after all listeners have had a chance to update based on the state change - */ - public default void onStatePostChange() { - } - - /** - * Required callback. Get the new state and do what you will with it. Keep in mind that - * other listeners are typically unordered and don't rely on your work being done before - * other peers. - * - * Only called if the state is actually different. - * - * @param newState the new {@link StatusBarState} - */ - default void onStateChanged(int newState) { - } - - /** - * Callback to be notified when Dozing changes. Dozing is stored separately from state. - * - * @param isDozing {@code true} if dozing according to {@link StatusBar} - */ - public default void onDozingChanged(boolean isDozing) {} - - /** - * Callback to be notified when the doze amount changes. Useful for animations. - * Note: this will be called for each animation frame. Please be careful to avoid - * performance regressions. - * - * @param linear A number from 0 to 1, where 1 means that the device is dozing. - * @param eased Same as {@code linear} but transformed by an interpolator. - */ - default void onDozeAmountChanged(float linear, float eased) {} + public static String describe(int state) { + return StatusBarState.toShortString(state); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java new file mode 100644 index 000000000000..dc5e1e913b4c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2019 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.systemui.statusbar; + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; + +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.phone.StatusBar; + +import java.lang.annotation.Retention; + +/** + * Sends updates to {@link StateListener}s about changes to the status bar state and dozing state + */ +public interface SysuiStatusBarStateController extends StatusBarStateController { + + // TODO: b/115739177 (remove this explicit ordering if we can) + @Retention(SOURCE) + @IntDef({RANK_STATUS_BAR, RANK_STATUS_BAR_WINDOW_CONTROLLER, RANK_STACK_SCROLLER, RANK_SHELF}) + @interface SbStateListenerRank {} + // This is the set of known dependencies when updating StatusBarState + int RANK_STATUS_BAR = 0; + int RANK_STATUS_BAR_WINDOW_CONTROLLER = 1; + int RANK_STACK_SCROLLER = 2; + int RANK_SHELF = 3; + + /** + * Add a listener and a rank based on the priority of this message + * @param listener the listener + * @param rank the order in which you'd like to be called. Ranked listeners will be + * notified before unranked, and we will sort ranked listeners from low to high + * + * @deprecated This method exists only to solve latent inter-dependencies from refactoring + * StatusBarState out of StatusBar.java. Any new listeners should be built not to need ranking + * (i.e., they are non-dependent on the order of operations of StatusBarState listeners). + */ + @Deprecated + void addCallback(StateListener listener, int rank); + + /** + * Update the status bar state + * @param state see {@link StatusBarState} for valid options + * @return {@code true} if the state changed, else {@code false} + */ + boolean setState(int state); + + /** + * Update the dozing state from {@link StatusBar}'s perspective + * @param isDozing well, are we dozing? + * @return {@code true} if the state changed, else {@code false} + */ + boolean setIsDozing(boolean isDozing); + + /** + * Changes the current doze amount. + * + * @param dozeAmount New doze/dark amount. + * @param animated If change should be animated or not. This will cancel current animations. + */ + void setDozeAmount(float dozeAmount, boolean animated); + + /** + * Sets whether to leave status bar open when hiding keyguard + */ + void setLeaveOpenOnKeyguardHide(boolean leaveOpen); + + /** + * Whether to leave status bar open when hiding keyguard + */ + boolean leaveOpenOnKeyguardHide(); + + /** + * Interpolated doze amount + */ + float getInterpolatedDozeAmount(); + + /** + * Whether status bar is going to full shade + */ + boolean goingToFullShade(); + + /** + * Whether the previous state of the status bar was the shade locked + */ + boolean fromShadeLocked(); + + /** + * Set keyguard requested + */ + void setKeyguardRequested(boolean keyguardRequested); + + /** + * Is keyguard requested + */ + boolean isKeyguardRequested(); + + /** + * Listener with rankings SbStateListenerRank that have dependencies so must be updated + * in a certain order + */ + class RankedListener { + final StateListener mListener; + final int mRank; + + RankedListener(StateListener l, int r) { + mListener = l; + mRank = r; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java index c50f10b55a71..7cbe1a3e279e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java @@ -35,8 +35,8 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationPresenter; -import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.policy.HeadsUpManager; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java index 54ed0d9cd8ce..8b522a2033f8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java @@ -16,8 +16,10 @@ package com.android.systemui.statusbar.notification.collection; +import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; +import android.app.Person; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.SnoozeCriterion; @@ -235,8 +237,11 @@ public class NotificationData { if (mRankingMap != null) { getRanking(statusBarNotification.getKey(), mTmpRanking); if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT - || statusBarNotification.getNotification().isForegroundService() - || statusBarNotification.getNotification().hasMediaSession()) { + || isImportantOngoing(statusBarNotification.getNotification()) + || statusBarNotification.getNotification().hasMediaSession() + || hasPerson(statusBarNotification.getNotification()) + || hasStyle(statusBarNotification.getNotification(), + Notification.MessagingStyle.class)) { return true; } if (mGroupManager.isSummaryOfGroup(statusBarNotification)) { @@ -252,6 +257,24 @@ public class NotificationData { return false; } + private boolean isImportantOngoing(Notification notification) { + return notification.isForegroundService() + && mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_LOW; + } + + private boolean hasStyle(Notification notification, Class targetStyle) { + Class<? extends Notification.Style> style = notification.getNotificationStyle(); + return targetStyle.equals(style); + } + + private boolean hasPerson(Notification notification) { + // TODO: cache favorite and recent contacts to check contact affinity + ArrayList<Person> people = notification.extras != null + ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST) + : new ArrayList<>(); + return people != null && !people.isEmpty(); + } + public boolean isAmbient(String key) { if (mRankingMap != null) { getRanking(key, mTmpRanking); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java index 43b5503682cc..a1fcbebecea1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java @@ -30,6 +30,9 @@ public class NotificationCounters { /** Counter tag for when the user hits 'stop notifications' in the blocking helper. */ public static final String BLOCKING_HELPER_STOP_NOTIFICATIONS = "blocking_helper_stop_notifications"; + /** Counter tag for when the user hits 'deliver silently' in the blocking helper. */ + public static final String BLOCKING_HELPER_DELIVER_SILENTLY = + "blocking_helper_deliver_silently"; /** Counter tag for when the user hits 'show silently' in the blocking helper. */ public static final String BLOCKING_HELPER_TOGGLE_SILENT = "blocking_helper_toggle_silent"; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java index 5e5241910e7f..c4ecb8259a4f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java @@ -33,9 +33,9 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.UiOffloadThread; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.NotificationListener; -import com.android.systemui.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index 80956159c20b..1dc48d4b18b9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -68,6 +68,7 @@ import java.util.List; public class NotificationContentView extends FrameLayout { private static final String TAG = "NotificationContentView"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); public static final int VISIBLE_TYPE_CONTRACTED = 0; public static final int VISIBLE_TYPE_EXPANDED = 1; public static final int VISIBLE_TYPE_HEADSUP = 2; @@ -1319,6 +1320,14 @@ public class NotificationContentView extends FrameLayout { SmartRepliesAndActions smartRepliesAndActions = chooseSmartRepliesAndActions(mSmartReplyConstants, entry); + if (DEBUG) { + Log.d(TAG, String.format("Adding suggestions for %s, %d actions, and %d replies.", + entry.notification.getKey(), + smartRepliesAndActions.smartActions == null ? 0 : + smartRepliesAndActions.smartActions.actions.size(), + smartRepliesAndActions.smartReplies == null ? 0 : + smartRepliesAndActions.smartReplies.choices.length)); + } applyRemoteInput(entry, smartRepliesAndActions.hasFreeformRemoteInput); applySmartReplyView(smartRepliesAndActions, entry); @@ -1341,6 +1350,10 @@ public class NotificationContentView extends FrameLayout { notification.findRemoteInputActionPair(true /* freeform */); if (!smartReplyConstants.isEnabled()) { + if (DEBUG) { + Log.d(TAG, "Smart suggestions not enabled, not adding suggestions for " + + entry.notification.getKey()); + } return new SmartRepliesAndActions(null, null, freeformRemoteInputActionPair != null); } // Only use smart replies from the app if they target P or above. We have this check because diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index aa221993cd82..fea01ef61df9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -42,11 +42,11 @@ import com.android.internal.logging.nano.MetricsProto; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java index c7b2fab54fff..37237317fc95 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java @@ -84,6 +84,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G public static final int ACTION_UNDO = 1; public static final int ACTION_TOGGLE_SILENT = 2; public static final int ACTION_BLOCK = 3; + public static final int ACTION_DELIVER_SILENTLY = 4; private INotificationManager mINotificationManager; private PackageManager mPm; @@ -135,30 +136,26 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G }; private OnClickListener mOnToggleSilent = v -> { - Runnable saveImportance = () -> { - swapContent(ACTION_TOGGLE_SILENT, true /* animate */); - if (mIsForBlockingHelper) { - mMetricsLogger.write(getLogMaker() - .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER) - .setType(MetricsEvent.TYPE_ACTION) - .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME)); - } - }; - if (mCheckSaveListener != null) { - mCheckSaveListener.checkSave(saveImportance, mSbn); - } else { - saveImportance.run(); - } + handleSaveImportance(ACTION_TOGGLE_SILENT, MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME); + }; + + private OnClickListener mOnDeliverSilently = v -> { + handleSaveImportance( + ACTION_DELIVER_SILENTLY, MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT); }; private OnClickListener mOnStopOrMinimizeNotifications = v -> { + handleSaveImportance(ACTION_BLOCK, MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED); + }; + + private void handleSaveImportance(int action, int metricsSubtype) { Runnable saveImportance = () -> { - swapContent(ACTION_BLOCK, true /* animate */); + swapContent(action, true /* animate */); if (mIsForBlockingHelper) { mMetricsLogger.write(getLogMaker() .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER) .setType(MetricsEvent.TYPE_ACTION) - .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED)); + .setSubtype(metricsSubtype)); } }; if (mCheckSaveListener != null) { @@ -166,7 +163,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } else { saveImportance.run(); } - }; + } private OnClickListener mOnUndo = v -> { // Reset exit counter that we'll log and record an undo event separately (not an exit event) @@ -283,8 +280,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G mMetricsLogger.write(notificationControlsLogMaker()); } - - private void bindHeader() throws RemoteException { // Package name Drawable pkgicon = null; @@ -479,17 +474,21 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G findViewById(R.id.block_or_minimize).setVisibility(VISIBLE); findViewById(R.id.interruptiveness_settings).setVisibility(GONE); View block = findViewById(R.id.block); - TextView keep = findViewById(R.id.keep); + TextView done = findViewById(R.id.done); View minimize = findViewById(R.id.minimize); + View deliverSilently = findViewById(R.id.deliver_silently); + block.setOnClickListener(mOnStopOrMinimizeNotifications); - keep.setOnClickListener(mOnKeepShowing); + done.setOnClickListener(mOnKeepShowing); minimize.setOnClickListener(mOnStopOrMinimizeNotifications); + deliverSilently.setOnClickListener(mOnDeliverSilently); if (mIsNonblockable) { - keep.setText(android.R.string.ok); + done.setText(android.R.string.ok); block.setVisibility(GONE); minimize.setVisibility(GONE); + deliverSilently.setVisibility(GONE); } else if (mIsForeground) { block.setVisibility(GONE); minimize.setVisibility(VISIBLE); @@ -499,7 +498,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } // Set up app settings link (i.e. Customize) - TextView settingsLinkView = findViewById(R.id.app_settings); + View settingsLinkView = findViewById(R.id.app_settings); Intent settingsIntent = getAppSettingsIntent(mPm, mPackageName, mSingleNotificationChannel, mSbn.getId(), mSbn.getTag()); @@ -507,7 +506,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G && settingsIntent != null && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) { settingsLinkView.setVisibility(VISIBLE); - settingsLinkView.setText(mContext.getString(R.string.notification_app_settings)); settingsLinkView.setOnClickListener((View view) -> { mAppSettingsClickListener.onClick(view, settingsIntent); }); @@ -531,6 +529,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G case ACTION_UNDO: mChosenImportance = mStartingChannelImportance; break; + case ACTION_DELIVER_SILENTLY: + mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY; + mChosenImportance = IMPORTANCE_LOW; + confirmationText.setText(R.string.notification_channel_silenced); + break; case ACTION_TOGGLE_SILENT: mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT; if (mWasShownHighPriority) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java index 4bdc1705c5ff..4c9c2f95b35c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java @@ -17,12 +17,7 @@ package com.android.systemui.statusbar.notification.row.wrapper; import android.content.Context; -import android.content.res.Configuration; import android.graphics.Color; -import android.graphics.ColorMatrix; -import android.graphics.ColorMatrixColorFilter; -import android.graphics.Paint; -import android.os.Build; import android.view.View; import com.android.internal.graphics.ColorUtils; @@ -49,43 +44,22 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper { } @Override - public void onReinflated() { - super.onReinflated(); - - Configuration configuration = mView.getResources().getConfiguration(); - boolean nightMode = (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK) - == Configuration.UI_MODE_NIGHT_YES; - - float[] hsl = new float[] {0f, 0f, 0f}; - ColorUtils.colorToHSL(mBackgroundColor, hsl); - boolean backgroundIsDark = Color.alpha(mBackgroundColor) == 0 - || hsl[1] == 0 && hsl[2] < 0.5; - boolean backgroundHasColor = hsl[1] > 0; + public void onContentUpdated(ExpandableNotificationRow row) { + super.onContentUpdated(row); // Let's invert the notification colors when we're in night mode and // the notification background isn't colorized. - if (!backgroundIsDark && !backgroundHasColor && nightMode - && mRow.getEntry().targetSdk < Build.VERSION_CODES.Q) { - Paint paint = new Paint(); - ColorMatrix matrix = new ColorMatrix(); - ColorMatrix tmp = new ColorMatrix(); - // Inversion should happen on Y'UV space to conseve the colors and - // only affect the luminosity. - matrix.setRGB2YUV(); - tmp.set(new float[]{ - -1f, 0f, 0f, 0f, 255f, - 0f, 1f, 0f, 0f, 0f, - 0f, 0f, 1f, 0f, 0f, - 0f, 0f, 0f, 1f, 0f - }); - matrix.postConcat(tmp); - tmp.setYUV2RGB(); - matrix.postConcat(tmp); - paint.setColorFilter(new ColorMatrixColorFilter(matrix)); - mView.setLayerType(View.LAYER_TYPE_HARDWARE, paint); - - hsl[2] = 1f - hsl[2]; - mBackgroundColor = ColorUtils.HSLToColor(hsl); + if (needsInversion(mBackgroundColor, mView)) { + invertViewLuminosity(mView); + + // Also invert background color if necessary + // (Otherwise we'd end-up with white on white.) + float[] hsl = new float[] {0f, 0f, 0f}; + ColorUtils.colorToHSL(mBackgroundColor, hsl); + if (mBackgroundColor != Color.TRANSPARENT && hsl[2] > 0.5) { + hsl[2] = 1f - hsl[2]; + mBackgroundColor = ColorUtils.HSLToColor(hsl); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java new file mode 100644 index 000000000000..49a8d56e1e65 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 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.systemui.statusbar.notification.row.wrapper; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; + +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; + +/** + * Wraps a notification containing a decorated custom view. + */ +public class NotificationDecoratedCustomViewWrapper extends NotificationTemplateViewWrapper { + + private View mWrappedView = null; + + protected NotificationDecoratedCustomViewWrapper(Context ctx, View view, + ExpandableNotificationRow row) { + super(ctx, view, row); + } + + @Override + public void onContentUpdated(ExpandableNotificationRow row) { + ViewGroup container = mView.findViewById( + com.android.internal.R.id.notification_main_column); + Integer childIndex = (Integer) container.getTag( + com.android.internal.R.id.notification_custom_view_index_tag); + if (childIndex != null && childIndex != -1) { + mWrappedView = container.getChildAt(childIndex); + } + if (needsInversion(resolveBackgroundColor(), mWrappedView)) { + invertViewLuminosity(mWrappedView); + } + super.onContentUpdated(row); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java index 9258c9971451..4c06ff6f5e49 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java @@ -16,13 +16,22 @@ package com.android.systemui.statusbar.notification.row.wrapper; +import android.annotation.ColorInt; +import android.app.Notification; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Color; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.Paint; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.view.NotificationHeaderView; import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import com.android.internal.graphics.ColorUtils; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.TransformableView; import com.android.systemui.statusbar.notification.TransformState; @@ -50,6 +59,11 @@ public abstract class NotificationViewWrapper implements TransformableView { } else if ("messaging".equals(v.getTag())) { return new NotificationMessagingTemplateViewWrapper(ctx, v, row); } + Class<? extends Notification.Style> style = + row.getEntry().notification.getNotification().getNotificationStyle(); + if (Notification.DecoratedCustomViewStyle.class.equals(style)) { + return new NotificationDecoratedCustomViewWrapper(ctx, v, row); + } return new NotificationTemplateViewWrapper(ctx, v, row); } else if (v instanceof NotificationHeaderView) { return new NotificationHeaderViewWrapper(ctx, v, row); @@ -75,14 +89,110 @@ public abstract class NotificationViewWrapper implements TransformableView { if (shouldClearBackgroundOnReapply()) { mBackgroundColor = 0; } - Drawable background = mView.getBackground(); - if (background instanceof ColorDrawable) { - int backgroundColor = ((ColorDrawable) background).getColor(); - if (backgroundColor != Color.TRANSPARENT) { - mBackgroundColor = backgroundColor; - mView.setBackground(new ColorDrawable(Color.TRANSPARENT)); + int backgroundColor = getBackgroundColor(mView); + if (backgroundColor != Color.TRANSPARENT) { + mBackgroundColor = backgroundColor; + mView.setBackground(new ColorDrawable(Color.TRANSPARENT)); + } + } + + protected boolean needsInversion(int defaultBackgroundColor, View view) { + if (view == null) { + return false; + } + + Configuration configuration = mView.getResources().getConfiguration(); + boolean nightMode = (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK) + == Configuration.UI_MODE_NIGHT_YES; + if (!nightMode) { + return false; + } + + int background = getBackgroundColor(view); + if (background == Color.TRANSPARENT) { + background = defaultBackgroundColor; + } + if (background == Color.TRANSPARENT) { + background = resolveBackgroundColor(); + } + + float[] hsl = new float[] {0f, 0f, 0f}; + ColorUtils.colorToHSL(background, hsl); + + // Notifications with colored backgrounds should not be inverted + if (hsl[1] != 0) { + return false; + } + + // Invert white or light gray backgrounds. + boolean isLightGrayOrWhite = hsl[1] == 0 && hsl[2] > 0.5; + if (isLightGrayOrWhite) { + return true; + } + + // Now let's check if there's unprotected text somewhere, and invert if we find it. + if (view instanceof ViewGroup) { + return childrenNeedInversion(background, (ViewGroup) view); + } else { + return false; + } + } + + private boolean childrenNeedInversion(@ColorInt int parentBackground, ViewGroup viewGroup) { + if (viewGroup == null) { + return false; + } + + for (int i = 0; i < viewGroup.getChildCount(); i++) { + View child = viewGroup.getChildAt(i); + int backgroundColor = getBackgroundColor(viewGroup); + if (backgroundColor == Color.TRANSPARENT) { + backgroundColor = parentBackground; } + if (child instanceof TextView) { + int foreground = ((TextView) child).getCurrentTextColor(); + if (ColorUtils.calculateContrast(foreground, backgroundColor) < 3) { + return true; + } + } else if (child instanceof ViewGroup) { + if (childrenNeedInversion(backgroundColor, (ViewGroup) child)) { + return true; + } + } + } + + return false; + } + + protected int getBackgroundColor(View view) { + if (view == null) { + return Color.TRANSPARENT; } + Drawable background = view.getBackground(); + if (background instanceof ColorDrawable) { + return ((ColorDrawable) background).getColor(); + } + return Color.TRANSPARENT; + } + + protected void invertViewLuminosity(View view) { + Paint paint = new Paint(); + ColorMatrix matrix = new ColorMatrix(); + ColorMatrix tmp = new ColorMatrix(); + // Inversion should happen on Y'UV space to conserve the colors and + // only affect the luminosity. + matrix.setRGB2YUV(); + tmp.set(new float[]{ + -1f, 0f, 0f, 0f, 255f, + 0f, 1f, 0f, 0f, 0f, + 0f, 0f, 1f, 0f, 0f, + 0f, 0f, 0f, 1f, 0f + }); + matrix.postConcat(tmp); + tmp.setYUV2RGB(); + matrix.postConcat(tmp); + paint.setColorFilter(new ColorMatrixColorFilter(matrix)); + view.setLayerType(View.LAYER_TYPE_HARDWARE, paint); } protected boolean shouldClearBackgroundOnReapply() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 855cfd9ef7cf..7105876907bf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -86,6 +86,8 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.DragDownHelper.DragDownCallback; import com.android.systemui.statusbar.EmptyShadeView; @@ -94,8 +96,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.FakeShadowView; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -664,8 +665,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) protected void onAttachedToWindow() { super.onAttachedToWindow(); - Dependency.get(StatusBarStateController.class) - .addCallback(mStateListener, StatusBarStateController.RANK_STACK_SCROLLER); + ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class)) + .addCallback(mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER); Dependency.get(ConfigurationController.class).addCallback(this); } @@ -5430,7 +5431,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mHeadsUpAppearanceController.setPublicMode(publicMode); } - StatusBarStateController state = Dependency.get(StatusBarStateController.class); + SysuiStatusBarStateController state = (SysuiStatusBarStateController) + Dependency.get(StatusBarStateController.class); setHideSensitive(publicMode, state.goingToFullShade() /* animate */); setDimmed(onKeyguard, state.fromShadeLocked() /* animate */); setExpandingEnabled(!onKeyguard); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java index 35763dce5529..6410860a852d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java @@ -33,8 +33,8 @@ import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager; import com.android.systemui.statusbar.policy.EncryptionHelper; import com.android.systemui.statusbar.policy.KeyguardMonitor; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java index 280dda0cd1dc..d9d74b9d17a6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java @@ -24,8 +24,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; -import com.android.systemui.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; /** * Controller which handles all the doze animations of the scrims. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index 035ccf1d6b81..4c1c0a4b4e58 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -38,9 +38,9 @@ import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.ScreenDecorations; import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java index 1944c3f21444..5ccb9b294718 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java @@ -33,9 +33,9 @@ import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.Interpolators; import com.android.systemui.SysUiServiceProvider; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue.Callbacks; -import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.policy.KeyguardMonitor; import java.io.FileDescriptor; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index ee047e41ec78..538d79717293 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -85,6 +85,7 @@ import com.android.systemui.SysUiServiceProvider; import com.android.systemui.assist.AssistManager; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentHostManager.FragmentListener; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -92,7 +93,6 @@ import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue.Callbacks; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.ContextualButton.ContextButtonListener; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java index d364356b19fe..b613e8efa8ee 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java @@ -25,12 +25,12 @@ import android.util.ArrayMap; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dependency; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.AlertingNotificationManager; import com.android.systemui.statusbar.AmbientPulseManager; import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListener; import com.android.systemui.statusbar.InflationTask; -import com.android.systemui.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java index bb9e4183ba76..cc8af3ba64fc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java @@ -22,11 +22,11 @@ import android.util.ArraySet; import android.util.Log; import com.android.systemui.Dependency; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.AmbientPulseManager; import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListener; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.policy.HeadsUpManager; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index 9e99fe9dac36..62f85fe8a00e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -11,6 +11,9 @@ import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; +import androidx.annotation.NonNull; +import androidx.collection.ArrayMap; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.util.ContrastColorUtil; @@ -19,10 +22,10 @@ import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.StatusBarIconView; -import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -31,9 +34,6 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import java.util.ArrayList; import java.util.function.Function; -import androidx.annotation.NonNull; -import androidx.collection.ArrayMap; - /** * A controller for the space in the status bar to the left of the system icons. This area is * normally reserved for notifications. 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 a9727c953afe..069703e9dd81 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -17,8 +17,7 @@ package com.android.systemui.statusbar.phone; import static com.android.systemui.SysUiServiceProvider.getComponent; -import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator - .ExpandAnimationParameters; +import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -63,6 +62,8 @@ import com.android.systemui.classifier.FalsingManager; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentHostManager.FragmentListener; import com.android.systemui.plugins.qs.QS; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.qs.QSFragment; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.FlingAnimationUtils; @@ -73,8 +74,6 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.NotificationEntryManager; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index f17145d72be1..4d0c8c3a7fb6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -44,9 +44,10 @@ import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.classifier.FalsingManager; import com.android.systemui.doze.DozeLog; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.policy.KeyguardMonitor; @@ -142,8 +143,8 @@ public abstract class PanelView extends FrameLayout { private boolean mIgnoreXTouchSlop; private boolean mExpandLatencyTracking; protected final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class); - protected final StatusBarStateController mStatusBarStateController = - Dependency.get(StatusBarStateController.class); + protected final SysuiStatusBarStateController mStatusBarStateController = + (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class); protected void onExpandingFinished() { mBar.onExpandingFinished(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 37a0610d4de5..9f3bec60cb6d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -163,6 +163,7 @@ import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.PluginDependencyProvider; import com.android.systemui.plugins.qs.QS; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSFragment; import com.android.systemui.qs.QSPanel; import com.android.systemui.recents.Recents; @@ -188,7 +189,8 @@ import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.ScrimView; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.StatusBarStateControllerImpl; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.NotificationActivityStarter; @@ -558,8 +560,8 @@ public class StatusBar extends SystemUI implements DemoMode, }; private boolean mNoAnimationOnNextBarModeChange; protected FalsingManager mFalsingManager; - private final StatusBarStateController - mStatusBarStateController = Dependency.get(StatusBarStateController.class); + private final SysuiStatusBarStateController mStatusBarStateController = + (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class); private final KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { @@ -650,7 +652,8 @@ public class StatusBar extends SystemUI implements DemoMode, } mColorExtractor.addOnColorsChangedListener(this); - mStatusBarStateController.addCallback(this, StatusBarStateController.RANK_STATUS_BAR); + mStatusBarStateController.addCallback(this, + StatusBarStateControllerImpl.RANK_STATUS_BAR); mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); mDreamManager = IDreamManager.Stub.asInterface( @@ -804,15 +807,17 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationLogger.setUpWithContainer(notifListContainer); mNotificationIconAreaController = SystemUIFactory.getInstance() - .createNotificationIconAreaController( - context, this, mStatusBarStateController, mNotificationListener); + .createNotificationIconAreaController(context, this, + mStatusBarStateController, mNotificationListener); inflateShelf(); mNotificationIconAreaController.setupShelf(mNotificationShelf); Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController); - // Allow plugins to reference DarkIconDispatcher + // Allow plugins to reference DarkIconDispatcher and StatusBarStateController Dependency.get(PluginDependencyProvider.class) .allowPluginDependency(DarkIconDispatcher.class); + Dependency.get(PluginDependencyProvider.class) + .allowPluginDependency(StatusBarStateController.class); FragmentHostManager.get(mStatusBarWindow) .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> { CollapsedStatusBarFragment statusBarFragment = @@ -3370,7 +3375,8 @@ public class StatusBar extends SystemUI implements DemoMode, // ringing. // Other transitions are covered in handleVisibleToUserChanged(). if (mVisible && (newState == StatusBarState.SHADE_LOCKED - || (Dependency.get(StatusBarStateController.class).goingToFullShade()))) { + || (((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class)) + .goingToFullShade()))) { clearNotificationEffects(); } if (newState == StatusBarState.KEYGUARD) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index bb23608799f0..5014783c43b1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -42,10 +42,11 @@ import com.android.systemui.DejankUtils; import com.android.systemui.Dependency; import com.android.systemui.SystemUIFactory; import com.android.systemui.keyguard.DismissCallbackRegistry; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.RemoteInputController; -import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback; import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.statusbar.policy.KeyguardMonitorImpl; @@ -701,7 +702,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } public boolean isGoingToNotificationShade() { - return Dependency.get(StatusBarStateController.class).leaveOpenOnKeyguardHide(); + return ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class)) + .leaveOpenOnKeyguardHide(); } public boolean isSecure(int userId) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 86326beb8b00..b0e006d75f81 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -51,13 +51,13 @@ import com.android.systemui.EventLogTags; import com.android.systemui.UiOffloadThread; import com.android.systemui.assist.AssistManager; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationEntryListener; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index df7f53b3b63a..e9705ff35a4d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -48,6 +48,7 @@ import com.android.systemui.InitController; import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.AmbientPulseManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; @@ -56,7 +57,7 @@ import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.AboveShelfObserver; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.NotificationAlertingManager; @@ -92,8 +93,8 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, Dependency.get(NotificationViewHierarchyManager.class); private final NotificationLockscreenUserManager mLockscreenUserManager = Dependency.get(NotificationLockscreenUserManager.class); - private final StatusBarStateController mStatusBarStateController = - Dependency.get(StatusBarStateController.class); + private final SysuiStatusBarStateController mStatusBarStateController = + (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class); private final NotificationEntryManager mEntryManager = Dependency.get(NotificationEntryManager.class); private final NotificationRowBinder mNotificationRowBinder = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java index 8d5841088591..21d9dcc6897d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java @@ -35,13 +35,14 @@ import android.view.ViewParent; import com.android.systemui.Dependency; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue.Callbacks; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationRemoteInputManager.Callback; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.policy.KeyguardMonitor; @@ -57,10 +58,10 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, StatusBarStateController.StateListener { private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class); - private final StatusBarStateController mStatusBarStateController - = Dependency.get(StatusBarStateController.class); - private final NotificationLockscreenUserManager mLockscreenUserManager - = Dependency.get(NotificationLockscreenUserManager.class); + private final SysuiStatusBarStateController mStatusBarStateController = + (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class); + private final NotificationLockscreenUserManager mLockscreenUserManager = + Dependency.get(NotificationLockscreenUserManager.class); private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class); private final Context mContext; private View mPendingWorkRemoteInputView; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java index 86e17f33fc77..e1a77b00f3ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java @@ -43,10 +43,11 @@ import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.keyguard.KeyguardViewMediator; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.RemoteInputController.Callback; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; @@ -98,8 +99,9 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat mDozeParameters = dozeParameters; mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze(); mLpChanged = new WindowManager.LayoutParams(); - Dependency.get(StatusBarStateController.class).addCallback( - mStateListener, StatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER); + ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class)) + .addCallback(mStateListener, + SysuiStatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER); Dependency.get(ConfigurationController.class).addCallback(this); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index c39e17266b56..ad4ba75d6569 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -59,15 +59,14 @@ import com.android.systemui.Dependency; import com.android.systemui.ExpandHelper; import com.android.systemui.R; import com.android.systemui.classifier.FalsingManager; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import java.io.FileDescriptor; import java.io.PrintWriter; - public class StatusBarWindowView extends FrameLayout { public static final String TAG = "StatusBarWindowView"; public static final boolean DEBUG = StatusBar.DEBUG; diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java b/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java index 52cabe278e2d..6ee341dd974c 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java +++ b/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java @@ -34,7 +34,7 @@ import android.widget.ImageView; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.PropertyAnimator; import com.android.systemui.statusbar.notification.stack.AnimationProperties; diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java index d80b444ad64b..b0d1106ecb24 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java @@ -35,15 +35,14 @@ import android.testing.TestableLooper.RunWithLooper; import android.text.TextPaint; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.TextClock; import com.android.keyguard.clock.ClockManager; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.ClockPlugin; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; import org.junit.Before; import org.junit.Test; @@ -60,6 +59,8 @@ import org.mockito.MockitoAnnotations; @RunWithLooper(setAsMainLooper = true) public class KeyguardClockSwitchTest extends SysuiTestCase { private FrameLayout mClockContainer; + private FrameLayout mBigClockContainer; + private TextClock mBigClock; private StatusBarStateController.StateListener mStateListener; @Mock @@ -73,6 +74,8 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { mKeyguardClockSwitch = (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null); mClockContainer = mKeyguardClockSwitch.findViewById(R.id.clock_view); + mBigClockContainer = new FrameLayout(getContext()); + mBigClock = new TextClock(getContext()); MockitoAnnotations.initMocks(this); when(mClockView.getPaint()).thenReturn(mock(TextPaint.class)); mStateListener = mKeyguardClockSwitch.getStateListener(); @@ -93,19 +96,17 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { @Test public void onPluginConnected_showPluginBigClock() { // GIVEN that the container for the big clock has visibility GONE - FrameLayout bigClockContainer = new FrameLayout(getContext()); - bigClockContainer.setVisibility(GONE); - mKeyguardClockSwitch.setBigClockContainer(bigClockContainer); + mBigClockContainer.setVisibility(GONE); + mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); // AND the plugin returns a view for the big clock ClockPlugin plugin = mock(ClockPlugin.class); - TextClock pluginView = new TextClock(getContext()); - when(plugin.getBigClockView()).thenReturn(pluginView); + when(plugin.getBigClockView()).thenReturn(mBigClock); // WHEN the plugin is connected mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); // THEN the big clock container is visible and it is the parent of the // big clock view. - assertThat(bigClockContainer.getVisibility()).isEqualTo(VISIBLE); - assertThat(pluginView.getParent()).isEqualTo(bigClockContainer); + assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mBigClock.getParent()).isEqualTo(mBigClockContainer); } @Test @@ -246,24 +247,64 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { @Test public void onStateChanged_InvisibleInShade() { // GIVEN that the big clock container is visible - ViewGroup container = mock(ViewGroup.class); - when(container.getVisibility()).thenReturn(View.VISIBLE); - mKeyguardClockSwitch.setBigClockContainer(container); + mBigClockContainer.setVisibility(View.VISIBLE); + mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); // WHEN transitioned to SHADE state mStateListener.onStateChanged(StatusBarState.SHADE); // THEN the container is invisible. - verify(container).setVisibility(View.INVISIBLE); + assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.INVISIBLE); } @Test public void onStateChanged_VisibleInKeyguard() { // GIVEN that the big clock container is invisible - ViewGroup container = mock(ViewGroup.class); - when(container.getVisibility()).thenReturn(View.INVISIBLE); - mKeyguardClockSwitch.setBigClockContainer(container); + mBigClockContainer.setVisibility(View.INVISIBLE); + mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); // WHEN transitioned to KEYGUARD state mStateListener.onStateChanged(StatusBarState.KEYGUARD); // THEN the container is visible. - verify(container).setVisibility(View.VISIBLE); + assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void setBigClockContainer_visible() { + // GIVEN that the big clock container is visible + mBigClockContainer.setVisibility(View.VISIBLE); + // AND GIVEN that a plugin is active. + ClockPlugin plugin = mock(ClockPlugin.class); + when(plugin.getBigClockView()).thenReturn(mBigClock); + mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); + // WHEN the container is associated with the clock switch + mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); + // THEN the container remains visible. + assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void setBigClockContainer_invisible() { + // GIVEN that the big clock container is invisible + mBigClockContainer.setVisibility(View.INVISIBLE); + // AND GIVEN that a plugin is active. + ClockPlugin plugin = mock(ClockPlugin.class); + when(plugin.getBigClockView()).thenReturn(mBigClock); + mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); + // WHEN the container is associated with the clock switch + mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); + // THEN the container remains invisible. + assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.INVISIBLE); + } + + @Test + public void setBigClockContainer_gone() { + // GIVEN that the big clock container is gone + mBigClockContainer.setVisibility(View.GONE); + // AND GIVEN that a plugin is active. + ClockPlugin plugin = mock(ClockPlugin.class); + when(plugin.getBigClockView()).thenReturn(mBigClock); + mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); + // WHEN the container is associated with the clock switch + mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); + // THEN the container is made visible. + assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java index c0dca354f5f7..cdac7c979c55 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -50,6 +50,7 @@ import org.junit.Test; import org.junit.runner.RunWith; @SmallTest +@Ignore("failing") @RunWith(AndroidTestingRunner.class) @RunWithLooper public class DozeTriggersTest extends SysuiTestCase { @@ -89,7 +90,6 @@ public class DozeTriggersTest extends SysuiTestCase { } @Test - @Ignore public void testOnNotification_stillWorksAfterOneFailedProxCheck() throws Exception { when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE); @@ -111,7 +111,6 @@ public class DozeTriggersTest extends SysuiTestCase { } @Test - @Ignore public void testDockEventListener_registerAndUnregister() { mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED); @@ -123,7 +122,6 @@ public class DozeTriggersTest extends SysuiTestCase { } @Test - @Ignore public void testOnSensor_whenUndockedWithNearAndDoubleTapScreen_shouldNotWakeUp() { mSensors.getMockProximitySensor().sendProximityResult(false /* far */); @@ -135,7 +133,6 @@ public class DozeTriggersTest extends SysuiTestCase { } @Test - @Ignore public void testOnSensor_whenDockedWithNearAndDoubleTapScreen_shouldWakeUp() { doReturn(true).when(mDockManagerFake).isDocked(); mSensors.getMockProximitySensor().sendProximityResult(false /* far */); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java index cfc19ef28c92..01d7b8b21b0c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java @@ -44,8 +44,8 @@ import androidx.slice.core.SliceQuery; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.StatusBarStateController; import org.junit.Assert; import org.junit.Before; diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index 769fdb5bb842..823485f4624d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -56,6 +56,7 @@ import org.junit.runner.RunWith; @RunWith(AndroidTestingRunner.class) @RunWithLooper @SmallTest +@Ignore public class QSFragmentTest extends SysuiBaseFragmentTest { private MetricsLogger mMockMetricsLogger; diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java index e5464e0343f4..86f6cd331fc9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java @@ -47,10 +47,10 @@ import com.android.internal.logging.MetricsLogger; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.qs.QSTile; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QSTileHost; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; import org.junit.Before; import org.junit.Ignore; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java index 39e1d101b945..8e92684876f6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java @@ -52,6 +52,7 @@ import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper +@Ignore("b/118400112") public class NonPhoneDependencyTest extends SysuiTestCase { @Mock private NotificationPresenter mPresenter; @Mock private NotificationListContainer mListContainer; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java index 56e1fc6b70de..62700c0b3b4c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java @@ -95,7 +95,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { mViewHierarchyManager = new NotificationViewHierarchyManager(mContext, mLockscreenUserManager, mGroupManager, mVisualStabilityManager, - mock(StatusBarStateController.class), mEntryManager, + mock(StatusBarStateControllerImpl.class), mEntryManager, () -> mShadeController); Dependency.get(InitController.class).executePostInitTasks(); mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index cad1a96b8075..79bc0a39d59c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -521,6 +521,16 @@ public class NotificationEntryManagerTest extends SysuiTestCase { verify(extender2).setShouldManageLifetime(mEntry, false); } + /** + * Ensure that calling NotificationEntryManager.performRemoveNotification() doesn't crash when + * given a notification that has already been removed from NotificationData. + */ + @Test + public void testPerformRemoveNotification_removedEntry() { + mEntryManager.getNotificationData().remove(mSbn.getKey(), null /* ranking */); + mEntryManager.performRemoveNotification(mSbn); + } + private Notification.Action createAction() { return new Notification.Action.Builder( Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java index ba2aec0dd3e1..9f36a1eb9943 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java @@ -23,12 +23,19 @@ import static android.app.Notification.CATEGORY_CALL; import static android.app.Notification.CATEGORY_EVENT; import static android.app.Notification.CATEGORY_MESSAGE; import static android.app.Notification.CATEGORY_REMINDER; +import static android.app.NotificationManager.IMPORTANCE_LOW; +import static android.app.NotificationManager.IMPORTANCE_MIN; + +import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_CHANNEL; +import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_IMPORTANCE; +import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_VIS_EFFECTS; import static junit.framework.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -36,6 +43,7 @@ import static org.mockito.Mockito.when; import android.Manifest; import android.app.Notification; import android.app.NotificationChannel; +import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Person; import android.content.Intent; @@ -84,8 +92,6 @@ public class NotificationDataTest extends SysuiTestCase { private static final int UID_NORMAL = 123; private static final int UID_ALLOW_DURING_SETUP = 456; - private static final String TEST_HIDDEN_NOTIFICATION_KEY = "testHiddenNotificationKey"; - private static final String TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY = "exempt"; private static final NotificationChannel NOTIFICATION_CHANNEL = new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE); @@ -97,7 +103,7 @@ public class NotificationDataTest extends SysuiTestCase { NotificationData.KeyguardEnvironment mEnvironment; private final IPackageManager mMockPackageManager = mock(IPackageManager.class); - private NotificationData mNotificationData; + private TestableNotificationData mNotificationData; private ExpandableNotificationRow mRow; @Before @@ -131,6 +137,7 @@ public class NotificationDataTest extends SysuiTestCase { @Test public void testChannelSetWhenAdded() { + mNotificationData.rankingOverrides.putParcelable(OVERRIDE_CHANNEL, NOTIFICATION_CHANNEL); mNotificationData.add(mRow.getEntry()); assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().channel); } @@ -217,12 +224,12 @@ public class NotificationDataTest extends SysuiTestCase { @Test public void testIsExemptFromDndVisualSuppression_foreground() { initStatusBarNotification(false); - when(mMockStatusBarNotification.getKey()).thenReturn( - TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); + Notification n = mMockStatusBarNotification.getNotification(); n.flags = Notification.FLAG_FOREGROUND_SERVICE; NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification); mNotificationData.add(entry); + mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS, 255); assertTrue(entry.isExemptFromDndVisualSuppression()); assertFalse(entry.shouldSuppressAmbient()); @@ -231,8 +238,6 @@ public class NotificationDataTest extends SysuiTestCase { @Test public void testIsExemptFromDndVisualSuppression_media() { initStatusBarNotification(false); - when(mMockStatusBarNotification.getKey()).thenReturn( - TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); Notification n = mMockStatusBarNotification.getNotification(); Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n); nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class))); @@ -240,6 +245,7 @@ public class NotificationDataTest extends SysuiTestCase { when(mMockStatusBarNotification.getNotification()).thenReturn(n); NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification); mNotificationData.add(entry); + mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS, 255); assertTrue(entry.isExemptFromDndVisualSuppression()); assertFalse(entry.shouldSuppressAmbient()); @@ -248,11 +254,10 @@ public class NotificationDataTest extends SysuiTestCase { @Test public void testIsExemptFromDndVisualSuppression_system() { initStatusBarNotification(false); - when(mMockStatusBarNotification.getKey()).thenReturn( - TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification); entry.mIsSystemNotification = true; mNotificationData.add(entry); + mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS, 255); assertTrue(entry.isExemptFromDndVisualSuppression()); assertFalse(entry.shouldSuppressAmbient()); @@ -261,10 +266,10 @@ public class NotificationDataTest extends SysuiTestCase { @Test public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() { initStatusBarNotification(false); - when(mMockStatusBarNotification.getKey()).thenReturn( - TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification); entry.mIsSystemNotification = true; + mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS, + NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT); mNotificationData.add(entry); when(mMockStatusBarNotification.getNotification()).thenReturn( @@ -353,6 +358,64 @@ public class NotificationDataTest extends SysuiTestCase { assertTrue(entry.isLastMessageFromReply()); } + @Test + public void personHighPriority() { + Person person = new Person.Builder() + .setName("name") + .setKey("abc") + .setUri("uri") + .setBot(true) + .build(); + + Notification notification = new Notification.Builder(mContext, "test") + .addPerson(person) + .build(); + + StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, + notification, mContext.getUser(), "", 0); + + assertTrue(mNotificationData.isHighPriority(sbn)); + } + + @Test + public void messagingStyleHighPriority() { + + Notification notification = new Notification.Builder(mContext, "test") + .setStyle(new Notification.MessagingStyle("")) + .build(); + + StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, + notification, mContext.getUser(), "", 0); + + assertTrue(mNotificationData.isHighPriority(sbn)); + } + + @Test + public void minForegroundNotHighPriority() { + Notification notification = mock(Notification.class); + when(notification.isForegroundService()).thenReturn(true); + + mNotificationData.rankingOverrides.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_MIN); + + StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, + notification, mContext.getUser(), "", 0); + + assertFalse(mNotificationData.isHighPriority(sbn)); + } + + @Test + public void lowForegroundHighPriority() { + Notification notification = mock(Notification.class); + when(notification.isForegroundService()).thenReturn(true); + + mNotificationData.rankingOverrides.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW); + + StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, + notification, mContext.getUser(), "", 0); + + assertTrue(mNotificationData.isHighPriority(sbn)); + } + private void initStatusBarNotification(boolean allowDuringSetup) { Bundle bundle = new Bundle(); bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup); @@ -362,39 +425,90 @@ public class NotificationDataTest extends SysuiTestCase { when(mMockStatusBarNotification.getNotification()).thenReturn(notification); } - private class TestableNotificationData extends NotificationData { + public static class TestableNotificationData extends NotificationData { public TestableNotificationData() { super(); } + public static final String OVERRIDE_RANK = "r"; + public static final String OVERRIDE_DND = "dnd"; + public static final String OVERRIDE_VIS_OVERRIDE = "vo"; + public static final String OVERRIDE_VIS_EFFECTS = "ve"; + public static final String OVERRIDE_IMPORTANCE = "i"; + public static final String OVERRIDE_IMP_EXP = "ie"; + public static final String OVERRIDE_GROUP = "g"; + public static final String OVERRIDE_CHANNEL = "c"; + public static final String OVERRIDE_PEOPLE = "p"; + public static final String OVERRIDE_SNOOZE_CRITERIA = "sc"; + public static final String OVERRIDE_BADGE = "b"; + public static final String OVERRIDE_USER_SENTIMENT = "us"; + public static final String OVERRIDE_HIDDEN = "h"; + public static final String OVERRIDE_LAST_ALERTED = "la"; + public static final String OVERRIDE_NOISY = "n"; + public static final String OVERRIDE_SMART_ACTIONS = "sa"; + public static final String OVERRIDE_SMART_REPLIES = "sr"; + public static final String OVERRIDE_BUBBLE = "cb"; + + public Bundle rankingOverrides = new Bundle(); + @Override protected boolean getRanking(String key, Ranking outRanking) { super.getRanking(key, outRanking); - if (key.equals(TEST_HIDDEN_NOTIFICATION_KEY)) { - outRanking.populate(key, outRanking.getRank(), - outRanking.matchesInterruptionFilter(), - outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(), - outRanking.getImportance(), outRanking.getImportanceExplanation(), - outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null, - outRanking.canShowBadge(), outRanking.getUserSentiment(), true, - -1, false, null, null, outRanking.canBubble()); - } else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) { - outRanking.populate(key, outRanking.getRank(), - outRanking.matchesInterruptionFilter(), - outRanking.getVisibilityOverride(), 255, - outRanking.getImportance(), outRanking.getImportanceExplanation(), - outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null, - outRanking.canShowBadge(), outRanking.getUserSentiment(), true, -1, - false, null, null, outRanking.canBubble()); - } else { - outRanking.populate(key, outRanking.getRank(), - outRanking.matchesInterruptionFilter(), - outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(), - outRanking.getImportance(), outRanking.getImportanceExplanation(), - outRanking.getOverrideGroupKey(), NOTIFICATION_CHANNEL, null, null, - outRanking.canShowBadge(), outRanking.getUserSentiment(), false, -1, - false, null, null, outRanking.canBubble()); + + ArrayList<String> currentAdditionalPeople = new ArrayList<>(); + if (outRanking.getAdditionalPeople() != null) { + currentAdditionalPeople.addAll(outRanking.getAdditionalPeople()); + } + + ArrayList<SnoozeCriterion> currentSnooze = new ArrayList<>(); + if (outRanking.getSnoozeCriteria() != null) { + currentSnooze.addAll(outRanking.getSnoozeCriteria()); + } + + ArrayList<Notification.Action> currentActions = new ArrayList<>(); + if (outRanking.getSmartActions() != null) { + currentActions.addAll(outRanking.getSmartActions()); } + + ArrayList<CharSequence> currentReplies = new ArrayList<>(); + if (outRanking.getSmartReplies() != null) { + currentReplies.addAll(outRanking.getSmartReplies()); + } + + outRanking.populate(key, + rankingOverrides.getInt(OVERRIDE_RANK, outRanking.getRank()), + rankingOverrides.getBoolean(OVERRIDE_DND, + outRanking.matchesInterruptionFilter()), + rankingOverrides.getInt(OVERRIDE_VIS_OVERRIDE, + outRanking.getVisibilityOverride()), + rankingOverrides.getInt(OVERRIDE_VIS_EFFECTS, + outRanking.getSuppressedVisualEffects()), + rankingOverrides.getInt(OVERRIDE_IMPORTANCE, outRanking.getImportance()), + rankingOverrides.getCharSequence(OVERRIDE_IMP_EXP, + outRanking.getImportanceExplanation()), + rankingOverrides.getString(OVERRIDE_GROUP, outRanking.getOverrideGroupKey()), + rankingOverrides.containsKey(OVERRIDE_CHANNEL) + ? (NotificationChannel) rankingOverrides.getParcelable(OVERRIDE_CHANNEL) + : outRanking.getChannel(), + rankingOverrides.containsKey(OVERRIDE_PEOPLE) + ? rankingOverrides.getStringArrayList(OVERRIDE_PEOPLE) + : currentAdditionalPeople, + rankingOverrides.containsKey(OVERRIDE_SNOOZE_CRITERIA) + ? rankingOverrides.getParcelableArrayList(OVERRIDE_SNOOZE_CRITERIA) + : currentSnooze, + rankingOverrides.getBoolean(OVERRIDE_BADGE, outRanking.canShowBadge()), + rankingOverrides.getInt(OVERRIDE_USER_SENTIMENT, outRanking.getUserSentiment()), + rankingOverrides.getBoolean(OVERRIDE_HIDDEN, outRanking.isSuspended()), + rankingOverrides.getLong(OVERRIDE_LAST_ALERTED, + outRanking.getLastAudiblyAlertedMillis()), + rankingOverrides.getBoolean(OVERRIDE_NOISY, outRanking.isNoisy()), + rankingOverrides.containsKey(OVERRIDE_SMART_ACTIONS) + ? rankingOverrides.getParcelableArrayList(OVERRIDE_SMART_ACTIONS) + : currentActions, + rankingOverrides.containsKey(OVERRIDE_SMART_REPLIES) + ? rankingOverrides.getCharSequenceArrayList(OVERRIDE_SMART_REPLIES) + : currentReplies, + rankingOverrides.getBoolean(OVERRIDE_BUBBLE, outRanking.canBubble())); return true; } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java index db2706bee3c9..d47700b6f3e0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java @@ -40,7 +40,7 @@ import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.UiOffloadThread; import com.android.systemui.statusbar.NotificationListener; -import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.StatusBarStateControllerImpl; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationData; @@ -99,7 +99,7 @@ public class NotificationLoggerTest extends SysuiTestCase { mEntry.setRow(mRow); mLogger = new TestableNotificationLogger(mListener, Dependency.get(UiOffloadThread.class), - mEntryManager, mock(StatusBarStateController.class), mBarService, + mEntryManager, mock(StatusBarStateControllerImpl.class), mBarService, mExpansionStateLogger); mLogger.setUpWithContainer(mListContainer); verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture()); @@ -167,7 +167,7 @@ public class NotificationLoggerTest extends SysuiTestCase { TestableNotificationLogger(NotificationListener notificationListener, UiOffloadThread uiOffloadThread, NotificationEntryManager entryManager, - StatusBarStateController statusBarStateController, + StatusBarStateControllerImpl statusBarStateController, IStatusBarService barService, ExpansionStateLogger expansionStateLogger) { super(notificationListener, uiOffloadThread, entryManager, statusBarStateController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java index 105bd9dd8793..19a73f6c2d5b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java @@ -737,7 +737,7 @@ public class NotificationInfoTest extends SysuiTestCase { guts.setGutsContent(mNotificationInfo); mNotificationInfo.setGutsParent(guts); - mNotificationInfo.findViewById(R.id.keep).performClick(); + mNotificationInfo.findViewById(R.id.done).performClick(); verify(mBlockingHelperManager).dismissCurrentBlockingHelper(); mTestableLooper.processAllMessages(); @@ -765,7 +765,7 @@ public class NotificationInfoTest extends SysuiTestCase { guts.setGutsContent(mNotificationInfo); mNotificationInfo.setGutsParent(guts); - mNotificationInfo.findViewById(R.id.keep).performClick(); + mNotificationInfo.findViewById(R.id.done).performClick(); verify(mBlockingHelperManager).dismissCurrentBlockingHelper(); mTestableLooper.processAllMessages(); @@ -961,6 +961,41 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test + public void testSilentlyChangedCallsUpdateNotificationChannel_blockingHelper() + throws Exception { + mNotificationChannel.setImportance(IMPORTANCE_LOW); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + 1 /* numChannels */, + mSbn, + null /* checkSaveListener */, + null /* onSettingsClick */, + null /* onAppSettingsClick */, + true /*provisioned */, + false /* isNonblockable */, + true /* isForBlockingHelper */, + true /* isUserSentimentNegative */, + IMPORTANCE_DEFAULT, + false); + + mNotificationInfo.findViewById(R.id.deliver_silently).performClick(); + waitForUndoButton(); + mNotificationInfo.handleCloseControls(true, false); + + mTestableLooper.processAllMessages(); + ArgumentCaptor<NotificationChannel> updated = + ArgumentCaptor.forClass(NotificationChannel.class); + verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( + anyString(), eq(TEST_UID), updated.capture()); + assertTrue((updated.getValue().getUserLockedFields() + & USER_LOCKED_IMPORTANCE) != 0); + assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance()); + } + + @Test public void testKeepUpdatesNotificationChannel() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index ae70b01cd35c..d83508201529 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -51,13 +51,13 @@ import com.android.systemui.InitController; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationEntry; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java index a72be7af8cd8..3c5425ce7d6f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java @@ -32,8 +32,8 @@ import android.view.ViewPropertyAnimator; import com.android.systemui.R; import com.android.systemui.SysuiBaseFragmentTest; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.tuner.TunerService; import org.junit.Before; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java index 13145b830178..608dd8b0d281 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java @@ -20,23 +20,15 @@ import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MOD import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import android.content.Context; import android.provider.Settings; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.systemui.SysuiTestCase; -import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationListener; -import com.android.systemui.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.phone.LightBarTransitionsController.DarkIntensityApplier; import org.junit.Before; import org.junit.Test; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index 3b98f0ca8ce2..a97fa1ff1629 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -27,8 +27,9 @@ import android.testing.TestableLooper; import com.android.keyguard.KeyguardStatusView; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ZenModeController; @@ -46,7 +47,7 @@ import org.mockito.MockitoAnnotations; public class NotificationPanelViewTest extends SysuiTestCase { @Mock - private StatusBarStateController mStatusBarStateController; + private SysuiStatusBarStateController mStatusBarStateController; @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout; @Mock diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 036e57acb7e4..a95361f9e046 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -82,6 +82,7 @@ import com.android.systemui.doze.DozeLog; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.NavigationBarController; @@ -94,7 +95,7 @@ import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.StatusBarStateControllerImpl; import com.android.systemui.statusbar.notification.NotificationAlertingManager; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -153,7 +154,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private NotificationLockscreenUserManager mLockscreenUserManager; @Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock private RemoteInputController mRemoteInputController; - @Mock private StatusBarStateController mStatusBarStateController; + @Mock private StatusBarStateControllerImpl mStatusBarStateController; @Mock private DeviceProvisionedController mDeviceProvisionedController; @Mock private NotificationPresenter mNotificationPresenter; @Mock diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java index 46335dc3b5ec..11284d6ce261 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java @@ -28,9 +28,9 @@ import android.view.MotionEvent; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import org.junit.Before; diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto index 2b45b49ff322..ad0ed8beb7c5 100644 --- a/proto/src/wifi.proto +++ b/proto/src/wifi.proto @@ -515,6 +515,12 @@ message WifiLog { // Total number of scan results for WPA3-Enterprise networks optional int32 num_wpa3_enterprise_network_scan_results = 136; + + // WifiConfigStore read/write metrics. + optional WifiConfigStoreIO wifi_config_store_io = 137; + + // Total number of saved networks with mac randomization enabled. + optional int32 num_saved_networks_with_mac_randomization = 138; } // Information that gets logged for every WiFi connection. @@ -668,6 +674,9 @@ message ConnectionEvent { // Has bug report been taken. optional bool automatic_bug_report_taken = 9; + + // Connection is using locally generated random MAC address. + optional bool use_randomized_mac = 10 [default = false]; } // Number of occurrences of a specific RSSI poll rssi value @@ -1874,6 +1883,13 @@ message WifiUsabilityStatsEntry { // Rx link speed at the sample time in Mbps optional int32 rx_link_speed_mbps = 27; + + // Sequence number generated by framework + optional int32 seq_num_inside_framework = 28; + + // Whether current entry is for the same BSSID on the same frequency compared + // to last entry + optional bool is_same_bssid_and_freq = 29; } message WifiUsabilityStats { @@ -2170,3 +2186,25 @@ message WifiDppLog { EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = 9; } } + +// WifiConfigStore read/write metrics. +message WifiConfigStoreIO { + // Histogram of config store read durations. + repeated DurationBucket read_durations = 1; + + // Histogram of config store write durations. + repeated DurationBucket write_durations = 2; + + // Total Number of instances of write/read duration in this duration bucket. + message DurationBucket { + // Bucket covers duration : [range_start_ms, range_end_ms) + // The (inclusive) lower bound of read/write duration represented by this bucket + optional int32 range_start_ms = 1; + + // The (exclusive) upper bound of read/write duration represented by this bucket + optional int32 range_end_ms = 2; + + // Number of read/write durations that fit into this bucket + optional int32 count = 3; + } +} diff --git a/sax/tests/saxtests/Android.bp b/sax/tests/saxtests/Android.bp new file mode 100644 index 000000000000..5889f769a645 --- /dev/null +++ b/sax/tests/saxtests/Android.bp @@ -0,0 +1,11 @@ +android_test { + name: "FrameworksSaxTests", + // Include all test java files. + srcs: ["src/**/*.java"], + libs: [ + "android.test.runner", + "android.test.base", + ], + static_libs: ["junit"], + platform_apis: true, +} diff --git a/sax/tests/saxtests/Android.mk b/sax/tests/saxtests/Android.mk deleted file mode 100644 index c4517a9a954a..000000000000 --- a/sax/tests/saxtests/Android.mk +++ /dev/null @@ -1,16 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -# We only want this apk build for tests. -LOCAL_MODULE_TAGS := tests - -# Include all test java files. -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base -LOCAL_STATIC_JAVA_LIBRARIES := junit -LOCAL_PACKAGE_NAME := FrameworksSaxTests -LOCAL_PRIVATE_PLATFORM_APIS := true - -include $(BUILD_PACKAGE) - diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS new file mode 100644 index 000000000000..265674a74b7e --- /dev/null +++ b/services/accessibility/OWNERS @@ -0,0 +1,3 @@ +svetoslavganov@google.com +pweaver@google.com +rhedjao@google.com diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 2e45fa72eaac..4a3f12674eb7 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -49,6 +49,7 @@ import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.UserHandle; import android.os.UserManager; +import android.provider.DeviceConfig; import android.provider.Settings; import android.service.autofill.FillEventHistory; import android.service.autofill.UserData; @@ -167,10 +168,14 @@ public final class AutofillManagerService mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext()); mAm = LocalServices.getService(ActivityManagerInternal.class); + DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_AUTOFILL, + ActivityThread.currentApplication().getMainExecutor(), + (namespace, name, value) -> setSmartSuggestionModesFromDeviceConfig(value)); + setLogLevelFromSettings(); setMaxPartitionsFromSettings(); setMaxVisibleDatasetsFromSettings(); - setSmartSuggestionEmulationFromSettings(); + setSmartSuggestionModesFromDeviceConfig(); final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); @@ -197,9 +202,6 @@ public final class AutofillManagerService resolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS), false, observer, UserHandle.USER_ALL); - resolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS), false, observer, - UserHandle.USER_ALL); } @Override // from AbstractMasterSystemService @@ -214,9 +216,6 @@ public final class AutofillManagerService case Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS: setMaxVisibleDatasetsFromSettings(); break; - case Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS: - setSmartSuggestionEmulationFromSettings(); - break; default: Slog.w(TAG, "Unexpected property (" + property + "); updating cache instead"); // fall through @@ -457,14 +456,25 @@ public final class AutofillManagerService } } - private void setSmartSuggestionEmulationFromSettings() { - final int flags = Settings.Global.getInt(getContext().getContentResolver(), - Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS, 0); - if (sDebug) { - Slog.d(TAG, "setSmartSuggestionEmulationFromSettings(): " - + getSmartSuggestionModeToString(flags)); - } + private void setSmartSuggestionModesFromDeviceConfig() { + final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_AUTOFILL, + AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES); + setSmartSuggestionModesFromDeviceConfig(value); + } + private void setSmartSuggestionModesFromDeviceConfig(@Nullable String value) { + if (sDebug) Slog.d(TAG, "setSmartSuggestionEmulationFromDeviceConfig(): value=" + value); + final int flags; + if (value == null) { + flags = AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM; + } else { + try { + flags = Integer.parseInt(value); + } catch (Exception e) { + Slog.w(TAG, "setSmartSuggestionEmulationFromDeviceConfig(): NAN:" + value); + return; + } + } synchronized (mLock) { mSupportedSmartSuggestionModes = flags; } diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListingMap.java index 2d2e88afccf1..a44890118717 100644 --- a/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java +++ b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListingMap.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 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. @@ -11,13 +11,14 @@ * 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 + * limitations under the License. */ package com.android.server.backup.encryption.chunk; import android.annotation.Nullable; import android.util.proto.ProtoInputStream; + import java.io.IOException; import java.util.Collections; import java.util.HashMap; @@ -30,16 +31,16 @@ import java.util.Map; * It can then tell the server to use that chunk, through telling it the position and length of the * chunk in the previous backup's blob. */ -public class ChunkListing { +public class ChunkListingMap { /** - * Reads a ChunkListing from a {@link ProtoInputStream}. Expects the message to be of format + * Reads a ChunkListingMap from a {@link ProtoInputStream}. Expects the message to be of format * {@link ChunksMetadataProto.ChunkListing}. * * @param inputStream Currently at a {@link ChunksMetadataProto.ChunkListing} message. * @throws IOException when the message is not structured as expected or a field can not be * read. */ - public static ChunkListing readFromProto(ProtoInputStream inputStream) throws IOException { + public static ChunkListingMap readFromProto(ProtoInputStream inputStream) throws IOException { Map<ChunkHash, Entry> entries = new HashMap(); long start = 0; @@ -54,12 +55,12 @@ public class ChunkListing { } } - return new ChunkListing(entries); + return new ChunkListingMap(entries); } private final Map<ChunkHash, Entry> mChunksByHash; - private ChunkListing(Map<ChunkHash, Entry> chunksByHash) { + private ChunkListingMap(Map<ChunkHash, Entry> chunksByHash) { mChunksByHash = Collections.unmodifiableMap(new HashMap<>(chunksByHash)); } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index 9249c9cc023a..4afbc641ea6c 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManagerInternal; +import android.app.ActivityThread; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -39,6 +40,7 @@ import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.UserHandle; import android.os.UserManager; +import android.provider.DeviceConfig; import android.provider.Settings; import android.util.LocalLog; import android.util.Slog; @@ -89,19 +91,38 @@ public final class ContentCaptureManagerService extends @Nullable private SparseBooleanArray mDisabledUsers; + /** + * Global kill-switch based on value defined by + * {@link ContentCaptureManager#DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED}. + */ + @GuardedBy("mLock") + @Nullable + private boolean mDisabledByDeviceConfig; public ContentCaptureManagerService(@NonNull Context context) { super(context, new FrameworkResourcesServiceNameResolver(context, com.android.internal.R.string.config_defaultContentCaptureService), UserManager.DISALLOW_CONTENT_CAPTURE); - // Sets which serviecs are disabled + DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE, + ActivityThread.currentApplication().getMainExecutor(), + (namespace, key, value) -> { + if (!ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED + .equals(key)) { + Slog.i(mTag, "Ignoring change on " + key); + return; + } + setDisabledByDeviceConfig(value); + }); + setDisabledByDeviceConfig(); + + // Sets which services are disabled final UserManager um = getContext().getSystemService(UserManager.class); final List<UserInfo> users = um.getUsers(); for (int i = 0; i < users.size(); i++) { final int userId = users.get(i).id; - final boolean disabled = isDisabledBySettings(userId); + final boolean disabled = mDisabledByDeviceConfig || isDisabledBySettings(userId); if (disabled) { - Slog.i(mTag, "user " + userId + " disabled by settings"); + Slog.i(mTag, "user " + userId + " disabled by settings or device config"); if (mDisabledUsers == null) { mDisabledUsers = new SparseBooleanArray(1); } @@ -160,7 +181,8 @@ public final class ContentCaptureManagerService extends @Override // from AbstractMasterSystemService protected boolean isDisabledLocked(@UserIdInt int userId) { - return isDisabledBySettingsLocked(userId) || super.isDisabledLocked(userId); + return mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId) + || super.isDisabledLocked(userId); } private boolean isDisabledBySettingsLocked(@UserIdInt int userId) { @@ -191,6 +213,45 @@ public final class ContentCaptureManagerService extends return false; } + private void setDisabledByDeviceConfig() { + final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE, + ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED); + setDisabledByDeviceConfig(value); + } + + private void setDisabledByDeviceConfig(@Nullable String value) { + if (verbose) Slog.v(mTag, "setDisabledByDeviceConfig(): value=" + value); + final UserManager um = getContext().getSystemService(UserManager.class); + final List<UserInfo> users = um.getUsers(); + + final boolean newDisabledValue; + + if (value != null && value.equalsIgnoreCase("false")) { + newDisabledValue = true; + } else { + newDisabledValue = false; + } + + synchronized (mLock) { + if (mDisabledByDeviceConfig == newDisabledValue) { + if (verbose) { + Slog.v(mTag, "setDisabledByDeviceConfig(): already " + newDisabledValue); + } + return; + } + mDisabledByDeviceConfig = newDisabledValue; + + Slog.i(mTag, "setDisabledByDeviceConfig(): set to " + mDisabledByDeviceConfig); + for (int i = 0; i < users.size(); i++) { + final int userId = users.get(i).id; + boolean disabled = mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId); + Slog.i(mTag, "setDisabledByDeviceConfig(): updating service for user " + + userId + " to " + (disabled ? "'disabled'" : "'enabled'")); + updateCachedServiceLocked(userId, disabled); + } + } + } + private void setContentCaptureFeatureEnabledForUser(@UserIdInt int userId, boolean enabled) { synchronized (mLock) { if (mDisabledUsers == null) { @@ -338,6 +399,8 @@ public final class ContentCaptureManagerService extends super.dumpLocked(prefix, pw); pw.print(prefix); pw.print("Disabled users: "); pw.println(mDisabledUsers); + pw.print(prefix); pw.print("Disabled by DeviceConfig: "); + pw.println(mDisabledByDeviceConfig); } final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub { @@ -406,7 +469,7 @@ public final class ContentCaptureManagerService extends "isContentCaptureFeatureEnabled()", userId, Binder.getCallingUid(), result); if (!isService) return; - enabled = !isDisabledBySettingsLocked(userId); + enabled = !mDisabledByDeviceConfig && !isDisabledBySettingsLocked(userId); } try { result.send(enabled ? ContentCaptureManager.RESULT_CODE_TRUE diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java index 39d5c9d0b777..86ad52d9a42b 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java @@ -77,15 +77,12 @@ public final class ContentCaptureManagerServiceShellCommand extends ShellCommand pw.println(" Temporarily (for DURATION ms) changes the service implemtation."); pw.println(" To reset, call with just the USER_ID argument."); pw.println(""); - pw.println(""); pw.println(" set default-service-enabled USER_ID [true|false]"); pw.println(" Enable / disable the default service for the user."); pw.println(""); - pw.println(""); pw.println(" get default-service-enabled USER_ID"); pw.println(" Checks whether the default service is enabled for the user."); pw.println(""); - pw.println(""); pw.println(" list sessions [--user USER_ID]"); pw.println(" Lists all pending sessions."); pw.println(""); diff --git a/services/core/java/com/android/server/AlarmManagerInternal.java b/services/core/java/com/android/server/AlarmManagerInternal.java index 275661084aa3..5b0de5e2aae0 100644 --- a/services/core/java/com/android/server/AlarmManagerInternal.java +++ b/services/core/java/com/android/server/AlarmManagerInternal.java @@ -26,6 +26,8 @@ public interface AlarmManagerInternal { void broadcastAlarmComplete(int recipientUid); } + /** Returns true if AlarmManager is delaying alarms due to device idle. */ + boolean isIdling(); public void removeAlarmsForUid(int uid); public void registerInFlightListener(InFlightListener callback); } diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 10b532700d1b..a400cc384a58 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -1991,6 +1991,11 @@ class AlarmManagerService extends SystemService { */ private final class LocalService implements AlarmManagerInternal { @Override + public boolean isIdling() { + return isIdlingImpl(); + } + + @Override public void removeAlarmsForUid(int uid) { synchronized (mLock) { removeLocked(uid); @@ -2823,6 +2828,12 @@ class AlarmManagerService extends SystemService { } } + private boolean isIdlingImpl() { + synchronized (mLock) { + return mPendingIdleUntil != null; + } + } + AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) { synchronized (mLock) { return mNextAlarmClockForUser.get(userId); diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java index eafa0e2a6786..e51025943df4 100644 --- a/services/core/java/com/android/server/BinderCallsStatsService.java +++ b/services/core/java/com/android/server/BinderCallsStatsService.java @@ -121,6 +121,8 @@ public class BinderCallsStatsService extends Binder { private static final String SETTINGS_DETAILED_TRACKING_KEY = "detailed_tracking"; private static final String SETTINGS_UPLOAD_DATA_KEY = "upload_data"; private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; + private static final String SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY = "track_screen_state"; + private static final String SETTINGS_TRACK_DIRECT_CALLING_UID_KEY = "track_calling_uid"; private static final String SETTINGS_MAX_CALL_STATS_KEY = "max_call_stats_count"; private boolean mEnabled; @@ -169,6 +171,12 @@ public class BinderCallsStatsService extends Binder { mBinderCallsStats.setMaxBinderCallStats(mParser.getInt( SETTINGS_MAX_CALL_STATS_KEY, BinderCallsStats.MAX_BINDER_CALL_STATS_COUNT_DEFAULT)); + mBinderCallsStats.setTrackScreenInteractive( + mParser.getBoolean(SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY, + BinderCallsStats.DEFAULT_TRACK_SCREEN_INTERACTIVE)); + mBinderCallsStats.setTrackDirectCallerUid( + mParser.getBoolean(SETTINGS_TRACK_DIRECT_CALLING_UID_KEY, + BinderCallsStats.DEFAULT_TRACK_DIRECT_CALLING_UID)); final boolean enabled = diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index fe4411c1dbb5..d1cd072ee215 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -38,7 +38,6 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.uidRulesToString; -import static android.net.NetworkStack.NETWORKSTACK_PACKAGE_NAME; import static android.net.shared.NetworkMonitorUtils.isValidationRequired; import static android.net.shared.NetworkParcelableUtil.toStableParcelable; import static android.os.Process.INVALID_UID; @@ -2667,9 +2666,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public void showProvisioningNotification(String action) { + public void showProvisioningNotification(String action, String packageName) { final Intent intent = new Intent(action); - intent.setPackage(NETWORKSTACK_PACKAGE_NAME); + intent.setPackage(packageName); final PendingIntent pendingIntent; // Only the system server can register notifications with package "android" diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 39030aaf3eb4..6b663941f8fb 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -271,6 +271,7 @@ public class DeviceIdleController extends SystemService private static final int EVENT_BUFFER_SIZE = 100; private AlarmManager mAlarmManager; + private AlarmManagerInternal mLocalAlarmManager; private IBatteryStats mBatteryStats; private ActivityManagerInternal mLocalActivityManager; private ActivityTaskManagerInternal mLocalActivityTaskManager; @@ -616,7 +617,8 @@ public class DeviceIdleController extends SystemService } }; - private final AlarmManager.OnAlarmListener mDeepAlarmListener + @VisibleForTesting + final AlarmManager.OnAlarmListener mDeepAlarmListener = new AlarmManager.OnAlarmListener() { @Override public void onAlarm() { @@ -1874,6 +1876,7 @@ public class DeviceIdleController extends SystemService if (phase == PHASE_SYSTEM_SERVICES_READY) { synchronized (this) { mAlarmManager = mInjector.getAlarmManager(); + mLocalAlarmManager = getLocalService(AlarmManagerInternal.class); mBatteryStats = BatteryStatsService.getService(); mLocalActivityManager = getLocalService(ActivityManagerInternal.class); mLocalActivityTaskManager = getLocalService(ActivityTaskManagerInternal.class); @@ -2605,6 +2608,16 @@ public class DeviceIdleController extends SystemService // next natural time to come out of it. } + + /** Returns true if the screen is locked. */ + @VisibleForTesting + boolean isKeyguardShowing() { + synchronized (this) { + return mScreenLocked; + } + } + + @VisibleForTesting void keyguardShowingLocked(boolean showing) { if (DEBUG) Slog.i(TAG, "keyguardShowing=" + showing); if (mScreenLocked != showing) { @@ -2616,25 +2629,38 @@ public class DeviceIdleController extends SystemService } } + @VisibleForTesting void scheduleReportActiveLocked(String activeReason, int activeUid) { Message msg = mHandler.obtainMessage(MSG_REPORT_ACTIVE, activeUid, 0, activeReason); mHandler.sendMessage(msg); } void becomeActiveLocked(String activeReason, int activeUid) { - if (DEBUG) Slog.i(TAG, "becomeActiveLocked, reason = " + activeReason); + becomeActiveLocked(activeReason, activeUid, mConstants.INACTIVE_TIMEOUT, true); + } + + private void becomeActiveLocked(String activeReason, int activeUid, + long newInactiveTimeout, boolean changeLightIdle) { + if (DEBUG) { + Slog.i(TAG, "becomeActiveLocked, reason=" + activeReason + + ", changeLightIdle=" + changeLightIdle); + } if (mState != STATE_ACTIVE || mLightState != STATE_ACTIVE) { EventLogTags.writeDeviceIdle(STATE_ACTIVE, activeReason); - EventLogTags.writeDeviceIdleLight(LIGHT_STATE_ACTIVE, activeReason); - scheduleReportActiveLocked(activeReason, activeUid); mState = STATE_ACTIVE; - mLightState = LIGHT_STATE_ACTIVE; - mInactiveTimeout = mConstants.INACTIVE_TIMEOUT; + mInactiveTimeout = newInactiveTimeout; mCurIdleBudget = 0; mMaintenanceStartTime = 0; resetIdleManagementLocked(); - resetLightIdleManagementLocked(); - addEvent(EVENT_NORMAL, activeReason); + + if (changeLightIdle) { + EventLogTags.writeDeviceIdleLight(LIGHT_STATE_ACTIVE, activeReason); + mLightState = LIGHT_STATE_ACTIVE; + resetLightIdleManagementLocked(); + // Only report active if light is also ACTIVE. + scheduleReportActiveLocked(activeReason, activeUid); + addEvent(EVENT_NORMAL, activeReason); + } } } @@ -2654,50 +2680,82 @@ public class DeviceIdleController extends SystemService } } + /** Sanity check to make sure DeviceIdleController and AlarmManager are on the same page. */ + private void verifyAlarmStateLocked() { + if (mState == STATE_ACTIVE && mNextAlarmTime != 0) { + Slog.wtf(TAG, "mState=ACTIVE but mNextAlarmTime=" + mNextAlarmTime); + } + if (mState != STATE_IDLE && mLocalAlarmManager.isIdling()) { + Slog.wtf(TAG, "mState=" + stateToString(mState) + " but AlarmManager is idling"); + } + if (mState == STATE_IDLE && !mLocalAlarmManager.isIdling()) { + Slog.wtf(TAG, "mState=IDLE but AlarmManager is not idling"); + } + if (mLightState == LIGHT_STATE_ACTIVE && mNextLightAlarmTime != 0) { + Slog.wtf(TAG, "mLightState=ACTIVE but mNextLightAlarmTime is " + + TimeUtils.formatDuration(mNextLightAlarmTime - SystemClock.elapsedRealtime()) + + " from now"); + } + } + void becomeInactiveIfAppropriateLocked() { - if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()"); - if ((!mScreenOn && !mCharging) || mForceIdle) { - // Become inactive and determine if we will ultimately go idle. - if (mDeepEnabled) { - if (mQuickDozeActivated) { - if (mState == STATE_QUICK_DOZE_DELAY || mState == STATE_IDLE - || mState == STATE_IDLE_MAINTENANCE) { - // Already "idling". Don't want to restart the process. - // mLightState can't be LIGHT_STATE_ACTIVE if mState is any of these 3 - // values, so returning here is safe. - return; - } - if (DEBUG) { - Slog.d(TAG, "Moved from " - + stateToString(mState) + " to STATE_QUICK_DOZE_DELAY"); - } - mState = STATE_QUICK_DOZE_DELAY; - // Make sure any motion sensing or locating is stopped. - resetIdleManagementLocked(); - // Wait a small amount of time in case something (eg: background service from - // recently closed app) needs to finish running. - scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false); - EventLogTags.writeDeviceIdle(mState, "no activity"); - } else if (mState == STATE_ACTIVE) { - mState = STATE_INACTIVE; - if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE"); - resetIdleManagementLocked(); - long delay = mInactiveTimeout; - if (shouldUseIdleTimeoutFactorLocked()) { - delay = (long) (mPreIdleFactor * delay); - } - scheduleAlarmLocked(delay, false); - EventLogTags.writeDeviceIdle(mState, "no activity"); + verifyAlarmStateLocked(); + + final boolean isScreenBlockingInactive = + mScreenOn && (!mConstants.WAIT_FOR_UNLOCK || !mScreenLocked); + if (DEBUG) { + Slog.d(TAG, "becomeInactiveIfAppropriateLocked():" + + " isScreenBlockingInactive=" + isScreenBlockingInactive + + " (mScreenOn=" + mScreenOn + + ", WAIT_FOR_UNLOCK=" + mConstants.WAIT_FOR_UNLOCK + + ", mScreenLocked=" + mScreenLocked + ")" + + " mCharging=" + mCharging + + " mForceIdle=" + mForceIdle + ); + } + if (!mForceIdle && (mCharging || isScreenBlockingInactive)) { + return; + } + // Become inactive and determine if we will ultimately go idle. + if (mDeepEnabled) { + if (mQuickDozeActivated) { + if (mState == STATE_QUICK_DOZE_DELAY || mState == STATE_IDLE + || mState == STATE_IDLE_MAINTENANCE) { + // Already "idling". Don't want to restart the process. + // mLightState can't be LIGHT_STATE_ACTIVE if mState is any of these 3 + // values, so returning here is safe. + return; } - } - if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) { - mLightState = LIGHT_STATE_INACTIVE; - if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE"); - resetLightIdleManagementLocked(); - scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT); - EventLogTags.writeDeviceIdleLight(mLightState, "no activity"); + if (DEBUG) { + Slog.d(TAG, "Moved from " + + stateToString(mState) + " to STATE_QUICK_DOZE_DELAY"); + } + mState = STATE_QUICK_DOZE_DELAY; + // Make sure any motion sensing or locating is stopped. + resetIdleManagementLocked(); + // Wait a small amount of time in case something (eg: background service from + // recently closed app) needs to finish running. + scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false); + EventLogTags.writeDeviceIdle(mState, "no activity"); + } else if (mState == STATE_ACTIVE) { + mState = STATE_INACTIVE; + if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE"); + resetIdleManagementLocked(); + long delay = mInactiveTimeout; + if (shouldUseIdleTimeoutFactorLocked()) { + delay = (long) (mPreIdleFactor * delay); + } + scheduleAlarmLocked(delay, false); + EventLogTags.writeDeviceIdle(mState, "no activity"); } } + if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) { + mLightState = LIGHT_STATE_INACTIVE; + if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE"); + resetLightIdleManagementLocked(); + scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT); + EventLogTags.writeDeviceIdleLight(mLightState, "no activity"); + } } private void resetIdleManagementLocked() { @@ -3216,33 +3274,10 @@ public class DeviceIdleController extends SystemService // The device is not yet active, so we want to go back to the pending idle // state to wait again for no motion. Note that we only monitor for motion // after moving out of the inactive state, so no need to worry about that. - boolean becomeInactive = false; - if (mState != STATE_ACTIVE) { - // Motion shouldn't affect light state, if it's already in doze-light or maintenance - boolean lightIdle = mLightState == LIGHT_STATE_IDLE - || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK - || mLightState == LIGHT_STATE_IDLE_MAINTENANCE; - if (!lightIdle) { - // Only switch to active state if we're not in either idle state - scheduleReportActiveLocked(type, Process.myUid()); - addEvent(EVENT_NORMAL, type); - } - mActiveReason = ACTIVE_REASON_MOTION; - mState = STATE_ACTIVE; - mInactiveTimeout = timeout; - mCurIdleBudget = 0; - mMaintenanceStartTime = 0; - EventLogTags.writeDeviceIdle(mState, type); - becomeInactive = true; - updateActiveConstraintsLocked(); - } - if (mLightState == LIGHT_STATE_OVERRIDE) { - // We went out of light idle mode because we had started deep idle mode... let's - // now go back and reset things so we resume light idling if appropriate. - mLightState = LIGHT_STATE_ACTIVE; - EventLogTags.writeDeviceIdleLight(mLightState, type); - becomeInactive = true; - } + final boolean becomeInactive = mState != STATE_ACTIVE + || mLightState == LIGHT_STATE_OVERRIDE; + // We only want to change the IDLE state if it's OVERRIDE. + becomeActiveLocked(type, Process.myUid(), timeout, mLightState == LIGHT_STATE_OVERRIDE); if (becomeInactive) { becomeInactiveIfAppropriateLocked(); } diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java index 9184128d466f..c334540f48cc 100644 --- a/services/core/java/com/android/server/LooperStatsService.java +++ b/services/core/java/com/android/server/LooperStatsService.java @@ -51,16 +51,19 @@ public class LooperStatsService extends Binder { private static final String LOOPER_STATS_SERVICE_NAME = "looper_stats"; private static final String SETTINGS_ENABLED_KEY = "enabled"; private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; + private static final String SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY = "track_screen_state"; private static final String DEBUG_SYS_LOOPER_STATS_ENABLED = "debug.sys.looper_stats_enabled"; private static final int DEFAULT_SAMPLING_INTERVAL = 100; private static final int DEFAULT_ENTRIES_SIZE_CAP = 2000; private static final boolean DEFAULT_ENABLED = true; + private static final boolean DEFAULT_TRACK_SCREEN_INTERACTIVE = false; private final Context mContext; private final LooperStats mStats; // Default should be false so that the first call to #setEnabled installed the looper observer. private boolean mEnabled = false; + private boolean mTrackScreenInteractive = false; private LooperStatsService(Context context, LooperStats stats) { this.mContext = context; @@ -79,6 +82,9 @@ public class LooperStatsService extends Binder { setSamplingInterval( parser.getInt(SETTINGS_SAMPLING_INTERVAL_KEY, DEFAULT_SAMPLING_INTERVAL)); + setTrackScreenInteractive( + parser.getBoolean(SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY, + DEFAULT_TRACK_SCREEN_INTERACTIVE)); // Manually specified value takes precedence over Settings. setEnabled(SystemProperties.getBoolean( DEBUG_SYS_LOOPER_STATS_ENABLED, @@ -155,6 +161,13 @@ public class LooperStatsService extends Binder { } } + private void setTrackScreenInteractive(boolean enabled) { + if (mTrackScreenInteractive != enabled) { + mTrackScreenInteractive = enabled; + mStats.reset(); + } + } + private void setSamplingInterval(int samplingInterval) { if (samplingInterval > 0) { mStats.setSamplingInterval(samplingInterval); diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index f2329d3ebf8e..e7d7434b5dc8 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -4013,7 +4013,7 @@ class StorageManagerService extends IStorageManager.Stub return; } userPackages.add(packageName); - sandboxId = getSandboxId(packageName, sharedUserId); + sandboxId = StorageManagerService.this.getSandboxId(packageName, sharedUserId); } try { @@ -4028,7 +4028,8 @@ class StorageManagerService extends IStorageManager.Stub if (!ENABLE_ISOLATED_STORAGE) { return; } - final String sandboxId = getSandboxId(packageName, sharedUserId); + final String sandboxId = StorageManagerService.this.getSandboxId( + packageName, sharedUserId); synchronized (mPackagesLock) { final ArraySet<String> userPackages = mPackages.get(userId); // If the userPackages is null, it means the user is not started but we still @@ -4056,6 +4057,12 @@ class StorageManagerService extends IStorageManager.Stub return visibleVolsForUser.toArray(new String[visibleVolsForUser.size()]); } + @Override + public String getSandboxId(String packageName) { + return StorageManagerService.this.getSandboxId(packageName, + mPmInternal.getSharedUserIdForPackage(packageName)); + } + private String getVolumeLabel(VolumeInfo vol) { // STOPSHIP: Label needs to part of VolumeInfo and need to be passed on from vold switch (vol.getType()) { diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java index c7b9a3cb7847..8ccb6e20a614 100644 --- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java +++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java @@ -82,6 +82,9 @@ public class AdbDebuggingManager { private static final String ADB_DIRECTORY = "misc/adb"; // This file contains keys that will always be allowed to connect to the device via adb. private static final String ADB_KEYS_FILE = "adb_keys"; + // This file contains keys that will be allowed to connect without user interaction as long + // as a subsequent connection occurs within the allowed duration. + private static final String ADB_TEMP_KEYS_FILE = "adb_temp_keys.xml"; private static final int BUFFER_SIZE = 4096; private final Context mContext; @@ -263,7 +266,6 @@ public class AdbDebuggingManager { AdbDebuggingHandler(Looper looper) { super(looper); - mAdbKeyStore = new AdbKeyStore(); } /** @@ -289,6 +291,7 @@ public class AdbDebuggingManager { mThread = new AdbDebuggingThread(); mThread.start(); + mAdbKeyStore = new AdbKeyStore(); break; case MESSAGE_ADB_DISABLED: @@ -303,6 +306,9 @@ public class AdbDebuggingManager { mThread = null; } + cancelJobToUpdateAdbKeyStore(); + mAdbKeyStore = null; + mConnectedKey = null; break; case MESSAGE_ADB_ALLOW: { @@ -322,6 +328,9 @@ public class AdbDebuggingManager { mConnectedKey = key; mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis()); scheduleJobToUpdateAdbKeyStore(); + // write this key to adb_keys as well so that subsequent connections can + // go through the expected SIGNATURE interaction. + writeKey(key); } logAdbConnectionChanged(key, AdbProtoEnums.USER_ALLOWED, alwaysAllow); } @@ -354,20 +363,9 @@ public class AdbDebuggingManager { } break; } - // Check if the key should be allowed without user interaction. - if (mAdbKeyStore.isKeyAuthorized(key)) { - if (mThread != null) { - mThread.sendResponse("OK"); - mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis()); - logAdbConnectionChanged(key, AdbProtoEnums.AUTOMATICALLY_ALLOWED, true); - mConnectedKey = key; - scheduleJobToUpdateAdbKeyStore(); - } - } else { - logAdbConnectionChanged(key, AdbProtoEnums.AWAITING_USER_APPROVAL, false); - mFingerprints = fingerprints; - startConfirmation(key, mFingerprints); - } + logAdbConnectionChanged(key, AdbProtoEnums.AWAITING_USER_APPROVAL, false); + mFingerprints = fingerprints; + startConfirmation(key, mFingerprints); break; } @@ -532,7 +530,11 @@ public class AdbDebuggingManager { return new File(adbDir, fileName); } - private File getUserKeyFile() { + File getAdbTempKeysFile() { + return getAdbFile(ADB_TEMP_KEYS_FILE); + } + + File getUserKeyFile() { return getAdbFile(ADB_KEYS_FILE); } @@ -668,9 +670,6 @@ public class AdbDebuggingManager { private Map<String, Long> mKeyMap; private File mKeyFile; private AtomicFile mAtomicKeyFile; - // This file contains keys that will be allowed to connect without user interaction as long - // as a subsequent connection occurs within the allowed duration. - private static final String ADB_TEMP_KEYS_FILE = "adb_temp_keys.xml"; private static final String XML_TAG_ADB_KEY = "adbKey"; private static final String XML_ATTRIBUTE_KEY = "key"; private static final String XML_ATTRIBUTE_LAST_CONNECTION = "lastConnection"; @@ -704,9 +703,9 @@ public class AdbDebuggingManager { */ private void initKeyFile() { if (mKeyFile == null) { - mKeyFile = getAdbFile(ADB_TEMP_KEYS_FILE); + mKeyFile = getAdbTempKeysFile(); } - // getAdbFile can return null if the adb file cannot be obtained + // getAdbTempKeysFile can return null if the adb file cannot be obtained if (mKeyFile != null) { mAtomicKeyFile = new AtomicFile(mKeyFile); } @@ -767,7 +766,8 @@ public class AdbDebuggingManager { public void persistKeyStore() { // if there is nothing in the key map then ensure any keys left in the key store files // are deleted as well. - if (mKeyMap.size() == 0) { + filterOutOldKeys(); + if (mKeyMap.isEmpty()) { deleteKeyStore(); return; } @@ -784,22 +784,15 @@ public class AdbDebuggingManager { keyStream = mAtomicKeyFile.startWrite(); serializer.setOutput(keyStream, StandardCharsets.UTF_8.name()); serializer.startDocument(null, true); - long allowedTime = getAllowedConnectionTime(); - long systemTime = System.currentTimeMillis(); - Iterator keyMapIterator = mKeyMap.entrySet().iterator(); - while (keyMapIterator.hasNext()) { - Map.Entry<String, Long> keyEntry = (Map.Entry) keyMapIterator.next(); - long connectionTime = keyEntry.getValue(); - if (systemTime < (connectionTime + allowedTime)) { - serializer.startTag(null, XML_TAG_ADB_KEY); - serializer.attribute(null, XML_ATTRIBUTE_KEY, keyEntry.getKey()); - serializer.attribute(null, XML_ATTRIBUTE_LAST_CONNECTION, - String.valueOf(keyEntry.getValue())); - serializer.endTag(null, XML_TAG_ADB_KEY); - } else { - keyMapIterator.remove(); - } + + for (Map.Entry<String, Long> keyEntry : mKeyMap.entrySet()) { + serializer.startTag(null, XML_TAG_ADB_KEY); + serializer.attribute(null, XML_ATTRIBUTE_KEY, keyEntry.getKey()); + serializer.attribute(null, XML_ATTRIBUTE_LAST_CONNECTION, + String.valueOf(keyEntry.getValue())); + serializer.endTag(null, XML_TAG_ADB_KEY); } + serializer.endDocument(); mAtomicKeyFile.finishWrite(keyStream); } catch (IOException e) { @@ -808,6 +801,19 @@ public class AdbDebuggingManager { } } + private void filterOutOldKeys() { + long allowedTime = getAllowedConnectionTime(); + long systemTime = System.currentTimeMillis(); + Iterator<Map.Entry<String, Long>> keyMapIterator = mKeyMap.entrySet().iterator(); + while (keyMapIterator.hasNext()) { + Map.Entry<String, Long> keyEntry = keyMapIterator.next(); + long connectionTime = keyEntry.getValue(); + if (allowedTime != 0 && systemTime > (connectionTime + allowedTime)) { + keyMapIterator.remove(); + } + } + } + /** * Removes all of the entries in the key map and deletes the key file. */ diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java index c31691551269..7fd98e0043c9 100644 --- a/services/core/java/com/android/server/adb/AdbService.java +++ b/services/core/java/com/android/server/adb/AdbService.java @@ -45,6 +45,7 @@ import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.SystemService; +import java.io.File; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Collections; @@ -95,6 +96,16 @@ public class AdbService extends IAdbManager.Stub { public boolean isAdbEnabled() { return mAdbEnabled; } + + @Override + public File getAdbKeysFile() { + return mDebuggingManager.getUserKeyFile(); + } + + @Override + public File getAdbTempKeysFile() { + return mDebuggingManager.getAdbTempKeysFile(); + } } private final class AdbHandler extends Handler { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5932f99b562b..c4a9db6b7262 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2226,7 +2226,7 @@ public class ActivityManagerService extends IActivityManager.Stub mConstants = hasHandlerThread ? new ActivityManagerConstants(this, mHandler) : null; final ActiveUids activeUids = new ActiveUids(this, false /* postChangesToAtm */); mProcessList.init(this, activeUids); - mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids, new Object()); + mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids); mIntentFirewall = hasHandlerThread ? new IntentFirewall(new IntentFirewallInterface(), mHandler) : null; @@ -2274,7 +2274,7 @@ public class ActivityManagerService extends IActivityManager.Stub mConstants = new ActivityManagerConstants(this, mHandler); final ActiveUids activeUids = new ActiveUids(this, true /* postChangesToAtm */); mProcessList.init(this, activeUids); - mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids, atm.getGlobalLock()); + mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids); // Broadcast policy parameters final BroadcastConstants foreConstants = new BroadcastConstants( @@ -6549,7 +6549,7 @@ public class ActivityManagerService extends IActivityManager.Stub conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag, stable); if (conn != null && (conn.stableCount+conn.unstableCount) == 1) { - if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) { + if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { // If this is a perceptible app accessing the provider, // make sure to count it as being accessed and thus // back up on the LRU list. This is good because @@ -6630,8 +6630,7 @@ public class ActivityManagerService extends IActivityManager.Stub String msg; if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) { - throw new SecurityException("Content provider lookup " - + cpr.name.flattenToShortString() + throw new SecurityException("Content provider lookup " + name + " failed: association not allowed with package " + msg); } checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission"); @@ -10828,6 +10827,7 @@ public class ActivityManagerService extends IActivityManager.Stub printOomLevel(pw, "FOREGROUND_APP_ADJ", ProcessList.FOREGROUND_APP_ADJ); printOomLevel(pw, "VISIBLE_APP_ADJ", ProcessList.VISIBLE_APP_ADJ); printOomLevel(pw, "PERCEPTIBLE_APP_ADJ", ProcessList.PERCEPTIBLE_APP_ADJ); + printOomLevel(pw, "PERCEPTIBLE_LOW_APP_ADJ", ProcessList.PERCEPTIBLE_LOW_APP_ADJ); printOomLevel(pw, "BACKUP_APP_ADJ", ProcessList.BACKUP_APP_ADJ); printOomLevel(pw, "HEAVY_WEIGHT_APP_ADJ", ProcessList.HEAVY_WEIGHT_APP_ADJ); printOomLevel(pw, "SERVICE_ADJ", ProcessList.SERVICE_ADJ); @@ -10878,16 +10878,17 @@ public class ActivityManagerService extends IActivityManager.Stub pw.println(" Total number of kills: " + cnt); return reportLmkKillAtOrBelow(pw, ProcessList.CACHED_APP_MAX_ADJ) && - reportLmkKillAtOrBelow(pw, ProcessList.CACHED_APP_MIN_ADJ) && - reportLmkKillAtOrBelow(pw, ProcessList.SERVICE_B_ADJ) && - reportLmkKillAtOrBelow(pw, ProcessList.PREVIOUS_APP_ADJ) && - reportLmkKillAtOrBelow(pw, ProcessList.HOME_APP_ADJ) && - reportLmkKillAtOrBelow(pw, ProcessList.SERVICE_ADJ) && - reportLmkKillAtOrBelow(pw, ProcessList.HEAVY_WEIGHT_APP_ADJ) && - reportLmkKillAtOrBelow(pw, ProcessList.BACKUP_APP_ADJ) && - reportLmkKillAtOrBelow(pw, ProcessList.PERCEPTIBLE_APP_ADJ) && - reportLmkKillAtOrBelow(pw, ProcessList.VISIBLE_APP_ADJ) && - reportLmkKillAtOrBelow(pw, ProcessList.FOREGROUND_APP_ADJ); + reportLmkKillAtOrBelow(pw, ProcessList.CACHED_APP_MIN_ADJ) && + reportLmkKillAtOrBelow(pw, ProcessList.SERVICE_B_ADJ) && + reportLmkKillAtOrBelow(pw, ProcessList.PREVIOUS_APP_ADJ) && + reportLmkKillAtOrBelow(pw, ProcessList.HOME_APP_ADJ) && + reportLmkKillAtOrBelow(pw, ProcessList.SERVICE_ADJ) && + reportLmkKillAtOrBelow(pw, ProcessList.HEAVY_WEIGHT_APP_ADJ) && + reportLmkKillAtOrBelow(pw, ProcessList.BACKUP_APP_ADJ) && + reportLmkKillAtOrBelow(pw, ProcessList.PERCEPTIBLE_LOW_APP_ADJ) && + reportLmkKillAtOrBelow(pw, ProcessList.PERCEPTIBLE_APP_ADJ) && + reportLmkKillAtOrBelow(pw, ProcessList.VISIBLE_APP_ADJ) && + reportLmkKillAtOrBelow(pw, ProcessList.FOREGROUND_APP_ADJ); } /** @@ -11760,7 +11761,8 @@ public class ActivityManagerService extends IActivityManager.Stub ProcessList.NATIVE_ADJ, ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ, ProcessList.PERSISTENT_SERVICE_ADJ, ProcessList.FOREGROUND_APP_ADJ, - ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ, + ProcessList.VISIBLE_APP_ADJ, + ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_LOW_APP_ADJ, ProcessList.BACKUP_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ, ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ, ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.CACHED_APP_MIN_ADJ @@ -11768,7 +11770,7 @@ public class ActivityManagerService extends IActivityManager.Stub static final String[] DUMP_MEM_OOM_LABEL = new String[] { "Native", "System", "Persistent", "Persistent Service", "Foreground", - "Visible", "Perceptible", + "Visible", "Perceptible", "Perceptible Low", "Heavy Weight", "Backup", "A Services", "Home", "Previous", "B Services", "Cached" @@ -11776,7 +11778,7 @@ public class ActivityManagerService extends IActivityManager.Stub static final String[] DUMP_MEM_OOM_COMPACT_LABEL = new String[] { "native", "sys", "pers", "persvc", "fore", - "vis", "percept", + "vis", "percept", "perceptl", "heavy", "backup", "servicea", "home", "prev", "serviceb", "cached" diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java index 502f078b532e..c7e4fc78c013 100644 --- a/services/core/java/com/android/server/am/AppCompactor.java +++ b/services/core/java/com/android/server/am/AppCompactor.java @@ -55,6 +55,8 @@ public final class AppCompactor { private static final int COMPACT_ACTION_FILE_FLAG = 1; private static final int COMPACT_ACTION_ANON_FLAG = 2; private static final int COMPACT_ACTION_FULL_FLAG = 3; + private static final int COMPACT_ACTION_NONE_FLAG = 4; + private static final String COMPACT_ACTION_NONE = ""; private static final String COMPACT_ACTION_FILE = "file"; private static final String COMPACT_ACTION_ANON = "anon"; private static final String COMPACT_ACTION_FULL = "all"; @@ -320,6 +322,8 @@ public final class AppCompactor { @VisibleForTesting static String compactActionIntToString(int action) { switch(action) { + case COMPACT_ACTION_NONE_FLAG: + return COMPACT_ACTION_NONE; case COMPACT_ACTION_FILE_FLAG: return COMPACT_ACTION_FILE; case COMPACT_ACTION_ANON_FLAG: @@ -327,7 +331,7 @@ public final class AppCompactor { case COMPACT_ACTION_FULL_FLAG: return COMPACT_ACTION_FULL; default: - return COMPACT_ACTION_FILE; + return COMPACT_ACTION_NONE; } } @@ -398,6 +402,10 @@ public final class AppCompactor { action = mCompactActionFull; } + if (action.equals(COMPACT_ACTION_NONE)) { + return; + } + try { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Compact " + ((pendingAction == COMPACT_PROCESS_SOME) ? "some" : "full") diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java index 01946247bd12..0bf54392465a 100644 --- a/services/core/java/com/android/server/am/CoreSettingsObserver.java +++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java @@ -76,6 +76,7 @@ final class CoreSettingsObserver extends ContentObserver { sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_OPT_OUT_APPS, String.class); sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_BLACKLIST, String.class); sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_WHITELIST, String.class); + sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_BLACKLISTS, String.class); // add other global settings here... } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 7035698d5ee0..93a71e5a2ed4 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -127,18 +127,8 @@ public final class OomAdjuster { private final ActivityManagerService mService; private final ProcessList mProcessList; - /** - * Used to lock {@link #updateOomAdjImpl} for state consistency. It also reduces frequency lock - * and unlock when getting and setting value to {@link ProcessRecord#mWindowProcessController}. - * Note it is declared as Object type so the locked-region-code-injection won't wrap the - * unnecessary priority booster. - */ - private final Object mAtmGlobalLock; - - OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids, - Object atmGlobalLock) { + OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) { mService = service; - mAtmGlobalLock = atmGlobalLock; mProcessList = processList; mActiveUids = activeUids; @@ -196,13 +186,6 @@ public final class OomAdjuster { @GuardedBy("mService") final void updateOomAdjLocked() { - synchronized (mAtmGlobalLock) { - updateOomAdjImpl(); - } - } - - @GuardedBy({"mService", "mAtmGlobalLock"}) - private void updateOomAdjImpl() { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "updateOomAdj"); mService.mOomAdjProfiler.oomAdjStarted(); final ProcessRecord TOP_APP = mService.getTopAppLocked(); @@ -1224,8 +1207,8 @@ public final class OomAdjuster { } } else if ((cr.flags & Context.BIND_ADJUST_BELOW_PERCEPTIBLE) != 0 && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ - && adj > ProcessList.PERCEPTIBLE_APP_ADJ + 1) { - newAdj = ProcessList.PERCEPTIBLE_APP_ADJ + 1; + && adj > ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { + newAdj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ; } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0 && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ && adj > ProcessList.PERCEPTIBLE_APP_ADJ) { @@ -1610,7 +1593,7 @@ public final class OomAdjuster { // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj); if (adj > app.maxAdj) { adj = app.maxAdj; - if (app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) { + if (app.maxAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { schedGroup = ProcessList.SCHED_GROUP_DEFAULT; } } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 69cf54b5528a..f01305eab761 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -183,6 +183,10 @@ public final class ProcessList { // is not entirely fatal but is generally a bad idea. static final int BACKUP_APP_ADJ = 300; + // This is a process bound by the system that's more important than services but not so + // perceptible that it affects the user immediately if killed. + static final int PERCEPTIBLE_LOW_APP_ADJ = 250; + // This is a process only hosting components that are perceptible to the // user, and we really want to avoid killing them, but they are not // immediately visible. An example is background music playback. @@ -717,6 +721,9 @@ public final class ProcessList { } else if (setAdj >= ProcessList.BACKUP_APP_ADJ) { return buildOomTag("bkup ", "bkup", null, setAdj, ProcessList.BACKUP_APP_ADJ, compact); + } else if (setAdj >= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { + return buildOomTag("prcl ", "prcl", null, setAdj, + ProcessList.PERCEPTIBLE_LOW_APP_ADJ, compact); } else if (setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) { return buildOomTag("prcp ", "prcp", null, setAdj, ProcessList.PERCEPTIBLE_APP_ADJ, compact); @@ -1740,8 +1747,11 @@ public final class ProcessList { try { final String[] packageNames = mService.mContext.getPackageManager() .getPackagesForUid(uid); - final String[] visibleVolIds = LocalServices.getService(StorageManagerInternal.class) + final StorageManagerInternal storageManagerInternal = + LocalServices.getService(StorageManagerInternal.class); + final String[] visibleVolIds = storageManagerInternal .getVisibleVolumesForUser(UserHandle.getUserId(uid)); + final String sandboxId = storageManagerInternal.getSandboxId(app.info.packageName); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " + app.processName); checkSlow(startTime, "startProcess: asking zygote to start proc"); @@ -1751,7 +1761,7 @@ public final class ProcessList { app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, - packageNames, visibleVolIds, + packageNames, visibleVolIds, sandboxId, new String[] {PROC_START_SEQ_IDENT + app.startSeq}); } else if (hostingType.equals("app_zygote")) { final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app); @@ -1760,14 +1770,14 @@ public final class ProcessList { app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, - packageNames, visibleVolIds, /*useBlastulaPool=*/ false, + packageNames, visibleVolIds, sandboxId, /*useBlastulaPool=*/ false, new String[] {PROC_START_SEQ_IDENT + app.startSeq}); } else { startResult = Process.start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith, app.info.packageName, - packageNames, visibleVolIds, + packageNames, visibleVolIds, sandboxId, new String[] {PROC_START_SEQ_IDENT + app.startSeq}); } checkSlow(startTime, "startProcess: returned from zygote!"); diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 5dccaf14e1f1..fcc857b7a75d 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -713,6 +713,8 @@ final class ProcessRecord implements WindowProcessListener { adj = ProcessList.VISIBLE_APP_ADJ; } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) { adj = ProcessList.PERCEPTIBLE_APP_ADJ; + } else if (adj < ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { + adj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ; } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) { adj = ProcessList.CACHED_APP_MIN_ADJ; } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) { diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index c981e6885a9e..7f6648a3d174 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -2072,7 +2072,8 @@ class UserController implements Handler.Callback { new TimingsTraceLog("SystemServerTiming", Trace.TRACE_TAG_SYSTEM_SERVER) .logDuration("SystemUserUnlock", unlockTime); } else { - Slog.d(TAG, "Unlocking user " + id + " took " + unlockTime + " ms"); + new TimingsTraceLog("SystemServerTiming", Trace.TRACE_TAG_SYSTEM_SERVER) + .logDuration("User" + id + "Unlock", unlockTime); } } }; diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 0dc73d9278a2..6df60d6bdd3a 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -21,6 +21,8 @@ import static com.android.server.audio.AudioService.CONNECTION_STATE_DISCONNECTE import android.annotation.NonNull; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHeadset; +import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothProfile; import android.content.ContentResolver; import android.content.Context; @@ -424,11 +426,28 @@ import java.util.ArrayList; } /*package*/ void postDisconnectHearingAid() { - sendMsgNoDelay(MSG_DISCONNECT_HEARING_AID, SENDMSG_QUEUE); + sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE); } /*package*/ void postDisconnectHeadset() { - sendMsgNoDelay(MSG_DISCONNECT_HEADSET, SENDMSG_QUEUE); + sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE); + } + + /*package*/ void postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile) { + sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP, SENDMSG_QUEUE, a2dpProfile); + } + + /*package*/ void postBtA2dpSinkProfileConnected(BluetoothProfile profile) { + sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK, SENDMSG_QUEUE, profile); + } + + /*package*/ void postBtHeasetProfileConnected(BluetoothHeadset headsetProfile) { + sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET, SENDMSG_QUEUE, headsetProfile); + } + + /*package*/ void postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile) { + sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID, SENDMSG_QUEUE, + hearingAidProfile); } //--------------------------------------------------------------------- @@ -460,16 +479,14 @@ import java.util.ArrayList; } } + @GuardedBy("mDeviceStateLock") /*package*/ void handleSetA2dpSinkConnectionState(@BluetoothProfile.BtProfileState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) { final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED; - final int delay; - synchronized (mDeviceStateLock) { - delay = mDeviceInventory.checkSendBecomingNoisyIntent( + final int delay = mDeviceInventory.checkSendBecomingNoisyIntent( AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState, AudioSystem.DEVICE_NONE); - } final String addr = btDeviceInfo == null ? "null" : btDeviceInfo.getBtDevice().getAddress(); if (AudioService.DEBUG_DEVICES) { @@ -719,16 +736,36 @@ import java.util.ArrayList; mDeviceInventory.disconnectA2dpSink(); } break; - case MSG_DISCONNECT_HEARING_AID: + case MSG_DISCONNECT_BT_HEARING_AID: synchronized (mDeviceStateLock) { mDeviceInventory.disconnectHearingAid(); } break; - case MSG_DISCONNECT_HEADSET: + case MSG_DISCONNECT_BT_HEADSET: synchronized (mDeviceStateLock) { mBtHelper.disconnectHeadset(); } break; + case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP: + synchronized (mDeviceStateLock) { + mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj); + } + break; + case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK: + synchronized (mDeviceStateLock) { + mBtHelper.onA2dpSinkProfileConnected((BluetoothProfile) msg.obj); + } + break; + case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID: + synchronized (mDeviceStateLock) { + mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj); + } + break; + case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET: + synchronized (mDeviceStateLock) { + mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj); + } + break; default: Log.wtf(TAG, "Invalid message " + msg.what); } @@ -766,8 +803,12 @@ import java.util.ArrayList; private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18; private static final int MSG_DISCONNECT_A2DP = 19; private static final int MSG_DISCONNECT_A2DP_SINK = 20; - private static final int MSG_DISCONNECT_HEARING_AID = 21; - private static final int MSG_DISCONNECT_HEADSET = 22; + private static final int MSG_DISCONNECT_BT_HEARING_AID = 21; + private static final int MSG_DISCONNECT_BT_HEADSET = 22; + private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP = 23; + private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24; + private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25; + private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26; private static boolean isMessageHandledUnderWakelock(int msgId) { diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index e9189974e988..58c1882abf6f 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -393,6 +393,84 @@ public class BtHelper { mBluetoothHeadset = null; } + /*package*/ synchronized void onA2dpProfileConnected(BluetoothA2dp a2dp) { + mA2dp = a2dp; + final List<BluetoothDevice> deviceList = mA2dp.getConnectedDevices(); + if (deviceList.isEmpty()) { + return; + } + final BluetoothDevice btDevice = deviceList.get(0); + final @BluetoothProfile.BtProfileState int state = mA2dp.getConnectionState(btDevice); + mDeviceBroker.handleSetA2dpSinkConnectionState( + state, new BluetoothA2dpDeviceInfo(btDevice)); + } + + /*package*/ synchronized void onA2dpSinkProfileConnected(BluetoothProfile profile) { + final List<BluetoothDevice> deviceList = profile.getConnectedDevices(); + if (deviceList.isEmpty()) { + return; + } + final BluetoothDevice btDevice = deviceList.get(0); + final @BluetoothProfile.BtProfileState int state = + profile.getConnectionState(btDevice); + mDeviceBroker.postSetA2dpSourceConnectionState( + state, new BluetoothA2dpDeviceInfo(btDevice)); + } + + /*package*/ synchronized void onHearingAidProfileConnected(BluetoothHearingAid hearingAid) { + mHearingAid = hearingAid; + final List<BluetoothDevice> deviceList = mHearingAid.getConnectedDevices(); + if (deviceList.isEmpty()) { + return; + } + final BluetoothDevice btDevice = deviceList.get(0); + final @BluetoothProfile.BtProfileState int state = + mHearingAid.getConnectionState(btDevice); + mDeviceBroker.setBluetoothHearingAidDeviceConnectionState( + btDevice, state, + /*suppressNoisyIntent*/ false, + /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE, + /*eventSource*/ "mBluetoothProfileServiceListener"); + } + + /*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) { + // Discard timeout message + mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService(); + mBluetoothHeadset = headset; + setBtScoActiveDevice(mBluetoothHeadset.getActiveDevice()); + // Refresh SCO audio state + checkScoAudioState(); + if (mScoAudioState != SCO_STATE_ACTIVATE_REQ + && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) { + return; + } + boolean status = false; + if (mBluetoothHeadsetDevice != null) { + switch (mScoAudioState) { + case SCO_STATE_ACTIVATE_REQ: + status = connectBluetoothScoAudioHelper( + mBluetoothHeadset, + mBluetoothHeadsetDevice, mScoAudioMode); + if (status) { + mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; + } + break; + case SCO_STATE_DEACTIVATE_REQ: + status = disconnectBluetoothScoAudioHelper( + mBluetoothHeadset, + mBluetoothHeadsetDevice, mScoAudioMode); + if (status) { + mScoAudioState = SCO_STATE_DEACTIVATING; + } + break; + } + } + if (!status) { + mScoAudioState = SCO_STATE_INACTIVE; + broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); + } + } + //---------------------------------------------------------------------- private void broadcastScoConnectionState(int state) { mDeviceBroker.postBroadcastScoConnectionState(state); @@ -462,99 +540,36 @@ public class BtHelper { } } + // NOTE this listener is NOT called from AudioDeviceBroker event thread, only call async + // methods inside listener. private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = new BluetoothProfile.ServiceListener() { public void onServiceConnected(int profile, BluetoothProfile proxy) { - final BluetoothDevice btDevice; - List<BluetoothDevice> deviceList; switch(profile) { case BluetoothProfile.A2DP: - synchronized (BtHelper.this) { - mA2dp = (BluetoothA2dp) proxy; - deviceList = mA2dp.getConnectedDevices(); - if (deviceList.size() > 0) { - btDevice = deviceList.get(0); - if (btDevice == null) { - Log.e(TAG, "Invalid null device in BT profile listener"); - return; - } - final @BluetoothProfile.BtProfileState int state = - mA2dp.getConnectionState(btDevice); - mDeviceBroker.handleSetA2dpSinkConnectionState( - state, new BluetoothA2dpDeviceInfo(btDevice)); - } - } + AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( + "BT profile service: connecting A2DP profile")); + mDeviceBroker.postBtA2dpProfileConnected((BluetoothA2dp) proxy); break; case BluetoothProfile.A2DP_SINK: - deviceList = proxy.getConnectedDevices(); - if (deviceList.size() > 0) { - btDevice = deviceList.get(0); - final @BluetoothProfile.BtProfileState int state = - proxy.getConnectionState(btDevice); - mDeviceBroker.postSetA2dpSourceConnectionState( - state, new BluetoothA2dpDeviceInfo(btDevice)); - } + AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( + "BT profile service: connecting A2DP_SINK profile")); + mDeviceBroker.postBtA2dpSinkProfileConnected(proxy); break; case BluetoothProfile.HEADSET: - synchronized (BtHelper.this) { - // Discard timeout message - mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService(); - mBluetoothHeadset = (BluetoothHeadset) proxy; - setBtScoActiveDevice(mBluetoothHeadset.getActiveDevice()); - // Refresh SCO audio state - checkScoAudioState(); - // Continue pending action if any - if (mScoAudioState == SCO_STATE_ACTIVATE_REQ - || mScoAudioState == SCO_STATE_DEACTIVATE_REQ) { - boolean status = false; - if (mBluetoothHeadsetDevice != null) { - switch (mScoAudioState) { - case SCO_STATE_ACTIVATE_REQ: - status = connectBluetoothScoAudioHelper( - mBluetoothHeadset, - mBluetoothHeadsetDevice, mScoAudioMode); - if (status) { - mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; - } - break; - case SCO_STATE_DEACTIVATE_REQ: - status = disconnectBluetoothScoAudioHelper( - mBluetoothHeadset, - mBluetoothHeadsetDevice, mScoAudioMode); - if (status) { - mScoAudioState = SCO_STATE_DEACTIVATING; - } - break; - } - } - if (!status) { - mScoAudioState = SCO_STATE_INACTIVE; - broadcastScoConnectionState( - AudioManager.SCO_AUDIO_STATE_DISCONNECTED); - } - } - } + AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( + "BT profile service: connecting HEADSET profile")); + mDeviceBroker.postBtHeasetProfileConnected((BluetoothHeadset) proxy); break; case BluetoothProfile.HEARING_AID: - synchronized (BtHelper.this) { - mHearingAid = (BluetoothHearingAid) proxy; - deviceList = mHearingAid.getConnectedDevices(); - if (deviceList.size() > 0) { - btDevice = deviceList.get(0); - final @BluetoothProfile.BtProfileState int state = - mHearingAid.getConnectionState(btDevice); - mDeviceBroker.setBluetoothHearingAidDeviceConnectionState( - btDevice, state, - /*suppressNoisyIntent*/ false, - /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE, - /*eventSource*/ "mBluetoothProfileServiceListener"); - } - } + AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( + "BT profile service: connecting HEARING_AID profile")); + mDeviceBroker.postBtHearingAidProfileConnected( + (BluetoothHearingAid) proxy); break; - default: break; } diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index b50b800f0e20..bca84f7b7217 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -391,10 +391,11 @@ public class BiometricService extends SystemService { private final Random mRandom = new Random(); // TODO(b/123378871): Remove when moved. - // When BiometricPrompt#setEnableFallback is set to true, we need to store the client (app) - // receiver. BiometricService internally launches CDCA which invokes BiometricService to - // start authentication (normal path). When auth is success/rejected, CDCA will use an aidl - // method to poke BiometricService - the result will then be forwarded to this receiver. + // When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the + // client (app) receiver. BiometricService internally launches CDCA which invokes + // BiometricService to start authentication (normal path). When auth is success/rejected, + // CDCA will use an aidl method to poke BiometricService - the result will then be forwarded + // to this receiver. private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver; // The current authentication session, null if idle/done. We need to track both the current @@ -803,11 +804,21 @@ public class BiometricService extends SystemService { // we can't get activity results. Store the receiver somewhere so we can forward the // result back to the client. // TODO(b/123378871): Remove when moved. - if (bundle.getBoolean(BiometricPrompt.KEY_ENABLE_FALLBACK)) { + if (bundle.getBoolean(BiometricPrompt.KEY_ALLOW_DEVICE_CREDENTIAL)) { mHandler.post(() -> { - mConfirmDeviceCredentialReceiver = receiver; final KeyguardManager kgm = getContext().getSystemService( KeyguardManager.class); + if (!kgm.isDeviceSecure()) { + try { + receiver.onError(BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL, + getContext().getString( + R.string.biometric_error_device_not_secured)); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + } + return; + } + mConfirmDeviceCredentialReceiver = receiver; // Use this so we don't need to duplicate logic.. final Intent intent = kgm.createConfirmDeviceCredentialIntent(null /* title */, null /* description */); diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java index b65535af52b1..9e0f2fcaa29f 100644 --- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java +++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java @@ -624,7 +624,8 @@ public abstract class BiometricServiceBase extends SystemService handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /*vendorCode */); - StatsLog.write(StatsLog.BIOMETRIC_HAL_DEATH_REPORTED, statsModality()); + StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality(), + BiometricsProtoEnums.ISSUE_HAL_DEATH); } protected ClientMonitor getCurrentClient() { diff --git a/services/core/java/com/android/server/biometrics/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/LoggableMonitor.java index 91c924de27a2..3b75b95fb0b9 100644 --- a/services/core/java/com/android/server/biometrics/LoggableMonitor.java +++ b/services/core/java/com/android/server/biometrics/LoggableMonitor.java @@ -28,7 +28,7 @@ import android.util.StatsLog; public abstract class LoggableMonitor { public static final String TAG = "BiometricStats"; - public static final boolean DEBUG = true; + public static final boolean DEBUG = false; private long mFirstAcquireTimeMs; @@ -137,6 +137,8 @@ public abstract class LoggableMonitor { + ", RequireConfirmation: " + requireConfirmation + ", State: " + authState + ", Latency: " + latency); + } else { + Slog.v(TAG, "Authentication latency: " + latency); } StatsLog.write(StatsLog.BIOMETRIC_AUTHENTICATED, diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java index 017503a03816..8995068ef504 100644 --- a/services/core/java/com/android/server/biometrics/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/face/FaceService.java @@ -705,6 +705,8 @@ public class FaceService extends BiometricServiceBase { public void serviceDied(long cookie) { super.serviceDied(cookie); mDaemon = null; + + mCurrentUserId = UserHandle.USER_NULL; // Force updateActiveGroup() to re-evaluate } @Override diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java index 9e0a1c0c2ef2..d8544e324618 100644 --- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java @@ -49,6 +49,7 @@ import android.os.SELinux; import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; +import android.util.StatsLog; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; @@ -554,6 +555,8 @@ public class FingerprintService extends BiometricServiceBase { + " " + f.getDeviceId()); FingerprintUtils.getInstance().removeBiometricForUser(getContext(), getTargetUserId(), f.getBiometricId()); + StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, + BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK); } mEnrolledList.clear(); } @@ -1003,6 +1006,8 @@ public class FingerprintService extends BiometricServiceBase { mHalDeviceId, mToken, new ServiceListenerImpl(null), uf.f.getBiometricId(), uf.f.getGroupId(), uf.userId, restricted, getContext().getOpPackageName()); removeInternal(client); + StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality(), + BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL); } else { clearEnumerateState(); } diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index a14fd17209e8..19bdc0969e6d 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -96,6 +96,7 @@ import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; +import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; @@ -180,6 +181,7 @@ public class Tethering extends BaseNetworkObserver { // into a single coherent structure. private final HashSet<IpServer> mForwardedDownstreams; private final VersionedBroadcastListener mCarrierConfigChange; + private final VersionedBroadcastListener mDefaultSubscriptionChange; private final TetheringDependencies mDeps; private final EntitlementManager mEntitlementMgr; @@ -232,6 +234,15 @@ public class Tethering extends BaseNetworkObserver { mEntitlementMgr.reevaluateSimCardProvisioning(); }); + filter = new IntentFilter(); + filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); + mDefaultSubscriptionChange = new VersionedBroadcastListener( + "DefaultSubscriptionChangeListener", mContext, smHandler, filter, + (Intent ignored) -> { + mLog.log("OBSERVED default data subscription change"); + updateConfiguration(); + mEntitlementMgr.reevaluateSimCardProvisioning(); + }); mStateReceiver = new StateReceiver(); // Load tethering configuration. @@ -242,6 +253,7 @@ public class Tethering extends BaseNetworkObserver { private void startStateMachineUpdaters() { mCarrierConfigChange.startListening(); + mDefaultSubscriptionChange.startListening(); final Handler handler = mTetherMasterSM.getHandler(); IntentFilter filter = new IntentFilter(); @@ -270,7 +282,8 @@ public class Tethering extends BaseNetworkObserver { // NOTE: This is always invoked on the mLooper thread. private void updateConfiguration() { - mConfig = new TetheringConfiguration(mContext, mLog); + final int subId = mDeps.getDefaultDataSubscriptionId(); + mConfig = new TetheringConfiguration(mContext, mLog, subId); mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired); mEntitlementMgr.updateConfiguration(mConfig); } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java index 1e6bb04858a1..8a46ff18979f 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java @@ -26,8 +26,8 @@ import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; import static com.android.internal.R.array.config_mobile_hotspot_provision_app; import static com.android.internal.R.array.config_tether_bluetooth_regexs; import static com.android.internal.R.array.config_tether_dhcp_range; -import static com.android.internal.R.array.config_tether_usb_regexs; import static com.android.internal.R.array.config_tether_upstream_types; +import static com.android.internal.R.array.config_tether_usb_regexs; import static com.android.internal.R.array.config_tether_wifi_regexs; import static com.android.internal.R.bool.config_tether_upstream_automatic; import static com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui; @@ -38,6 +38,7 @@ import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.util.SharedLog; import android.provider.Settings; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -100,29 +101,34 @@ public class TetheringConfiguration { public final String[] provisioningApp; public final String provisioningAppNoUi; - public TetheringConfiguration(Context ctx, SharedLog log) { + public final int subId; + + public TetheringConfiguration(Context ctx, SharedLog log, int id) { final SharedLog configLog = log.forSubComponent("config"); - tetherableUsbRegexs = getResourceStringArray(ctx, config_tether_usb_regexs); + subId = id; + Resources res = getResources(ctx, subId); + + tetherableUsbRegexs = getResourceStringArray(res, config_tether_usb_regexs); // TODO: Evaluate deleting this altogether now that Wi-Fi always passes // us an interface name. Careful consideration needs to be given to // implications for Settings and for provisioning checks. - tetherableWifiRegexs = getResourceStringArray(ctx, config_tether_wifi_regexs); - tetherableBluetoothRegexs = getResourceStringArray(ctx, config_tether_bluetooth_regexs); + tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs); + tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs); dunCheck = checkDunRequired(ctx); configLog.log("DUN check returned: " + dunCheckString(dunCheck)); - chooseUpstreamAutomatically = getResourceBoolean(ctx, config_tether_upstream_automatic); - preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck); + chooseUpstreamAutomatically = getResourceBoolean(res, config_tether_upstream_automatic); + preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, dunCheck); isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN); - legacyDhcpRanges = getLegacyDhcpRanges(ctx); + legacyDhcpRanges = getLegacyDhcpRanges(res); defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); enableLegacyDhcpServer = getEnableLegacyDhcpServer(ctx); - provisioningApp = getResourceStringArray(ctx, config_mobile_hotspot_provision_app); - provisioningAppNoUi = getProvisioningAppNoUi(ctx); + provisioningApp = getResourceStringArray(res, config_mobile_hotspot_provision_app); + provisioningAppNoUi = getProvisioningAppNoUi(res); configLog.log(toString()); } @@ -144,6 +150,9 @@ public class TetheringConfiguration { } public void dump(PrintWriter pw) { + pw.print("subId: "); + pw.println(subId); + dumpStringArray(pw, "tetherableUsbRegexs", tetherableUsbRegexs); dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs); dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs); @@ -169,6 +178,7 @@ public class TetheringConfiguration { public String toString() { final StringJoiner sj = new StringJoiner(" "); + sj.add(String.format("subId:%d", subId)); sj.add(String.format("tetherableUsbRegexs:%s", makeString(tetherableUsbRegexs))); sj.add(String.format("tetherableWifiRegexs:%s", makeString(tetherableWifiRegexs))); sj.add(String.format("tetherableBluetoothRegexs:%s", @@ -235,8 +245,8 @@ public class TetheringConfiguration { } } - private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, int dunCheck) { - final int ifaceTypes[] = ctx.getResources().getIntArray(config_tether_upstream_types); + private static Collection<Integer> getUpstreamIfaceTypes(Resources res, int dunCheck) { + final int[] ifaceTypes = res.getIntArray(config_tether_upstream_types); final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); for (int i : ifaceTypes) { switch (i) { @@ -286,33 +296,33 @@ public class TetheringConfiguration { return false; } - private static String[] getLegacyDhcpRanges(Context ctx) { - final String[] fromResource = getResourceStringArray(ctx, config_tether_dhcp_range); + private static String[] getLegacyDhcpRanges(Resources res) { + final String[] fromResource = getResourceStringArray(res, config_tether_dhcp_range); if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) { return fromResource; } return copy(LEGACY_DHCP_DEFAULT_RANGE); } - private static String getProvisioningAppNoUi(Context ctx) { + private static String getProvisioningAppNoUi(Resources res) { try { - return ctx.getResources().getString(config_mobile_hotspot_provision_app_no_ui); + return res.getString(config_mobile_hotspot_provision_app_no_ui); } catch (Resources.NotFoundException e) { return ""; } } - private static boolean getResourceBoolean(Context ctx, int resId) { + private static boolean getResourceBoolean(Resources res, int resId) { try { - return ctx.getResources().getBoolean(resId); + return res.getBoolean(resId); } catch (Resources.NotFoundException e404) { return false; } } - private static String[] getResourceStringArray(Context ctx, int resId) { + private static String[] getResourceStringArray(Resources res, int resId) { try { - final String[] strArray = ctx.getResources().getStringArray(resId); + final String[] strArray = res.getStringArray(resId); return (strArray != null) ? strArray : EMPTY_STRING_ARRAY; } catch (Resources.NotFoundException e404) { return EMPTY_STRING_ARRAY; @@ -325,6 +335,19 @@ public class TetheringConfiguration { return intVal != 0; } + private Resources getResources(Context ctx, int subId) { + if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + return getResourcesForSubIdWrapper(ctx, subId); + } else { + return ctx.getResources(); + } + } + + @VisibleForTesting + protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) { + return SubscriptionManager.getResourcesForSubId(ctx, subId); + } + private static String[] copy(String[] strarray) { return Arrays.copyOf(strarray, strarray.length); } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java index 6d6f81eb98e6..3fddac111ec5 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java @@ -21,6 +21,7 @@ import android.net.NetworkRequest; import android.net.ip.IpServer; import android.net.util.SharedLog; import android.os.Handler; +import android.telephony.SubscriptionManager; import com.android.internal.util.StateMachine; import com.android.server.connectivity.MockableSystemProperties; @@ -85,4 +86,11 @@ public class TetheringDependencies { SharedLog log, MockableSystemProperties systemProperties) { return new EntitlementManager(ctx, target, log, systemProperties); } + + /** + * Get default data subscription id to build TetheringConfiguration. + */ + public int getDefaultDataSubscriptionId() { + return SubscriptionManager.getDefaultDataSubscriptionId(); + } } diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java index 9cb6eeec2126..45f169ca0b6f 100644 --- a/services/core/java/com/android/server/display/ColorDisplayService.java +++ b/services/core/java/com/android/server/display/ColorDisplayService.java @@ -387,8 +387,10 @@ public final class ColorDisplayService extends SystemService { Slog.d(TAG, "Setting saturation level: " + saturationLevel); if (saturationLevel == 100) { + setActivated(false); Matrix.setIdentityM(mMatrixGlobalSaturation, 0); } else { + setActivated(true); float saturation = saturationLevel * 0.1f; float desaturation = 1.0f - saturation; float[] luminance = {0.231f * desaturation, 0.715f * desaturation, @@ -556,14 +558,16 @@ public final class ColorDisplayService extends SystemService { if (setting != null) { switch (setting) { case Secure.NIGHT_DISPLAY_ACTIVATED: - final boolean activated = isNightDisplayActivatedSetting(); + final boolean activated = mNightDisplayTintController + .isActivatedSetting(); if (mNightDisplayTintController.isActivatedStateNotSet() || mNightDisplayTintController.isActivated() != activated) { - mNightDisplayTintController.onActivated(activated); + mNightDisplayTintController.setActivated(activated); } break; case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE: - final int temperature = getNightDisplayColorTemperatureSetting(); + final int temperature = mNightDisplayTintController + .getColorTemperatureSetting(); if (mNightDisplayTintController.getColorTemperature() != temperature) { mNightDisplayTintController @@ -639,14 +643,16 @@ public final class ColorDisplayService extends SystemService { // Prepare the night display color transformation matrix. mNightDisplayTintController .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix()); - mNightDisplayTintController.setMatrix(getNightDisplayColorTemperatureSetting()); + mNightDisplayTintController + .setMatrix(mNightDisplayTintController.getColorTemperatureSetting()); // Initialize the current auto mode. onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal()); // Force the initialization of the current saved activation state. if (mNightDisplayTintController.isActivatedStateNotSet()) { - mNightDisplayTintController.onActivated(isNightDisplayActivatedSetting()); + mNightDisplayTintController + .setActivated(mNightDisplayTintController.isActivatedSetting()); } } @@ -674,6 +680,10 @@ public final class ColorDisplayService extends SystemService { if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) { mDisplayWhiteBalanceTintController.endAnimator(); } + + if (mGlobalSaturationTintController.isAvailable(getContext())) { + mGlobalSaturationTintController.setActivated(null); + } } private void onNightDisplayAutoModeChanged(int autoMode) { @@ -722,7 +732,8 @@ public final class ColorDisplayService extends SystemService { if (mNightDisplayTintController.isAvailable(getContext())) { mNightDisplayTintController .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode)); - mNightDisplayTintController.setMatrix(getNightDisplayColorTemperatureSetting()); + mNightDisplayTintController + .setMatrix(mNightDisplayTintController.getColorTemperatureSetting()); } updateDisplayWhiteBalanceStatus(); @@ -1040,8 +1051,7 @@ public final class ColorDisplayService extends SystemService { * * See {@link com.android.server.display.DisplayTransformManager} */ - private @ColorMode - int getCurrentColorModeFromSystemProperties() { + private @ColorMode int getCurrentColorModeFromSystemProperties() { final int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0); if (displayColorSetting == 0) { return "1.0".equals(SystemProperties.get("persist.sys.sf.color_saturation")) @@ -1098,33 +1108,6 @@ public final class ColorDisplayService extends SystemService { pw.println("Color mode: " + getColorModeInternal()); } - private boolean isNightDisplayActivatedSetting() { - return Secure.getIntForUser(getContext().getContentResolver(), - Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1; - } - - private int getNightDisplayColorTemperatureSetting() { - return clampNightDisplayColorTemperature(Secure.getIntForUser( - getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, NOT_SET, - mCurrentUser)); - } - - private int clampNightDisplayColorTemperature(int colorTemperature) { - if (colorTemperature == NOT_SET) { - colorTemperature = getContext().getResources().getInteger( - R.integer.config_nightDisplayColorTemperatureDefault); - } - final int minimumTemperature = ColorDisplayManager.getMinimumColorTemperature(getContext()); - final int maximumTemperature = ColorDisplayManager.getMaximumColorTemperature(getContext()); - if (colorTemperature < minimumTemperature) { - colorTemperature = minimumTemperature; - } else if (colorTemperature > maximumTemperature) { - colorTemperature = maximumTemperature; - } - - return colorTemperature; - } - private abstract class NightDisplayAutoMode { public abstract void onActivated(boolean activated); @@ -1171,7 +1154,7 @@ public final class ColorDisplayService extends SystemService { // Maintain the existing activated state if within the current period. if (mLastActivatedTime.isBefore(now) && mLastActivatedTime.isAfter(start) && (mLastActivatedTime.isAfter(end) || now.isBefore(end))) { - activate = isNightDisplayActivatedSetting(); + activate = mNightDisplayTintController.isActivatedSetting(); } } @@ -1267,7 +1250,7 @@ public final class ColorDisplayService extends SystemService { // Maintain the existing activated state if within the current period. if (mLastActivatedTime.isBefore(now) && (mLastActivatedTime.isBefore(sunrise) ^ mLastActivatedTime.isBefore(sunset))) { - activate = isNightDisplayActivatedSetting(); + activate = mNightDisplayTintController.isActivatedSetting(); } } @@ -1466,9 +1449,11 @@ public final class ColorDisplayService extends SystemService { if (isActivatedStateNotSet() || activationStateChanged) { super.setActivated(activated); - Secure.putIntForUser(getContext().getContentResolver(), - Secure.NIGHT_DISPLAY_ACTIVATED, - activated ? 1 : 0, mCurrentUser); + if (isActivatedSetting() != activated) { + Secure.putIntForUser(getContext().getContentResolver(), + Secure.NIGHT_DISPLAY_ACTIVATED, + activated ? 1 : 0, mCurrentUser); + } onActivated(activated); } } @@ -1486,7 +1471,7 @@ public final class ColorDisplayService extends SystemService { return mIsAvailable; } - void onActivated(boolean activated) { + private void onActivated(boolean activated) { Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display"); if (mNightDisplayAutoMode != null) { mNightDisplayAutoMode.onActivated(activated); @@ -1501,7 +1486,7 @@ public final class ColorDisplayService extends SystemService { int getColorTemperature() { return mColorTemp != null ? clampNightDisplayColorTemperature(mColorTemp) - : getNightDisplayColorTemperatureSetting(); + : getColorTemperatureSetting(); } boolean setColorTemperature(int temperature) { @@ -1516,6 +1501,36 @@ public final class ColorDisplayService extends SystemService { setMatrix(temperature); mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE); } + + boolean isActivatedSetting() { + return Secure.getIntForUser(getContext().getContentResolver(), + Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1; + } + + int getColorTemperatureSetting() { + return clampNightDisplayColorTemperature(Secure.getIntForUser( + getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, + NOT_SET, + mCurrentUser)); + } + + private int clampNightDisplayColorTemperature(int colorTemperature) { + if (colorTemperature == NOT_SET) { + colorTemperature = getContext().getResources().getInteger( + R.integer.config_nightDisplayColorTemperatureDefault); + } + final int minimumTemperature = ColorDisplayManager + .getMinimumColorTemperature(getContext()); + final int maximumTemperature = ColorDisplayManager + .getMaximumColorTemperature(getContext()); + if (colorTemperature < minimumTemperature) { + colorTemperature = minimumTemperature; + } else if (colorTemperature > maximumTemperature) { + colorTemperature = maximumTemperature; + } + + return colorTemperature; + } } /** @@ -1671,6 +1686,20 @@ public final class ColorDisplayService extends SystemService { } @Override + public boolean isSaturationActivated() { + getContext().enforceCallingPermission( + Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, + "Permission required to get display saturation level"); + final long token = Binder.clearCallingIdentity(); + try { + return !mGlobalSaturationTintController.isActivatedStateNotSet() + && mGlobalSaturationTintController.isActivated(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override public boolean setAppSaturationLevel(String packageName, int level) { getContext().enforceCallingPermission( Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java index 7ae00af626c8..b9aa34e89216 100644 --- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java +++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java @@ -18,6 +18,7 @@ package com.android.server.display.whitebalance; import android.annotation.NonNull; import android.util.Slog; +import android.util.Spline; import com.android.internal.util.Preconditions; import com.android.server.LocalServices; @@ -75,6 +76,9 @@ public class DisplayWhiteBalanceController implements // Override the ambient color temperature for debugging purposes. private float mAmbientColorTemperatureOverride; + // A piecewise linear relationship between ambient and display color temperatures + private Spline.LinearSpline mAmbientToDisplayTemperatureSpline; + /** * @param brightnessSensor * The sensor used to detect changes in the ambient brightness. @@ -109,7 +113,8 @@ public class DisplayWhiteBalanceController implements @NonNull AmbientSensor.AmbientColorTemperatureSensor colorTemperatureSensor, @NonNull AmbientFilter colorTemperatureFilter, @NonNull DisplayWhiteBalanceThrottler throttler, - float lowLightAmbientBrightnessThreshold, float lowLightAmbientColorTemperature) { + float lowLightAmbientBrightnessThreshold, float lowLightAmbientColorTemperature, + float[] ambientTemperatures, float[] displayTemperatures) { validateArguments(brightnessSensor, brightnessFilter, colorTemperatureSensor, colorTemperatureFilter, throttler); mLoggingEnabled = false; @@ -127,6 +132,14 @@ public class DisplayWhiteBalanceController implements mLastAmbientColorTemperature = -1.0f; mAmbientColorTemperatureHistory = new History(HISTORY_SIZE); mAmbientColorTemperatureOverride = -1.0f; + + try { + mAmbientToDisplayTemperatureSpline = new Spline.LinearSpline(ambientTemperatures, + displayTemperatures); + } catch (Exception e) { + mAmbientToDisplayTemperatureSpline = null; + } + mColorDisplayServiceInternal = LocalServices.getService(ColorDisplayServiceInternal.class); } @@ -227,6 +240,9 @@ public class DisplayWhiteBalanceController implements writer.println(" mLastAmbientColorTemperature=" + mLastAmbientColorTemperature); writer.println(" mAmbientColorTemperatureHistory=" + mAmbientColorTemperatureHistory); writer.println(" mAmbientColorTemperatureOverride=" + mAmbientColorTemperatureOverride); + writer.println(" mAmbientToDisplayTemperatureSpline=" + + (mAmbientToDisplayTemperatureSpline == null ? "unused" : + mAmbientToDisplayTemperatureSpline)); } @Override // AmbientSensor.AmbientBrightnessSensor.Callbacks @@ -250,6 +266,11 @@ public class DisplayWhiteBalanceController implements final long time = System.currentTimeMillis(); float ambientColorTemperature = mColorTemperatureFilter.getEstimate(time); + if (mAmbientToDisplayTemperatureSpline != null) { + ambientColorTemperature = + mAmbientToDisplayTemperatureSpline.interpolate(ambientColorTemperature); + } + final float ambientBrightness = mBrightnessFilter.getEstimate(time); if (ambientBrightness < mLowLightAmbientBrightnessThreshold) { if (mLoggingEnabled) { diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java index fd78ddbda9c8..56f4ca339eb3 100644 --- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java +++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java @@ -67,9 +67,14 @@ public class DisplayWhiteBalanceFactory { final float lowLightAmbientColorTemperature = getFloat(resources, com.android.internal.R.dimen .config_displayWhiteBalanceLowLightAmbientColorTemperature); + final float[] ambientTemperatures = getFloatArray(resources, + com.android.internal.R.array.config_displayWhiteBalanceAmbientTemperatureValues); + final float[] displayTemperatures = getFloatArray(resources, + com.android.internal.R.array.config_displayWhiteBalanceDisplayTemperatureValues); final DisplayWhiteBalanceController controller = new DisplayWhiteBalanceController( brightnessSensor, brightnessFilter, colorTemperatureSensor, colorTemperatureFilter, - throttler, lowLightAmbientBrightnessThreshold, lowLightAmbientColorTemperature); + throttler, lowLightAmbientBrightnessThreshold, lowLightAmbientColorTemperature, + ambientTemperatures, displayTemperatures); brightnessSensor.setCallbacks(controller); colorTemperatureSensor.setCallbacks(controller); return controller; diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java index cf84e22e7dd1..1b237949a543 100644 --- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java +++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java @@ -187,7 +187,7 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR @Override public boolean isDefaultServiceEnabled(int userId) { synchronized (mLock) { - return mDefaultServicesDisabled.get(userId); + return !mDefaultServicesDisabled.get(userId); } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 144f2b6b143f..96ba0841855c 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -667,13 +667,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final int mSequenceNumber; final long mTimestamp; final long mWallTime; + @UserIdInt + final int mImeUserId; @NonNull final IBinder mImeToken; + final int mImeDisplayId; @NonNull final String mImeId; @StartInputReason final int mStartInputReason; final boolean mRestarting; + @UserIdInt + final int mTargetUserId; + final int mTargetDisplayId; @Nullable final IBinder mTargetWindow; @NonNull @@ -682,17 +688,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final int mTargetWindowSoftInputMode; final int mClientBindSequenceNumber; - StartInputInfo(@NonNull IBinder imeToken, @NonNull String imeId, - @StartInputReason int startInputReason, boolean restarting, - @Nullable IBinder targetWindow, @NonNull EditorInfo editorInfo, - @SoftInputModeFlags int targetWindowSoftInputMode, int clientBindSequenceNumber) { + StartInputInfo(@UserIdInt int imeUserId, @NonNull IBinder imeToken, int imeDisplayId, + @NonNull String imeId, @StartInputReason int startInputReason, boolean restarting, + @UserIdInt int targetUserId, int targetDisplayId, @Nullable IBinder targetWindow, + @NonNull EditorInfo editorInfo, @SoftInputModeFlags int targetWindowSoftInputMode, + int clientBindSequenceNumber) { mSequenceNumber = sSequenceNumber.getAndIncrement(); mTimestamp = SystemClock.uptimeMillis(); mWallTime = System.currentTimeMillis(); + mImeUserId = imeUserId; mImeToken = imeToken; + mImeDisplayId = imeDisplayId; mImeId = imeId; mStartInputReason = startInputReason; mRestarting = restarting; + mTargetUserId = targetUserId; + mTargetDisplayId = targetDisplayId; mTargetWindow = targetWindow; mEditorInfo = editorInfo; mTargetWindowSoftInputMode = targetWindowSoftInputMode; @@ -749,13 +760,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub int mSequenceNumber; long mTimestamp; long mWallTime; + @UserIdInt + int mImeUserId; @NonNull String mImeTokenString; + int mImeDisplayId; @NonNull String mImeId; @StartInputReason int mStartInputReason; boolean mRestarting; + @UserIdInt + int mTargetUserId; + int mTargetDisplayId; @NonNull String mTargetWindowString; @NonNull @@ -772,12 +789,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mSequenceNumber = original.mSequenceNumber; mTimestamp = original.mTimestamp; mWallTime = original.mWallTime; + mImeUserId = original.mImeUserId; // Intentionally convert to String so as not to keep a strong reference to a Binder // object. mImeTokenString = String.valueOf(original.mImeToken); + mImeDisplayId = original.mImeDisplayId; mImeId = original.mImeId; mStartInputReason = original.mStartInputReason; mRestarting = original.mRestarting; + mTargetUserId = original.mTargetUserId; + mTargetDisplayId = original.mTargetDisplayId; // Intentionally convert to String so as not to keep a strong reference to a Binder // object. mTargetWindowString = String.valueOf(original.mTargetWindow); @@ -821,11 +842,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + " restarting=" + entry.mRestarting); pw.print(prefix); - pw.println(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]"); + pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]"); + pw.print(" imeUserId=" + entry.mImeUserId); + pw.println(" imeDisplayId=" + entry.mImeDisplayId); pw.print(prefix); pw.println(" targetWin=" + entry.mTargetWindowString + " [" + entry.mEditorInfo.packageName + "]" + + " targetUserId=" + entry.mTargetUserId + + " targetDisplayId=" + entry.mTargetDisplayId + " clientBindSeq=" + entry.mClientBindSequenceNumber); pw.print(prefix); @@ -1904,9 +1929,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } final Binder startInputToken = new Binder(); - final StartInputInfo info = new StartInputInfo(mCurToken, mCurId, startInputReason, - !initial, mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, - mCurSeq); + final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), mCurToken, + mCurTokenDisplayId, mCurId, startInputReason, !initial, + UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId, + mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, mCurSeq); mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow); mStartInputHistory.addEntry(info); diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 19d10ecfb34d..cefe583fc5d1 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -509,7 +509,7 @@ public class JobSchedulerService extends com.android.server.SystemService private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f; private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f; private static final boolean DEFAULT_USE_HEARTBEATS = false; - private static final boolean DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false; + private static final boolean DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; private static final long DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = 10 * 60 * 1000L; // 10 minutes private static final long DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java index 97c3bac4ddbb..74628fb9b502 100644 --- a/services/core/java/com/android/server/job/controllers/StateController.java +++ b/services/core/java/com/android/server/job/controllers/StateController.java @@ -110,6 +110,7 @@ public abstract class StateController { final boolean jobWouldBeReady = jobStatus.wouldBeReadyWithConstraint(constraint); if (DEBUG) { Slog.v(TAG, "wouldBeReadyWithConstraintLocked: " + jobStatus.toShortString() + + " constraint=" + constraint + " readyWithConstraint=" + jobWouldBeReady); } if (!jobWouldBeReady) { diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java index 26f3caf2e487..70deb38080b4 100644 --- a/services/core/java/com/android/server/job/controllers/TimeController.java +++ b/services/core/java/com/android/server/job/controllers/TimeController.java @@ -149,8 +149,8 @@ public final class TimeController extends StateController { @Override public void onConstantsUpdatedLocked() { - checkExpiredDelaysAndResetAlarm(); checkExpiredDeadlinesAndResetAlarm(); + checkExpiredDelaysAndResetAlarm(); } @Override @@ -159,20 +159,47 @@ public final class TimeController extends StateController { return; } - if (job.hasTimingDelayConstraint() - && job.getEarliestRunTime() <= mNextDelayExpiredElapsedMillis) { - checkExpiredDelaysAndResetAlarm(); - } + final long nowElapsedMillis = sElapsedRealtimeClock.millis(); + + // Check deadline constraint first because if it's satisfied, we avoid a little bit of + // unnecessary processing of the timing delay. if (job.hasDeadlineConstraint() + && !job.isConstraintSatisfied(JobStatus.CONSTRAINT_DEADLINE) && job.getLatestRunTimeElapsed() <= mNextJobExpiredElapsedMillis) { - checkExpiredDeadlinesAndResetAlarm(); + if (evaluateDeadlineConstraint(job, nowElapsedMillis)) { + checkExpiredDeadlinesAndResetAlarm(); + checkExpiredDelaysAndResetAlarm(); + } else { + final boolean isAlarmForJob = + job.getLatestRunTimeElapsed() == mNextJobExpiredElapsedMillis; + final boolean wouldBeReady = wouldBeReadyWithConstraintLocked( + job, JobStatus.CONSTRAINT_DEADLINE); + if ((isAlarmForJob && !wouldBeReady) || (!isAlarmForJob && wouldBeReady)) { + checkExpiredDeadlinesAndResetAlarm(); + } + } + } + if (job.hasTimingDelayConstraint() + && !job.isConstraintSatisfied(JobStatus.CONSTRAINT_TIMING_DELAY) + && job.getEarliestRunTime() <= mNextDelayExpiredElapsedMillis) { + if (evaluateTimingDelayConstraint(job, nowElapsedMillis)) { + checkExpiredDelaysAndResetAlarm(); + } else { + final boolean isAlarmForJob = + job.getEarliestRunTime() == mNextDelayExpiredElapsedMillis; + final boolean wouldBeReady = wouldBeReadyWithConstraintLocked( + job, JobStatus.CONSTRAINT_TIMING_DELAY); + if ((isAlarmForJob && !wouldBeReady) || (!isAlarmForJob && wouldBeReady)) { + checkExpiredDelaysAndResetAlarm(); + } + } } } @Override public void reevaluateStateLocked(int uid) { - checkExpiredDelaysAndResetAlarm(); checkExpiredDeadlinesAndResetAlarm(); + checkExpiredDelaysAndResetAlarm(); } /** @@ -182,10 +209,10 @@ public final class TimeController extends StateController { * back and forth. */ private boolean canStopTrackingJobLocked(JobStatus job) { - return (!job.hasTimingDelayConstraint() || - (job.satisfiedConstraints&JobStatus.CONSTRAINT_TIMING_DELAY) != 0) && - (!job.hasDeadlineConstraint() || - (job.satisfiedConstraints&JobStatus.CONSTRAINT_DEADLINE) != 0); + return (!job.hasTimingDelayConstraint() + || job.isConstraintSatisfied(JobStatus.CONSTRAINT_TIMING_DELAY)) + && (!job.hasDeadlineConstraint() + || job.isConstraintSatisfied(JobStatus.CONSTRAINT_DEADLINE)); } private void ensureAlarmServiceLocked() { @@ -241,6 +268,7 @@ public final class TimeController extends StateController { } } + /** @return true if the job's deadline constraint is satisfied */ private boolean evaluateDeadlineConstraint(JobStatus job, long nowElapsedMillis) { final long jobDeadline = job.getLatestRunTimeElapsed(); @@ -279,7 +307,7 @@ public final class TimeController extends StateController { if (job.isReady()) { ready = true; } - } else if (!job.isConstraintSatisfied(JobStatus.CONSTRAINT_TIMING_DELAY)) { + } else { if (mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS && !wouldBeReadyWithConstraintLocked( job, JobStatus.CONSTRAINT_TIMING_DELAY)) { @@ -319,6 +347,7 @@ public final class TimeController extends StateController { } } + /** @return true if the job's delay constraint is satisfied */ private boolean evaluateTimingDelayConstraint(JobStatus job, long nowElapsedMillis) { final long jobDelayTime = job.getEarliestRunTime(); if (jobDelayTime <= nowElapsedMillis) { @@ -347,6 +376,9 @@ public final class TimeController extends StateController { */ private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) { alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis); + if (mNextDelayExpiredElapsedMillis == alarmTimeElapsedMillis) { + return; + } mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis; updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener, mNextDelayExpiredElapsedMillis, ws); @@ -359,6 +391,9 @@ public final class TimeController extends StateController { */ private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) { alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis); + if (mNextJobExpiredElapsedMillis == alarmTimeElapsedMillis) { + return; + } mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis; updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener, mNextJobExpiredElapsedMillis, ws); diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java index 72259268aa81..91b5234e02e5 100644 --- a/services/core/java/com/android/server/location/GnssConfiguration.java +++ b/services/core/java/com/android/server/location/GnssConfiguration.java @@ -367,7 +367,7 @@ class GnssConfiguration { return defaultValue; } try { - return Integer.parseInt(valueString); + return Integer.decode(valueString); } catch (NumberFormatException e) { Log.e(TAG, "Unable to parse config parameter " + configParameter + " value: " + valueString + ". Using default value: " + defaultValue); diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index f368e7b8494e..2f0b388b9a7d 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -302,7 +302,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements MAX_RETRY_INTERVAL); // true if we are enabled, protected by this - private boolean mEnabled = true; + private boolean mEnabled; private boolean mShutdown; diff --git a/services/core/java/com/android/server/location/LocationBasedCountryDetector.java b/services/core/java/com/android/server/location/LocationBasedCountryDetector.java index 6527899f2979..8ee1285b41f2 100644 --- a/services/core/java/com/android/server/location/LocationBasedCountryDetector.java +++ b/services/core/java/com/android/server/location/LocationBasedCountryDetector.java @@ -235,18 +235,15 @@ public class LocationBasedCountryDetector extends CountryDetectorBase { * Start a new thread to query the country from Geocoder. */ private synchronized void queryCountryCode(final Location location) { - if (location == null) { - notifyListener(null); - return; - } if (mQueryThread != null) return; mQueryThread = new Thread(new Runnable() { @Override public void run() { - String countryIso = null; - if (location != null) { - countryIso = getCountryFromLocation(location); + if (location == null) { + notifyListener(null); + return; } + String countryIso = getCountryFromLocation(location); if (countryIso != null) { mDetectedCountry = new Country(countryIso, Country.COUNTRY_SOURCE_LOCATION); } else { diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java index 1f9b027be030..e7a71b99a213 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java @@ -20,6 +20,7 @@ import static android.security.keystore.recovery.KeyChainProtectionParams.TYPE_L import android.annotation.Nullable; import android.content.Context; +import android.os.RemoteException; import android.security.Scrypt; import android.security.keystore.recovery.KeyChainProtectionParams; import android.security.keystore.recovery.KeyChainSnapshot; @@ -162,7 +163,7 @@ public class KeySyncTask implements Runnable { } } - private void syncKeys() { + private void syncKeys() throws RemoteException { if (mCredentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) { // Application keys for the user will not be available for sync. Log.w(TAG, "Credentials are not set for user " + mUserId); @@ -195,7 +196,7 @@ public class KeySyncTask implements Runnable { && mCredentialType != LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; } - private void syncKeysForAgent(int recoveryAgentUid) throws IOException { + private void syncKeysForAgent(int recoveryAgentUid) throws IOException, RemoteException { boolean shouldRecreateCurrentVersion = false; if (!shouldCreateSnapshot(recoveryAgentUid)) { shouldRecreateCurrentVersion = @@ -412,7 +413,7 @@ public class KeySyncTask implements Runnable { private Map<String, Pair<SecretKey, byte[]>> getKeysToSync(int recoveryAgentUid) throws InsecureUserException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, NoSuchPaddingException, BadPlatformKeyException, - InvalidKeyException, InvalidAlgorithmParameterException, IOException { + InvalidKeyException, InvalidAlgorithmParameterException, IOException, RemoteException { PlatformDecryptionKey decryptKey = mPlatformKeyManager.getDecryptKey(mUserId);; Map<String, WrappedKey> wrappedKeys = mRecoverableKeyStoreDb.getAllKeys( mUserId, recoveryAgentUid, decryptKey.getGenerationId()); diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java index 9ca052b9c9a8..1c187713540a 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java @@ -18,15 +18,21 @@ package com.android.server.locksettings.recoverablekeystore; import android.app.KeyguardManager; import android.content.Context; +import android.os.RemoteException; +import android.security.GateKeeper; import android.security.keystore.AndroidKeyStoreSecretKey; +import android.security.keystore.KeyPermanentlyInvalidatedException; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; +import android.service.gatekeeper.IGateKeeperService; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb; import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -34,9 +40,11 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.Locale; +import javax.crypto.Cipher; import javax.crypto.KeyGenerator; +import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; -import javax.security.auth.DestroyFailedException; +import javax.crypto.spec.GCMParameterSpec; /** * Manages creating and checking the validity of the platform key. @@ -67,6 +75,10 @@ public class PlatformKeyManager { private static final String ENCRYPT_KEY_ALIAS_SUFFIX = "encrypt"; private static final String DECRYPT_KEY_ALIAS_SUFFIX = "decrypt"; private static final int USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS = 15; + private static final String KEY_WRAP_CIPHER_ALGORITHM = "AES/GCM/NoPadding"; + private static final int GCM_TAG_LENGTH_BITS = 128; + // Only used for checking if a key is usable + private static final byte[] GCM_INSECURE_NONCE_BYTES = new byte[12]; private final Context mContext; private final KeyStoreProxy mKeyStore; @@ -158,12 +170,14 @@ public class PlatformKeyManager { * @throws KeyStoreException if there is an error in AndroidKeyStore. * @throws InsecureUserException if the user does not have a lock screen set. * @throws IOException if there was an issue with local database update. + * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}. * * @hide */ @VisibleForTesting void regenerate(int userId) - throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException, IOException { + throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException, IOException, + RemoteException { if (!isAvailable(userId)) { throw new InsecureUserException(String.format( Locale.US, "%d does not have a lock screen set.", userId)); @@ -190,11 +204,13 @@ public class PlatformKeyManager { * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. * @throws InsecureUserException if the user does not have a lock screen set. * @throws IOException if there was an issue with local database update. + * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}. * * @hide */ - public PlatformEncryptionKey getEncryptKey(int userId) throws KeyStoreException, - UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException, IOException { + public PlatformEncryptionKey getEncryptKey(int userId) + throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, + InsecureUserException, IOException, RemoteException { init(userId); try { // Try to see if the decryption key is still accessible before using the encryption key. @@ -243,14 +259,18 @@ public class PlatformKeyManager { * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. * @throws InsecureUserException if the user does not have a lock screen set. * @throws IOException if there was an issue with local database update. + * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}. * * @hide */ - public PlatformDecryptionKey getDecryptKey(int userId) throws KeyStoreException, - UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException, IOException { + public PlatformDecryptionKey getDecryptKey(int userId) + throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, + InsecureUserException, IOException, RemoteException { init(userId); try { - return getDecryptKeyInternal(userId); + PlatformDecryptionKey decryptionKey = getDecryptKeyInternal(userId); + ensureDecryptionKeyIsValid(userId, decryptionKey); + return decryptionKey; } catch (UnrecoverableKeyException e) { Log.i(TAG, String.format(Locale.US, "Regenerating permanently invalid Platform key for user %d.", @@ -284,6 +304,29 @@ public class PlatformKeyManager { } /** + * Tries to use the decryption key to make sure it is not permanently invalidated. The exception + * {@code KeyPermanentlyInvalidatedException} is thrown only when the key is in use. + * + * <p>Note that we ignore all other InvalidKeyException exceptions, because such an exception + * may be thrown for auth-bound keys if there's no recent unlock event. + */ + private void ensureDecryptionKeyIsValid(int userId, PlatformDecryptionKey decryptionKey) + throws UnrecoverableKeyException { + try { + Cipher.getInstance(KEY_WRAP_CIPHER_ALGORITHM).init(Cipher.UNWRAP_MODE, + decryptionKey.getKey(), + new GCMParameterSpec(GCM_TAG_LENGTH_BITS, GCM_INSECURE_NONCE_BYTES)); + } catch (KeyPermanentlyInvalidatedException e) { + Log.e(TAG, String.format(Locale.US, "The platform key for user %d became invalid.", + userId)); + throw new UnrecoverableKeyException(e.getMessage()); + } catch (NoSuchAlgorithmException | InvalidKeyException + | InvalidAlgorithmParameterException | NoSuchPaddingException e) { + // Ignore all other exceptions + } + } + + /** * Initializes the class. If there is no current platform key, and the user has a lock screen * set, will create the platform key and set the generation ID. * @@ -291,11 +334,13 @@ public class PlatformKeyManager { * @throws KeyStoreException if there was an error in AndroidKeyStore. * @throws NoSuchAlgorithmException if AES is unavailable - should never happen. * @throws IOException if there was an issue with local database update. + * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}. * * @hide */ void init(int userId) - throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException, IOException { + throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException, IOException, + RemoteException { if (!isAvailable(userId)) { throw new InsecureUserException(String.format( Locale.US, "%d does not have a lock screen set.", userId)); @@ -372,6 +417,11 @@ public class PlatformKeyManager { && mKeyStore.containsAlias(getDecryptAlias(userId, generationId)); } + @VisibleForTesting + IGateKeeperService getGateKeeperService() { + return GateKeeper.getService(); + } + /** * Generates a new 256-bit AES key, and loads it into AndroidKeyStore with the given * {@code generationId} determining its aliases. @@ -380,15 +430,23 @@ public class PlatformKeyManager { * available since API version 1. * @throws KeyStoreException if there was an issue loading the keys into AndroidKeyStore. * @throws IOException if there was an issue with local database update. + * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}. */ private void generateAndLoadKey(int userId, int generationId) - throws NoSuchAlgorithmException, KeyStoreException, IOException { + throws NoSuchAlgorithmException, KeyStoreException, IOException, RemoteException { String encryptAlias = getEncryptAlias(userId, generationId); String decryptAlias = getDecryptAlias(userId, generationId); // SecretKey implementation doesn't provide reliable way to destroy the secret // so it may live in memory for some time. SecretKey secretKey = generateAesKey(); + long secureUserId = getGateKeeperService().getSecureUserId(userId); + // TODO(b/124095438): Propagate this failure instead of silently failing. + if (secureUserId == GateKeeper.INVALID_SECURE_USER_ID) { + Log.e(TAG, "No SID available for user " + userId); + return; + } + // Store decryption key first since it is more likely to fail. mKeyStore.setEntry( decryptAlias, @@ -399,7 +457,7 @@ public class PlatformKeyManager { USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) - .setBoundToSpecificSecureUserId(userId) + .setBoundToSpecificSecureUserId(secureUserId) .build()); mKeyStore.setEntry( encryptAlias, diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index a7f114655dcb..e479a1539e25 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -23,6 +23,9 @@ import static android.content.Intent.ACTION_PACKAGE_REMOVED; import static android.content.Intent.ACTION_USER_ADDED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.pm.PackageManager.SIGNATURE_MATCH; +import static android.os.Trace.TRACE_TAG_RRO; +import static android.os.Trace.traceBegin; +import static android.os.Trace.traceEnd; import android.annotation.NonNull; import android.annotation.Nullable; @@ -223,36 +226,41 @@ public final class OverlayManagerService extends SystemService { public OverlayManagerService(@NonNull final Context context, @NonNull final Installer installer) { super(context); - mSettingsFile = new AtomicFile( - new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays"); - mPackageManager = new PackageManagerHelper(); - mUserManager = UserManagerService.getInstance(); - IdmapManager im = new IdmapManager(installer); - mSettings = new OverlayManagerSettings(); - mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings, - getDefaultOverlayPackages(), new OverlayChangeListener()); - - final IntentFilter packageFilter = new IntentFilter(); - packageFilter.addAction(ACTION_PACKAGE_ADDED); - packageFilter.addAction(ACTION_PACKAGE_CHANGED); - packageFilter.addAction(ACTION_PACKAGE_REMOVED); - packageFilter.addDataScheme("package"); - getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, - packageFilter, null, null); - - final IntentFilter userFilter = new IntentFilter(); - userFilter.addAction(ACTION_USER_ADDED); - userFilter.addAction(ACTION_USER_REMOVED); - getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL, - userFilter, null, null); - - restoreSettings(); - - initIfNeeded(); - onSwitchUser(UserHandle.USER_SYSTEM); - - publishBinderService(Context.OVERLAY_SERVICE, mService); - publishLocalService(OverlayManagerService.class, this); + try { + traceBegin(TRACE_TAG_RRO, "OMS#OverlayManagerService"); + mSettingsFile = new AtomicFile( + new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays"); + mPackageManager = new PackageManagerHelper(); + mUserManager = UserManagerService.getInstance(); + IdmapManager im = new IdmapManager(installer); + mSettings = new OverlayManagerSettings(); + mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings, + getDefaultOverlayPackages(), new OverlayChangeListener()); + + final IntentFilter packageFilter = new IntentFilter(); + packageFilter.addAction(ACTION_PACKAGE_ADDED); + packageFilter.addAction(ACTION_PACKAGE_CHANGED); + packageFilter.addAction(ACTION_PACKAGE_REMOVED); + packageFilter.addDataScheme("package"); + getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, + packageFilter, null, null); + + final IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(ACTION_USER_ADDED); + userFilter.addAction(ACTION_USER_REMOVED); + getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL, + userFilter, null, null); + + restoreSettings(); + + initIfNeeded(); + onSwitchUser(UserHandle.USER_SYSTEM); + + publishBinderService(Context.OVERLAY_SERVICE, mService); + publishLocalService(OverlayManagerService.class, this); + } finally { + traceEnd(TRACE_TAG_RRO); + } } @Override @@ -280,13 +288,18 @@ public final class OverlayManagerService extends SystemService { @Override public void onSwitchUser(final int newUserId) { - // ensure overlays in the settings are up-to-date, and propagate - // any asset changes to the rest of the system - synchronized (mLock) { - final List<String> targets = mImpl.updateOverlaysForUser(newUserId); - updateAssets(newUserId, targets); + try { + traceBegin(TRACE_TAG_RRO, "OMS#onSwitchUser " + newUserId); + // ensure overlays in the settings are up-to-date, and propagate + // any asset changes to the rest of the system + synchronized (mLock) { + final List<String> targets = mImpl.updateOverlaysForUser(newUserId); + updateAssets(newUserId, targets); + } + schedulePersistSettings(); + } finally { + traceEnd(TRACE_TAG_RRO); } - schedulePersistSettings(); } private static String[] getDefaultOverlayPackages() { @@ -350,85 +363,110 @@ public final class OverlayManagerService extends SystemService { private void onPackageAdded(@NonNull final String packageName, @NonNull final int[] userIds) { - for (final int userId : userIds) { - synchronized (mLock) { - final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, - false); - if (pi != null) { - mPackageManager.cachePackageInfo(packageName, userId, pi); - if (pi.isOverlayPackage()) { - mImpl.onOverlayPackageAdded(packageName, userId); - } else { - mImpl.onTargetPackageAdded(packageName, userId); + try { + traceBegin(TRACE_TAG_RRO, "OMS#onPackageAdded " + packageName); + for (final int userId : userIds) { + synchronized (mLock) { + final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, + false); + if (pi != null) { + mPackageManager.cachePackageInfo(packageName, userId, pi); + if (pi.isOverlayPackage()) { + mImpl.onOverlayPackageAdded(packageName, userId); + } else { + mImpl.onTargetPackageAdded(packageName, userId); + } } } } + } finally { + traceEnd(TRACE_TAG_RRO); } } private void onPackageChanged(@NonNull final String packageName, @NonNull final int[] userIds) { - for (int userId : userIds) { - synchronized (mLock) { - final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, - false); - if (pi != null) { - mPackageManager.cachePackageInfo(packageName, userId, pi); - if (pi.isOverlayPackage()) { - mImpl.onOverlayPackageChanged(packageName, userId); - } else { - mImpl.onTargetPackageChanged(packageName, userId); + try { + traceBegin(TRACE_TAG_RRO, "OMS#onPackageChanged " + packageName); + for (int userId : userIds) { + synchronized (mLock) { + final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, + false); + if (pi != null) { + mPackageManager.cachePackageInfo(packageName, userId, pi); + if (pi.isOverlayPackage()) { + mImpl.onOverlayPackageChanged(packageName, userId); + } else { + mImpl.onTargetPackageChanged(packageName, userId); + } } } } + } finally { + traceEnd(TRACE_TAG_RRO); } } private void onPackageUpgrading(@NonNull final String packageName, @NonNull final int[] userIds) { - for (int userId : userIds) { - synchronized (mLock) { - mPackageManager.forgetPackageInfo(packageName, userId); - final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId); - if (oi != null) { - mImpl.onOverlayPackageUpgrading(packageName, userId); - } else { - mImpl.onTargetPackageUpgrading(packageName, userId); + try { + traceBegin(TRACE_TAG_RRO, "OMS#onPackageUpgrading " + packageName); + for (int userId : userIds) { + synchronized (mLock) { + mPackageManager.forgetPackageInfo(packageName, userId); + final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId); + if (oi != null) { + mImpl.onOverlayPackageUpgrading(packageName, userId); + } else { + mImpl.onTargetPackageUpgrading(packageName, userId); + } } } + } finally { + traceEnd(TRACE_TAG_RRO); } } private void onPackageUpgraded(@NonNull final String packageName, @NonNull final int[] userIds) { - for (int userId : userIds) { - synchronized (mLock) { - final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, - false); - if (pi != null) { - mPackageManager.cachePackageInfo(packageName, userId, pi); - if (pi.isOverlayPackage()) { - mImpl.onOverlayPackageUpgraded(packageName, userId); - } else { - mImpl.onTargetPackageUpgraded(packageName, userId); + try { + traceBegin(TRACE_TAG_RRO, "OMS#onPackageUpgraded " + packageName); + for (int userId : userIds) { + synchronized (mLock) { + final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, + false); + if (pi != null) { + mPackageManager.cachePackageInfo(packageName, userId, pi); + if (pi.isOverlayPackage()) { + mImpl.onOverlayPackageUpgraded(packageName, userId); + } else { + mImpl.onTargetPackageUpgraded(packageName, userId); + } } } } + } finally { + traceEnd(TRACE_TAG_RRO); } } private void onPackageRemoved(@NonNull final String packageName, @NonNull final int[] userIds) { - for (int userId : userIds) { - synchronized (mLock) { - mPackageManager.forgetPackageInfo(packageName, userId); - final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId); - if (oi != null) { - mImpl.onOverlayPackageRemoved(packageName, userId); - } else { - mImpl.onTargetPackageRemoved(packageName, userId); + try { + traceBegin(TRACE_TAG_RRO, "OMS#onPackageRemoved " + packageName); + for (int userId : userIds) { + synchronized (mLock) { + mPackageManager.forgetPackageInfo(packageName, userId); + final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId); + if (oi != null) { + mImpl.onOverlayPackageRemoved(packageName, userId); + } else { + mImpl.onTargetPackageRemoved(packageName, userId); + } } } + } finally { + traceEnd(TRACE_TAG_RRO); } } } @@ -440,19 +478,29 @@ public final class OverlayManagerService extends SystemService { switch (intent.getAction()) { case ACTION_USER_ADDED: if (userId != UserHandle.USER_NULL) { - final ArrayList<String> targets; - synchronized (mLock) { - targets = mImpl.updateOverlaysForUser(userId); + try { + traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_ADDED"); + final ArrayList<String> targets; + synchronized (mLock) { + targets = mImpl.updateOverlaysForUser(userId); + } + updateOverlayPaths(userId, targets); + } finally { + traceEnd(TRACE_TAG_RRO); } - updateOverlayPaths(userId, targets); } break; case ACTION_USER_REMOVED: if (userId != UserHandle.USER_NULL) { - synchronized (mLock) { - mImpl.onUserRemoved(userId); - mPackageManager.forgetAllPackageInfos(userId); + try { + traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_REMOVED"); + synchronized (mLock) { + mImpl.onUserRemoved(userId); + mPackageManager.forgetAllPackageInfos(userId); + } + } finally { + traceEnd(TRACE_TAG_RRO); } } break; @@ -466,152 +514,198 @@ public final class OverlayManagerService extends SystemService { private final IBinder mService = new IOverlayManager.Stub() { @Override public Map<String, List<OverlayInfo>> getAllOverlays(int userId) throws RemoteException { - userId = handleIncomingUser(userId, "getAllOverlays"); + try { + traceBegin(TRACE_TAG_RRO, "OMS#getAllOverlays " + userId); + userId = handleIncomingUser(userId, "getAllOverlays"); - synchronized (mLock) { - return mImpl.getOverlaysForUser(userId); + synchronized (mLock) { + return mImpl.getOverlaysForUser(userId); + } + } finally { + traceEnd(TRACE_TAG_RRO); } } @Override public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName, int userId) throws RemoteException { - userId = handleIncomingUser(userId, "getOverlayInfosForTarget"); - if (targetPackageName == null) { - return Collections.emptyList(); - } + try { + traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfosForTarget " + targetPackageName); + userId = handleIncomingUser(userId, "getOverlayInfosForTarget"); + if (targetPackageName == null) { + return Collections.emptyList(); + } - synchronized (mLock) { - return mImpl.getOverlayInfosForTarget(targetPackageName, userId); + synchronized (mLock) { + return mImpl.getOverlayInfosForTarget(targetPackageName, userId); + } + } finally { + traceEnd(TRACE_TAG_RRO); } } @Override public OverlayInfo getOverlayInfo(@Nullable final String packageName, int userId) throws RemoteException { - userId = handleIncomingUser(userId, "getOverlayInfo"); - if (packageName == null) { - return null; - } + try { + traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfo " + packageName); + userId = handleIncomingUser(userId, "getOverlayInfo"); + if (packageName == null) { + return null; + } - synchronized (mLock) { - return mImpl.getOverlayInfo(packageName, userId); + synchronized (mLock) { + return mImpl.getOverlayInfo(packageName, userId); + } + } finally { + traceEnd(TRACE_TAG_RRO); } } @Override public boolean setEnabled(@Nullable final String packageName, final boolean enable, int userId) throws RemoteException { - enforceChangeOverlayPackagesPermission("setEnabled"); - userId = handleIncomingUser(userId, "setEnabled"); - if (packageName == null) { - return false; - } - - final long ident = Binder.clearCallingIdentity(); try { - synchronized (mLock) { - return mImpl.setEnabled(packageName, enable, userId); + traceBegin(TRACE_TAG_RRO, "OMS#setEnabled " + packageName + " " + enable); + enforceChangeOverlayPackagesPermission("setEnabled"); + userId = handleIncomingUser(userId, "setEnabled"); + if (packageName == null) { + return false; + } + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + return mImpl.setEnabled(packageName, enable, userId); + } + } finally { + Binder.restoreCallingIdentity(ident); } } finally { - Binder.restoreCallingIdentity(ident); + traceEnd(TRACE_TAG_RRO); } } @Override public boolean setEnabledExclusive(@Nullable final String packageName, final boolean enable, int userId) throws RemoteException { - enforceChangeOverlayPackagesPermission("setEnabledExclusive"); - userId = handleIncomingUser(userId, "setEnabledExclusive"); - if (packageName == null || !enable) { - return false; - } - - final long ident = Binder.clearCallingIdentity(); try { - synchronized (mLock) { - return mImpl.setEnabledExclusive(packageName, false /* withinCategory */, - userId); + traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusive " + packageName + " " + enable); + enforceChangeOverlayPackagesPermission("setEnabledExclusive"); + userId = handleIncomingUser(userId, "setEnabledExclusive"); + if (packageName == null || !enable) { + return false; + } + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + return mImpl.setEnabledExclusive(packageName, false /* withinCategory */, + userId); + } + } finally { + Binder.restoreCallingIdentity(ident); } } finally { - Binder.restoreCallingIdentity(ident); + traceEnd(TRACE_TAG_RRO); } } @Override public boolean setEnabledExclusiveInCategory(@Nullable String packageName, int userId) throws RemoteException { - enforceChangeOverlayPackagesPermission("setEnabledExclusiveInCategory"); - userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory"); - if (packageName == null) { - return false; - } - - final long ident = Binder.clearCallingIdentity(); try { - synchronized (mLock) { - return mImpl.setEnabledExclusive(packageName, true /* withinCategory */, - userId); + traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusiveInCategory " + packageName); + enforceChangeOverlayPackagesPermission("setEnabledExclusiveInCategory"); + userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory"); + if (packageName == null) { + return false; + } + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + return mImpl.setEnabledExclusive(packageName, true /* withinCategory */, + userId); + } + } finally { + Binder.restoreCallingIdentity(ident); } } finally { - Binder.restoreCallingIdentity(ident); + traceEnd(TRACE_TAG_RRO); } } @Override public boolean setPriority(@Nullable final String packageName, @Nullable final String parentPackageName, int userId) throws RemoteException { - enforceChangeOverlayPackagesPermission("setPriority"); - userId = handleIncomingUser(userId, "setPriority"); - if (packageName == null || parentPackageName == null) { - return false; - } - - final long ident = Binder.clearCallingIdentity(); try { - synchronized (mLock) { - return mImpl.setPriority(packageName, parentPackageName, userId); + traceBegin(TRACE_TAG_RRO, "OMS#setPriority " + packageName + " " + + parentPackageName); + enforceChangeOverlayPackagesPermission("setPriority"); + userId = handleIncomingUser(userId, "setPriority"); + if (packageName == null || parentPackageName == null) { + return false; + } + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + return mImpl.setPriority(packageName, parentPackageName, userId); + } + } finally { + Binder.restoreCallingIdentity(ident); } } finally { - Binder.restoreCallingIdentity(ident); + traceEnd(TRACE_TAG_RRO); } } @Override public boolean setHighestPriority(@Nullable final String packageName, int userId) throws RemoteException { - enforceChangeOverlayPackagesPermission("setHighestPriority"); - userId = handleIncomingUser(userId, "setHighestPriority"); - if (packageName == null) { - return false; - } - - final long ident = Binder.clearCallingIdentity(); try { - synchronized (mLock) { - return mImpl.setHighestPriority(packageName, userId); + traceBegin(TRACE_TAG_RRO, "OMS#setHighestPriority " + packageName); + enforceChangeOverlayPackagesPermission("setHighestPriority"); + userId = handleIncomingUser(userId, "setHighestPriority"); + if (packageName == null) { + return false; + } + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + return mImpl.setHighestPriority(packageName, userId); + } + } finally { + Binder.restoreCallingIdentity(ident); } } finally { - Binder.restoreCallingIdentity(ident); + traceEnd(TRACE_TAG_RRO); } } @Override public boolean setLowestPriority(@Nullable final String packageName, int userId) throws RemoteException { - enforceChangeOverlayPackagesPermission("setLowestPriority"); - userId = handleIncomingUser(userId, "setLowestPriority"); - if (packageName == null) { - return false; - } - - final long ident = Binder.clearCallingIdentity(); try { - synchronized (mLock) { - return mImpl.setLowestPriority(packageName, userId); + traceBegin(TRACE_TAG_RRO, "OMS#setLowestPriority " + packageName); + enforceChangeOverlayPackagesPermission("setLowestPriority"); + userId = handleIncomingUser(userId, "setLowestPriority"); + if (packageName == null) { + return false; + } + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + return mImpl.setLowestPriority(packageName, userId); + } + } finally { + Binder.restoreCallingIdentity(ident); } } finally { - Binder.restoreCallingIdentity(ident); + traceEnd(TRACE_TAG_RRO); } } @@ -705,45 +799,52 @@ public final class OverlayManagerService extends SystemService { * Updates the target packages' set of enabled overlays in PackageManager. */ private void updateOverlayPaths(int userId, List<String> targetPackageNames) { - if (DEBUG) { - Slog.d(TAG, "Updating overlay assets"); - } - final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); - final boolean updateFrameworkRes = targetPackageNames.contains("android"); - if (updateFrameworkRes) { - targetPackageNames = pm.getTargetPackageNames(userId); - } + try { + traceBegin(TRACE_TAG_RRO, "OMS#updateOverlayPaths " + targetPackageNames); + if (DEBUG) { + Slog.d(TAG, "Updating overlay assets"); + } + final PackageManagerInternal pm = + LocalServices.getService(PackageManagerInternal.class); + final boolean updateFrameworkRes = targetPackageNames.contains("android"); + if (updateFrameworkRes) { + targetPackageNames = pm.getTargetPackageNames(userId); + } + + final Map<String, List<String>> pendingChanges = + new ArrayMap<>(targetPackageNames.size()); + synchronized (mLock) { + final List<String> frameworkOverlays = + mImpl.getEnabledOverlayPackageNames("android", userId); + final int n = targetPackageNames.size(); + for (int i = 0; i < n; i++) { + final String targetPackageName = targetPackageNames.get(i); + List<String> list = new ArrayList<>(); + if (!"android".equals(targetPackageName)) { + list.addAll(frameworkOverlays); + } + list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId)); + pendingChanges.put(targetPackageName, list); + } + } - final Map<String, List<String>> pendingChanges = new ArrayMap<>(targetPackageNames.size()); - synchronized (mLock) { - final List<String> frameworkOverlays = - mImpl.getEnabledOverlayPackageNames("android", userId); final int n = targetPackageNames.size(); for (int i = 0; i < n; i++) { final String targetPackageName = targetPackageNames.get(i); - List<String> list = new ArrayList<>(); - if (!"android".equals(targetPackageName)) { - list.addAll(frameworkOverlays); + if (DEBUG) { + Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=[" + + TextUtils.join(",", pendingChanges.get(targetPackageName)) + + "] userId=" + userId); } - list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId)); - pendingChanges.put(targetPackageName, list); - } - } - - final int n = targetPackageNames.size(); - for (int i = 0; i < n; i++) { - final String targetPackageName = targetPackageNames.get(i); - if (DEBUG) { - Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=[" - + TextUtils.join(",", pendingChanges.get(targetPackageName)) - + "] userId=" + userId); - } - if (!pm.setEnabledOverlayPackages( - userId, targetPackageName, pendingChanges.get(targetPackageName))) { - Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d", - targetPackageName, userId)); + if (!pm.setEnabledOverlayPackages( + userId, targetPackageName, pendingChanges.get(targetPackageName))) { + Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d", + targetPackageName, userId)); + } } + } finally { + traceEnd(TRACE_TAG_RRO); } } @@ -785,32 +886,37 @@ public final class OverlayManagerService extends SystemService { } private void restoreSettings() { - synchronized (mLock) { - if (!mSettingsFile.getBaseFile().exists()) { - return; - } - try (FileInputStream stream = mSettingsFile.openRead()) { - mSettings.restore(stream); + try { + traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings"); + synchronized (mLock) { + if (!mSettingsFile.getBaseFile().exists()) { + return; + } + try (FileInputStream stream = mSettingsFile.openRead()) { + mSettings.restore(stream); - // We might have data for dying users if the device was - // restarted before we received USER_REMOVED. Remove data for - // users that will not exist after the system is ready. + // We might have data for dying users if the device was + // restarted before we received USER_REMOVED. Remove data for + // users that will not exist after the system is ready. - final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/); - final int[] liveUserIds = new int[liveUsers.size()]; - for (int i = 0; i < liveUsers.size(); i++) { - liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier(); - } - Arrays.sort(liveUserIds); + final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/); + final int[] liveUserIds = new int[liveUsers.size()]; + for (int i = 0; i < liveUsers.size(); i++) { + liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier(); + } + Arrays.sort(liveUserIds); - for (int userId : mSettings.getUsers()) { - if (Arrays.binarySearch(liveUserIds, userId) < 0) { - mSettings.removeUser(userId); + for (int userId : mSettings.getUsers()) { + if (Arrays.binarySearch(liveUserIds, userId) < 0) { + mSettings.removeUser(userId); + } } + } catch (IOException | XmlPullParserException e) { + Slog.e(TAG, "failed to restore overlay state", e); } - } catch (IOException | XmlPullParserException e) { - Slog.e(TAG, "failed to restore overlay state", e); } + } finally { + traceEnd(TRACE_TAG_RRO); } } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 21965e4e83a2..f6bd2a95a4a3 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -481,6 +481,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } } + if (params.isStaged) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG); + } + if (!params.isMultiPackage) { // Only system components can circumvent runtime permissions when installing. if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0 diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index eaedec597359..874d1a719ee6 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -16321,7 +16321,6 @@ public class PackageManagerService extends IPackageManager.Stub final boolean onExternal = args.volumeUuid != null; final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0); final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0); - final boolean forceSdk = ((installFlags & PackageManager.INSTALL_FORCE_SDK) != 0); final boolean virtualPreload = ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0); @ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE; @@ -16353,8 +16352,7 @@ public class PackageManagerService extends IPackageManager.Stub // Retrieve PackageSettings and parse package @ParseFlags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY | PackageParser.PARSE_ENFORCE_CODE - | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0) - | (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0); + | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0); PackageParser pp = new PackageParser(); pp.setSeparateProcesses(mSeparateProcesses); @@ -16775,19 +16773,6 @@ public class PackageManagerService extends IPackageManager.Stub "replacePackageLI: new=" + pkg + ", old=" + oldPackage); } - // don't allow upgrade to target a release SDK from a pre-release SDK - final boolean oldTargetsPreRelease = oldPackage.applicationInfo.targetSdkVersion - == Build.VERSION_CODES.CUR_DEVELOPMENT; - final boolean newTargetsPreRelease = pkg.applicationInfo.targetSdkVersion - == Build.VERSION_CODES.CUR_DEVELOPMENT; - if (oldTargetsPreRelease - && !newTargetsPreRelease - && ((parseFlags & PackageParser.PARSE_FORCE_SDK) == 0)) { - Slog.w(TAG, "Can't install package targeting released sdk"); - throw new PrepareFailure( - PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE); - } - ps = mSettings.mPackages.get(pkgName11); disabledPs = mSettings.getDisabledSystemPkgLPr(ps); diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index dc18dfcf8613..2eb762b59be4 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -2383,8 +2383,7 @@ class PackageManagerShellCommand extends ShellCommand { sessionParams.volumeUuid = null; } break; - case "--force-sdk": - sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK; + case "--force-sdk": // ignore break; case "--apex": sessionParams.setInstallAsApex(); @@ -2961,8 +2960,6 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" 0=unknown, 1=admin policy, 2=device restore,"); pw.println(" 3=device setup, 4=user request"); pw.println(" --force-uuid: force install on to disk volume with given UUID"); - pw.println(" --force-sdk: allow install even when existing app targets platform"); - pw.println(" codename but new one targets a final API level"); pw.println(" --apex: install an .apex file, not an .apk"); pw.println(""); pw.println(" install-create [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]"); diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 89aea36429d2..fa8360b1e5ba 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -220,6 +220,7 @@ public class StagingManager { session.setStagedSessionFailed( SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, "APEX staging failed, check logcat messages from apexd for more details."); + return; } if (apexInfoList.apexInfos != null && apexInfoList.apexInfos.length > 0) { diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index 8d64b810b407..7e4365dafbe4 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -119,6 +119,7 @@ public class UserRestrictionsUtils { UserManager.DISALLOW_OEM_UNLOCK, UserManager.DISALLOW_UNMUTE_DEVICE, UserManager.DISALLOW_AUTOFILL, + UserManager.DISALLOW_CONTENT_CAPTURE, UserManager.DISALLOW_USER_SWITCH, UserManager.DISALLOW_UNIFIED_PASSWORD, UserManager.DISALLOW_CONFIG_LOCATION, @@ -743,6 +744,9 @@ public class UserRestrictionsUtils { case android.provider.Settings.Global.PRIVATE_DNS_MODE: case android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER: + if (callingUid == Process.SYSTEM_UID) { + return false; + } restriction = UserManager.DISALLOW_CONFIG_PRIVATE_DNS; break; default: diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java index 23705db884f5..9948a3ad47da 100644 --- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -480,10 +480,13 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { final String apkPath = pkg.baseCodePath; final ApplicationInfo appInfo = pkg.applicationInfo; final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex"; - if (appInfo.isPrivilegedApp() || appInfo.isEmbeddedDexUsed()) { + if (appInfo.isPrivilegedApp() || appInfo.isEmbeddedDexUsed() + || appInfo.isDefaultToDeviceProtectedStorage()) { // Privileged apps prefer to load trusted code so they don't use compiled views. // If the app is not privileged but prefers code integrity, also avoid compiling // views. + // Also disable the view compiler for protected storage apps since there are + // selinux permissions required for writing to user_de. return false; } Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath + diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index bfa539c9007e..2036ed73fdf2 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -645,7 +645,7 @@ public final class DefaultPermissionGrantPolicy { grantPermissionsToSystemPackage(packageName, userId, CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS, PHONE_PERMISSIONS, SMS_PERMISSIONS, CAMERA_PERMISSIONS, - SENSORS_PERMISSIONS, STORAGE_PERMISSIONS); + SENSORS_PERMISSIONS, STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS); grantSystemFixedPermissionsToSystemPackage(packageName, userId, LOCATION_PERMISSIONS, ACTIVITY_RECOGNITION_PERMISSIONS); } diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java index e7de8ddf87d1..3534cf30e2bf 100644 --- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java +++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java @@ -67,8 +67,8 @@ public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHolder mContext.getContentResolver(), Settings.Secure.SMS_DEFAULT_APPLICATION, userId); - // TODO: STOPSHIP: Remove the following code once we remove default_sms_application - // and use the new config_defaultRoleHolders. + // TODO: STOPSHIP: Remove the following code once we read the value of + // config_defaultSms in RoleControllerService. if (result == null) { Collection<SmsApplication.SmsApplicationData> applications = SmsApplication.getApplicationCollectionAsUser(mContext, userId); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index af3bff0c96ba..1782b6a8aa78 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -197,7 +197,8 @@ public final class PowerManagerService extends SystemService // System Property indicating that retail demo mode is currently enabled. private static final String SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED = "sys.retaildemo.enabled"; - // Possible reasons for shutting down for use in data/misc/reboot/last_shutdown_reason + // Possible reasons for shutting down or reboot for use in REBOOT_PROPERTY(sys.boot.reason) + // which is set by bootstat private static final String REASON_SHUTDOWN = "shutdown"; private static final String REASON_REBOOT = "reboot"; private static final String REASON_USERREQUESTED = "shutdown,userrequested"; diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java index 3c6a54af4bd7..3a2b69f8a6e1 100644 --- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -16,8 +16,11 @@ package com.android.server.rollback; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; @@ -25,6 +28,7 @@ import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; import android.os.Handler; import android.os.HandlerThread; +import android.os.PowerManager; import android.text.TextUtils; import android.util.Pair; import android.util.Slog; @@ -91,6 +95,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve + failedPackage.getVersionCode() + "]"); return false; } + RollbackInfo rollback = rollbackPair.first; // We only log mainline package rollbacks, so check if rollback contains the // module metadata provider, if it does, the rollback is a mainline rollback @@ -111,6 +116,12 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, moduleMetadataPackage.getPackageName(), moduleMetadataPackage.getVersionCode()); + if (rollback.isStaged()) { + int rollbackId = rollback.getRollbackId(); + BroadcastReceiver listener = + listenForStagedSessionReady(rollbackManager, rollbackId); + handleStagedSessionChange(rollbackManager, rollbackId, listener); + } } else { StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, @@ -178,4 +189,42 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve return null; } } + + private BroadcastReceiver listenForStagedSessionReady(RollbackManager rollbackManager, + int rollbackId) { + BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + handleStagedSessionChange(rollbackManager, + rollbackId, this /* BroadcastReceiver */); + } + }; + IntentFilter sessionUpdatedFilter = + new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED); + mContext.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter); + return sessionUpdatedReceiver; + } + + private void handleStagedSessionChange(RollbackManager rollbackManager, int rollbackId, + BroadcastReceiver listener) { + PackageInstaller packageInstaller = + mContext.getPackageManager().getPackageInstaller(); + List<RollbackInfo> recentRollbacks = + rollbackManager.getRecentlyCommittedRollbacks(); + for (int i = 0; i < recentRollbacks.size(); i++) { + RollbackInfo recentRollback = recentRollbacks.get(i); + int sessionId = recentRollback.getCommittedSessionId(); + if ((rollbackId == recentRollback.getRollbackId()) + && (sessionId != PackageInstaller.SessionInfo.INVALID_ID)) { + PackageInstaller.SessionInfo sessionInfo = + packageInstaller.getSessionInfo(sessionId); + if (sessionInfo.isSessionReady()) { + mContext.unregisterReceiver(listener); + mContext.getSystemService(PowerManager.class).reboot("Rollback staged install"); + } else if (sessionInfo.isSessionFailed()) { + mContext.unregisterReceiver(listener); + } + } + } + } } diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 35867728f2c9..dd2cda20e0f1 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -45,6 +45,8 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.content.pm.UserInfo; +import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import android.net.ConnectivityManager; import android.net.INetworkStatsService; @@ -1419,23 +1421,35 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - private void pullNumFingerprints(int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { + private void pullNumBiometricsEnrolled(int modality, int tagId, long elapsedNanos, + long wallClockNanos, List<StatsLogEventWrapper> pulledData) { FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class); - if (fingerprintManager == null) { + FaceManager faceManager = mContext.getSystemService(FaceManager.class); + if (modality == BiometricsProtoEnums.MODALITY_FINGERPRINT && fingerprintManager == null) { + return; + } + if (modality == BiometricsProtoEnums.MODALITY_FACE && faceManager == null) { return; } UserManager userManager = mContext.getSystemService(UserManager.class); if (userManager == null) { return; } + final long token = Binder.clearCallingIdentity(); for (UserInfo user : userManager.getUsers()) { final int userId = user.getUserHandle().getIdentifier(); - final int numFingerprints = fingerprintManager.getEnrolledFingerprints(userId).size(); + int numEnrolled = 0; + if (modality == BiometricsProtoEnums.MODALITY_FINGERPRINT) { + numEnrolled = fingerprintManager.getEnrolledFingerprints(userId).size(); + } else if (modality == BiometricsProtoEnums.MODALITY_FACE) { + numEnrolled = faceManager.getEnrolledFaces(userId).size(); + } else { + return; + } StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); e.writeInt(userId); - e.writeInt(numFingerprints); + e.writeInt(numEnrolled); pulledData.add(e); } Binder.restoreCallingIdentity(token); @@ -2027,7 +2041,13 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { break; } case StatsLog.NUM_FINGERPRINTS_ENROLLED: { - pullNumFingerprints(tagId, elapsedNanos, wallClockNanos, ret); + pullNumBiometricsEnrolled(BiometricsProtoEnums.MODALITY_FINGERPRINT, tagId, + elapsedNanos, wallClockNanos, ret); + break; + } + case StatsLog.NUM_FACES_ENROLLED: { + pullNumBiometricsEnrolled(BiometricsProtoEnums.MODALITY_FACE, tagId, elapsedNanos, + wallClockNanos, ret); break; } case StatsLog.PROC_STATS: { diff --git a/services/core/java/com/android/server/testharness/TestHarnessModeService.java b/services/core/java/com/android/server/testharness/TestHarnessModeService.java index 4adce586e9a5..ec62ec76b32f 100644 --- a/services/core/java/com/android/server/testharness/TestHarnessModeService.java +++ b/services/core/java/com/android/server/testharness/TestHarnessModeService.java @@ -22,6 +22,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.UserInfo; +import android.debug.AdbManagerInternal; import android.os.BatteryManager; import android.os.Binder; import android.os.IBinder; @@ -42,6 +43,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; @@ -49,7 +51,6 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.attribute.PosixFilePermission; import java.util.Set; @@ -85,6 +86,7 @@ public class TestHarnessModeService extends SystemService { break; case PHASE_BOOT_COMPLETED: disableAutoSync(); + configureSettings(); break; } super.onBootPhase(phase); @@ -98,47 +100,60 @@ public class TestHarnessModeService extends SystemService { return; } mShouldSetUpTestHarnessMode = true; + setUpAdb(testHarnessModeData); + setDeviceProvisioned(); + } + + private void setUpAdb(byte[] testHarnessModeData) { + ContentResolver cr = getContext().getContentResolver(); + // Disable the TTL for ADB keys before enabling ADB + Settings.Global.putLong(cr, Settings.Global.ADB_ALLOWED_CONNECTION_TIME, 0); + PersistentData persistentData = PersistentData.fromBytes(testHarnessModeData); SystemProperties.set(TEST_HARNESS_MODE_PROPERTY, persistentData.mEnabled ? "1" : "0"); writeAdbKeysFile(persistentData); - // Clear out the data block so that we don't revert the ADB keys on every boot. - getPersistentDataBlock().clearTestHarnessModeData(); + } - ContentResolver cr = getContext().getContentResolver(); - if (Settings.Global.getInt(cr, Settings.Global.ADB_ENABLED, 0) == 0) { - // Enable ADB - Settings.Global.putInt(cr, Settings.Global.ADB_ENABLED, 1); - } else { - // ADB is already enabled, we should restart the service so it picks up the new keys - android.os.SystemService.restart("adbd"); + private void disableAutoSync() { + if (!mShouldSetUpTestHarnessMode) { + return; } + UserInfo primaryUser = UserManager.get(getContext()).getPrimaryUser(); + ContentResolver + .setMasterSyncAutomaticallyAsUser(false, primaryUser.getUserHandle().getIdentifier()); + } + + private void configureSettings() { + if (!mShouldSetUpTestHarnessMode) { + return; + } + ContentResolver cr = getContext().getContentResolver(); + Settings.Global.putInt(cr, Settings.Global.ADB_ENABLED, 1); + Settings.Global.putInt(cr, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1); Settings.Global.putInt(cr, Settings.Global.PACKAGE_VERIFIER_ENABLE, 0); Settings.Global.putInt( cr, Settings.Global.STAY_ON_WHILE_PLUGGED_IN, BatteryManager.BATTERY_PLUGGED_ANY); Settings.Global.putInt(cr, Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE, 1); - Settings.Global.putInt(cr, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1); - - setDeviceProvisioned(); } - private void disableAutoSync() { - if (!mShouldSetUpTestHarnessMode) { - return; - } - UserInfo primaryUser = UserManager.get(getContext()).getPrimaryUser(); - ContentResolver - .setMasterSyncAutomaticallyAsUser(false, primaryUser.getUserHandle().getIdentifier()); + private void writeAdbKeysFile(PersistentData persistentData) { + AdbManagerInternal adbManager = LocalServices.getService(AdbManagerInternal.class); + + writeBytesToFile(persistentData.mAdbKeys, adbManager.getAdbKeysFile().toPath()); + writeBytesToFile(persistentData.mAdbTempKeys, adbManager.getAdbTempKeysFile().toPath()); + + // Clear out the data block so that we don't revert the ADB keys on every boot. + getPersistentDataBlock().clearTestHarnessModeData(); } - private void writeAdbKeysFile(PersistentData persistentData) { - Path adbKeys = Paths.get("/data/misc/adb/adb_keys"); + private void writeBytesToFile(byte[] keys, Path adbKeys) { try { OutputStream fileOutputStream = Files.newOutputStream(adbKeys); - fileOutputStream.write(persistentData.mAdbKeys); + fileOutputStream.write(keys); fileOutputStream.close(); Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(adbKeys); @@ -219,23 +234,22 @@ public class TestHarnessModeService extends SystemService { } private int handleEnable() { - Path adbKeys = Paths.get("/data/misc/adb/adb_keys"); - if (!Files.exists(adbKeys)) { + AdbManagerInternal adbManager = LocalServices.getService(AdbManagerInternal.class); + File adbKeys = adbManager.getAdbKeysFile(); + File adbTempKeys = adbManager.getAdbTempKeysFile(); + if (adbKeys == null && adbTempKeys == null) { // This should only be accessible on eng builds that haven't yet set up ADB keys getErrPrintWriter() .println("No ADB keys stored; not enabling test harness mode"); return 1; } - try (InputStream inputStream = Files.newInputStream(adbKeys)) { - long size = Files.size(adbKeys); - byte[] adbKeysBytes = new byte[(int) size]; - int numBytes = inputStream.read(adbKeysBytes); - if (numBytes != size) { - getErrPrintWriter().println("Failed to read all bytes of adb_keys"); - return 1; - } - PersistentData persistentData = new PersistentData(true, adbKeysBytes); + try { + byte[] adbKeysBytes = getBytesFromFile(adbKeys); + byte[] adbTempKeysBytes = getBytesFromFile(adbTempKeys); + + PersistentData persistentData = + new PersistentData(true, adbKeysBytes, adbTempKeysBytes); getPersistentDataBlock().setTestHarnessModeData(persistentData.toBytes()); } catch (IOException e) { Slog.e(TAG, "Failed to store ADB keys.", e); @@ -252,6 +266,22 @@ public class TestHarnessModeService extends SystemService { return 0; } + private byte[] getBytesFromFile(File file) throws IOException { + if (file == null || !file.exists()) { + return new byte[0]; + } + Path path = file.toPath(); + try (InputStream inputStream = Files.newInputStream(path)) { + int size = (int) Files.size(path); + byte[] bytes = new byte[size]; + int numBytes = inputStream.read(bytes); + if (numBytes != size) { + throw new IOException("Failed to read the whole file"); + } + return bytes; + } + } + @Override public void onHelp() { PrintWriter pw = getOutPrintWriter(); @@ -290,15 +320,17 @@ public class TestHarnessModeService extends SystemService { final int mVersion; final boolean mEnabled; final byte[] mAdbKeys; + final byte[] mAdbTempKeys; - PersistentData(boolean enabled, byte[] adbKeys) { - this(VERSION_1, enabled, adbKeys); + PersistentData(boolean enabled, byte[] adbKeys, byte[] adbTempKeys) { + this(VERSION_1, enabled, adbKeys, adbTempKeys); } - PersistentData(int version, boolean enabled, byte[] adbKeys) { + PersistentData(int version, boolean enabled, byte[] adbKeys, byte[] adbTempKeys) { this.mVersion = version; this.mEnabled = enabled; this.mAdbKeys = adbKeys; + this.mAdbTempKeys = adbTempKeys; } static PersistentData fromBytes(byte[] bytes) { @@ -309,7 +341,10 @@ public class TestHarnessModeService extends SystemService { int adbKeysLength = is.readInt(); byte[] adbKeys = new byte[adbKeysLength]; is.readFully(adbKeys); - return new PersistentData(version, enabled, adbKeys); + int adbTempKeysLength = is.readInt(); + byte[] adbTempKeys = new byte[adbTempKeysLength]; + is.readFully(adbTempKeys); + return new PersistentData(version, enabled, adbKeys, adbTempKeys); } catch (IOException e) { throw new RuntimeException(e); } @@ -323,6 +358,8 @@ public class TestHarnessModeService extends SystemService { dos.writeBoolean(mEnabled); dos.writeInt(mAdbKeys.length); dos.write(mAdbKeys); + dos.writeInt(mAdbTempKeys.length); + dos.write(mAdbTempKeys); dos.close(); return os.toByteArray(); } catch (IOException e) { diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java index 62421ac4fc76..f882fdee8c1f 100644 --- a/services/core/java/com/android/server/wm/ActivityDisplay.java +++ b/services/core/java/com/android/server/wm/ActivityDisplay.java @@ -40,6 +40,7 @@ import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY; import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE; import static com.android.server.am.ActivityDisplayProto.STACKS; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; +import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; @@ -575,7 +576,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> final ActivityStack stack = mStacks.get(stackNdx); final ActivityRecord resumedActivity = stack.getResumedActivity(); if (resumedActivity != null - && (!stack.shouldBeVisible(resuming) || !stack.isFocusable())) { + && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE + || !stack.isFocusable())) { if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack + " mResumedActivity=" + resumedActivity); someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming, diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index ef4064846381..0251efb872bc 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -75,12 +75,12 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; import static android.content.pm.ActivityInfo.isFixedOrientationPortrait; import static android.content.res.Configuration.EMPTY; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.content.res.Configuration.UI_MODE_TYPE_MASK; import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET; import static android.os.Build.VERSION_CODES.HONEYCOMB; @@ -109,6 +109,7 @@ import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; import static com.android.server.wm.ActivityStack.LAUNCH_TICK; import static com.android.server.wm.ActivityStack.LAUNCH_TICK_MSG; import static com.android.server.wm.ActivityStack.PAUSE_TIMEOUT_MSG; +import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.ActivityStack.STOP_TIMEOUT_MSG; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS; @@ -2054,8 +2055,10 @@ final class ActivityRecord extends ConfigurationContainer { * @param activeActivity the activity that is active or just completed pause action. We won't * resume if this activity is active. */ - private boolean shouldResumeActivity(ActivityRecord activeActivity) { - return shouldMakeActive(activeActivity) && isFocusable() && !isState(RESUMED); + @VisibleForTesting + boolean shouldResumeActivity(ActivityRecord activeActivity) { + return shouldMakeActive(activeActivity) && isFocusable() && !isState(RESUMED) + && getActivityStack().getVisibility(activeActivity) == STACK_VISIBILITY_VISIBLE; } /** @@ -2607,10 +2610,6 @@ final class ActivityRecord extends ConfigurationContainer { } } - int getRequestedOrientation() { - return getOrientation(); - } - void setRequestedOrientation(int requestedOrientation) { setOrientation(requestedOrientation, mayFreezeScreenLocked(app)); mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged( @@ -2638,7 +2637,7 @@ final class ActivityRecord extends ConfigurationContainer { int getOrientation() { if (mAppWindowToken == null) { - return SCREEN_ORIENTATION_UNSPECIFIED; + return info.screenOrientation; } return mAppWindowToken.getOrientationIgnoreVisibility(); @@ -2674,25 +2673,92 @@ final class ActivityRecord extends ConfigurationContainer { mLastReportedConfiguration.setConfiguration(global, override); } + /** + * Get the configuration orientation by the requested screen orientation + * ({@link ActivityInfo.ScreenOrientation}) of this activity. + * + * @return orientation in ({@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}, + * {@link #ORIENTATION_UNDEFINED}). + */ + int getRequestedConfigurationOrientation() { + final int screenOrientation = getOrientation(); + if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { + // NOSENSOR means the display's "natural" orientation, so return that. + final ActivityDisplay display = getDisplay(); + if (display != null && display.mDisplayContent != null) { + return display.mDisplayContent.getNaturalOrientation(); + } + } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { + // LOCKED means the activity's orientation remains unchanged, so return existing value. + return getConfiguration().orientation; + } else if (isFixedOrientationLandscape(screenOrientation)) { + return ORIENTATION_LANDSCAPE; + } else if (isFixedOrientationPortrait(screenOrientation)) { + return ORIENTATION_PORTRAIT; + } + return ORIENTATION_UNDEFINED; + } + + /** + * Indicates the activity will keep the bounds and screen configuration when it was first + * launched, no matter how its parent changes. + * + * @return {@code true} if this activity is declared as non-resizable and fixed orientation or + * aspect ratio. + */ + private boolean inSizeCompatMode() { + return !isResizeable() && (info.isFixedOrientation() || info.hasFixedAspectRatio()) + // The configuration of non-standard type should be enforced by system. + && isActivityTypeStandard() + && !mAtmService.mForceResizableActivities; + } + // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer. private void updateOverrideConfiguration() { + final boolean inSizeCompatMode = inSizeCompatMode(); + if (inSizeCompatMode) { + if (!matchParentBounds()) { + // The override configuration is set only once in size compatible mode. + return; + } + if (!hasProcess() && !isConfigurationCompatible(task.getConfiguration())) { + // Don't compute when launching in fullscreen and the fixed orientation is not the + // current orientation. It is more accurately to compute the override bounds from + // the updated configuration after the fixed orientation is applied. + return; + } + } + computeBounds(mTmpBounds); + if (inSizeCompatMode && mTmpBounds.isEmpty()) { + mTmpBounds.set(task.getWindowConfiguration().getBounds()); + } if (mTmpBounds.equals(getRequestedOverrideBounds())) { + // The bounds is not changed or the activity is resizable (both the 2 bounds are empty). return; } - setBounds(mTmpBounds); - - // Bounds changed...update configuration to match. - if (!matchParentBounds()) { - mTmpConfig.setTo(getRequestedOverrideConfiguration()); - task.computeConfigResourceOverrides(mTmpConfig, task.getParent().getConfiguration()); - } else { - mTmpConfig.unset(); + final Configuration overrideConfig = mTmpConfig; + overrideConfig.unset(); + if (!mTmpBounds.isEmpty()) { + overrideConfig.windowConfiguration.setBounds(mTmpBounds); + if (inSizeCompatMode) { + // Ensure the screen related fields are set. It is used to prevent activity relaunch + // when moving between displays. For screenWidthDp and screenWidthDp, because they + // are relative to bounds and density, they will be calculated in + // {@link TaskRecord#computeConfigResourceOverrides} and the result will also be + // relatively fixed. + final Configuration srcConfig = task.getConfiguration(); + overrideConfig.colorMode = srcConfig.colorMode; + overrideConfig.densityDpi = srcConfig.densityDpi; + overrideConfig.screenLayout = srcConfig.screenLayout; + // The smallest screen width is the short side of screen bounds. Because the bounds + // and density won't be changed, smallestScreenWidthDp is also fixed. + overrideConfig.smallestScreenWidthDp = srcConfig.smallestScreenWidthDp; + } } - - onRequestedOverrideConfigurationChanged(mTmpConfig); + onRequestedOverrideConfigurationChanged(overrideConfig); } @Override @@ -2704,6 +2770,86 @@ final class ActivityRecord extends ConfigurationContainer { // layout traversals. mConfigurationSeq = Math.max(++mConfigurationSeq, 1); getResolvedOverrideConfiguration().seq = mConfigurationSeq; + + if (matchParentBounds()) { + return; + } + + final Configuration resolvedConfig = getResolvedOverrideConfiguration(); + if (!inSizeCompatMode()) { + computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, + ORIENTATION_UNDEFINED, true /* insideParentBounds */); + return; + } + + final Configuration displayConfig = getDisplay().getConfiguration(); + int orientation = getConfiguration().orientation; + if (orientation != displayConfig.orientation && isConfigurationCompatible(displayConfig)) { + // The activity is compatible to apply the orientation change or it requests different + // fixed orientation. + orientation = displayConfig.orientation; + } else { + if (resolvedConfig.windowConfiguration.getAppBounds() != null) { + // Keep the computed resolved override configuration. + return; + } + final int requestedOrientation = getRequestedConfigurationOrientation(); + if (requestedOrientation != ORIENTATION_UNDEFINED) { + orientation = requestedOrientation; + } + } + + // Adjust the bounds to match the current orientation. + if (orientation != ORIENTATION_UNDEFINED) { + final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); + final int longSide = Math.max(resolvedBounds.height(), resolvedBounds.width()); + final int shortSide = Math.min(resolvedBounds.height(), resolvedBounds.width()); + final boolean toBeLandscape = orientation == ORIENTATION_LANDSCAPE; + final int width = toBeLandscape ? longSide : shortSide; + final int height = toBeLandscape ? shortSide : longSide; + // Assume the bounds is always started from zero because the size may be bigger than its + // parent (task ~ display). The actual letterboxing will be done by surface offset. + resolvedBounds.set(0, 0, width, height); + } + + // In size compatible mode, activity is allowed to have larger bounds than its parent. + computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, orientation, + false /* insideParentBounds */); + } + + private void computeConfigResourceOverrides(Configuration inOutConfig, + Configuration parentConfig, int orientation, boolean insideParentBounds) { + // Set the real orientation or undefined value to ensure the output orientation won't be the + // old value. Also reset app bounds so it will be updated according to bounds. + inOutConfig.orientation = orientation; + final Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); + if (outAppBounds != null) { + outAppBounds.setEmpty(); + } + + // TODO(b/112288258): Remove below calculation because the position information in bounds + // will be replaced by the offset of surface. + final Rect appBounds = parentConfig.windowConfiguration.getAppBounds(); + if (appBounds != null) { + final Rect outBounds = inOutConfig.windowConfiguration.getBounds(); + final int activityWidth = outBounds.width(); + final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId()); + if (navBarPosition == NAV_BAR_LEFT) { + // Position the activity frame on the opposite side of the nav bar. + outBounds.left = appBounds.right - activityWidth; + outBounds.right = appBounds.right; + } else if (navBarPosition == NAV_BAR_RIGHT) { + // Position the activity frame on the opposite side of the nav bar. + outBounds.left = 0; + outBounds.right = activityWidth + appBounds.left; + } else if (appBounds.width() > activityWidth) { + // Horizontally center the frame. + outBounds.left = appBounds.left + (appBounds.width() - activityWidth) / 2; + outBounds.right = outBounds.left + activityWidth; + } + } + + task.computeConfigResourceOverrides(inOutConfig, parentConfig, insideParentBounds); } @Override @@ -2736,8 +2882,7 @@ final class ActivityRecord extends ConfigurationContainer { /** Returns true if the configuration is compatible with this activity. */ boolean isConfigurationCompatible(Configuration config) { - final int orientation = mAppWindowToken != null - ? getOrientation() : info.screenOrientation; + final int orientation = getOrientation(); if (isFixedOrientationPortrait(orientation) && config.orientation != ORIENTATION_PORTRAIT) { return false; @@ -2819,21 +2964,6 @@ final class ActivityRecord extends ConfigurationContainer { // away later in StackWindowController.adjustConfigurationForBounds(). Otherwise, the app // bounds would end up too small. outBounds.set(0, 0, activityWidth + appBounds.left, activityHeight + appBounds.top); - - final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId()); - if (navBarPosition == NAV_BAR_LEFT) { - // Position the activity frame on the opposite side of the nav bar. - outBounds.left = appBounds.right - activityWidth; - outBounds.right = appBounds.right; - } else if (navBarPosition == NAV_BAR_RIGHT) { - // Position the activity frame on the opposite side of the nav bar. - outBounds.left = 0; - outBounds.right = activityWidth + appBounds.left; - } else { - // Horizontally center the frame. - outBounds.left = appBounds.left + (containingAppWidth - activityWidth) / 2; - outBounds.right = outBounds.left + activityWidth; - } } /** diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 6f07be82d267..932cfd3ae007 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -108,6 +108,7 @@ import static com.android.server.wm.RootActivityContainer.FindTaskResult; import static java.lang.Integer.MAX_VALUE; +import android.annotation.IntDef; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManagerInternal; @@ -223,6 +224,22 @@ class ActivityStack extends ConfigurationContainer { // How many activities have to be scheduled to stop to force a stop pass. private static final int MAX_STOPPING_TO_FORCE = 3; + @IntDef(prefix = {"STACK_VISIBILITY"}, value = { + STACK_VISIBILITY_VISIBLE, + STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, + STACK_VISIBILITY_INVISIBLE, + }) + @interface StackVisibility {} + + /** Stack is visible. No other stacks on top that fully or partially occlude it. */ + static final int STACK_VISIBILITY_VISIBLE = 0; + + /** Stack is partially occluded by other translucent stack(s) on top of it. */ + static final int STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT = 1; + + /** Stack is completely invisible. */ + static final int STACK_VISIBILITY_INVISIBLE = 2; + @Override protected int getChildCount() { return mTaskHistory.size(); @@ -1959,14 +1976,28 @@ class ActivityStack extends ConfigurationContainer { * @param starting The currently starting activity or null if there is none. */ boolean shouldBeVisible(ActivityRecord starting) { + return getVisibility(starting) != STACK_VISIBILITY_INVISIBLE; + } + + /** + * Returns true if the stack should be visible. + * + * @param starting The currently starting activity or null if there is none. + */ + @StackVisibility + int getVisibility(ActivityRecord starting) { if (!isAttached() || mForceHidden) { - return false; + return STACK_VISIBILITY_INVISIBLE; } final ActivityDisplay display = getDisplay(); boolean gotSplitScreenStack = false; boolean gotOpaqueSplitScreenPrimary = false; boolean gotOpaqueSplitScreenSecondary = false; + boolean gotTranslucentFullscreen = false; + boolean gotTranslucentSplitScreenPrimary = false; + boolean gotTranslucentSplitScreenSecondary = false; + boolean shouldBeVisible = true; final int windowingMode = getWindowingMode(); final boolean isAssistantType = isActivityTypeAssistant(); for (int i = display.getChildCount() - 1; i >= 0; --i) { @@ -1975,8 +2006,9 @@ class ActivityStack extends ConfigurationContainer { if (other == this) { // Should be visible if there is no other stack occluding it, unless it doesn't // have any running activities, not starting one and not home stack. - return hasRunningActivities || isInStackLocked(starting) != null + shouldBeVisible = hasRunningActivities || isInStackLocked(starting) != null || isActivityTypeHome(); + break; } if (!hasRunningActivities) { @@ -1996,51 +2028,79 @@ class ActivityStack extends ConfigurationContainer { if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { if (activityType == ACTIVITY_TYPE_HOME || (activityType == ACTIVITY_TYPE_ASSISTANT - && mWindowManager.getRecentsAnimationController() != null)) { - return true; + && mWindowManager.getRecentsAnimationController() != null)) { + break; } } if (other.isStackTranslucent(starting)) { // Can be visible behind a translucent fullscreen stack. + gotTranslucentFullscreen = true; continue; } - return false; + return STACK_VISIBILITY_INVISIBLE; } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !gotOpaqueSplitScreenPrimary) { gotSplitScreenStack = true; - gotOpaqueSplitScreenPrimary = - !other.isStackTranslucent(starting); + gotTranslucentSplitScreenPrimary = other.isStackTranslucent(starting); + gotOpaqueSplitScreenPrimary = !gotTranslucentSplitScreenPrimary; if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && gotOpaqueSplitScreenPrimary) { // Can not be visible behind another opaque stack in split-screen-primary mode. - return false; + return STACK_VISIBILITY_INVISIBLE; } } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY && !gotOpaqueSplitScreenSecondary) { gotSplitScreenStack = true; - gotOpaqueSplitScreenSecondary = - !other.isStackTranslucent(starting); + gotTranslucentSplitScreenSecondary = other.isStackTranslucent(starting); + gotOpaqueSplitScreenSecondary = !gotTranslucentSplitScreenSecondary; if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY && gotOpaqueSplitScreenSecondary) { // Can not be visible behind another opaque stack in split-screen-secondary mode. - return false; + return STACK_VISIBILITY_INVISIBLE; } } if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) { // Can not be visible if we are in split-screen windowing mode and both halves of // the screen are opaque. - return false; + return STACK_VISIBILITY_INVISIBLE; } if (isAssistantType && gotSplitScreenStack) { // Assistant stack can't be visible behind split-screen. In addition to this not // making sense, it also works around an issue here we boost the z-order of the // assistant window surfaces in window manager whenever it is visible. - return false; + return STACK_VISIBILITY_INVISIBLE; } } - // Well, nothing is stopping you from being visible... - return true; + if (!shouldBeVisible) { + return STACK_VISIBILITY_INVISIBLE; + } + + // Handle cases when there can be a translucent split-screen stack on top. + switch (windowingMode) { + case WINDOWING_MODE_FULLSCREEN: + if (gotTranslucentSplitScreenPrimary || gotTranslucentSplitScreenSecondary) { + // At least one of the split-screen stacks that covers this one is translucent. + return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; + } + break; + case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: + if (gotTranslucentSplitScreenPrimary) { + // Covered by translucent primary split-screen on top. + return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; + } + break; + case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: + if (gotTranslucentSplitScreenSecondary) { + // Covered by translucent secondary split-screen on top. + return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; + } + break; + } + + // Lastly - check if there is a translucent fullscreen stack on top. + return gotTranslucentFullscreen ? STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT + : STACK_VISIBILITY_VISIBLE; } final int rankTaskLayers(int baseLayer) { @@ -5571,6 +5631,19 @@ class ActivityStack extends ConfigurationContainer { } } + /** + * Get current bounds of this stack, return empty when it is unavailable. + * @see TaskStack#getAnimationOrCurrentBounds(Rect) + */ + void getAnimationOrCurrentBounds(Rect outBounds) { + final TaskStack stack = getTaskStack(); + if (stack == null) { + outBounds.setEmpty(); + return; + } + stack.getAnimationOrCurrentBounds(outBounds); + } + private boolean skipResizeAnimation(boolean toFullscreen) { if (!toFullscreen) { return false; diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 678a896bddbc..c33a2c179ab7 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -989,8 +989,8 @@ class ActivityStarter { if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) { return false; } - // don't abort if the callingPackage is a device owner - if (mService.getDevicePolicyManager().isDeviceOwnerApp(callingPackage)) { + // don't abort if the callingPackage is the device owner + if (mService.isDeviceOwner(callingPackage)) { return false; } // anything that has fallen through would currently be aborted diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 1a5e6a14e733..5a20959dcdbf 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -492,4 +492,9 @@ public abstract class ActivityTaskManagerInternal { /** Returns true if uid has a visible window or its process is in a top state. */ public abstract boolean isUidForeground(int uid); + + /** + * Called by DevicePolicyManagerService to set the package name of the device owner. + */ + public abstract void setDeviceOwnerPackageName(String deviceOwnerPkg); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 7aa34819692b..258819fdece9 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -151,7 +151,6 @@ import android.app.RemoteAction; import android.app.WaitResult; import android.app.WindowConfiguration; import android.app.admin.DevicePolicyCache; -import android.app.admin.DevicePolicyManager; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.app.usage.UsageStatsManagerInternal; @@ -363,7 +362,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { WindowManagerService mWindowManager; private UserManagerService mUserManager; private AppOpsService mAppOpsService; - private DevicePolicyManager mDpm; /** All active uids in the system. */ private final SparseArray<Integer> mActiveUids = new SparseArray<>(); private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>(); @@ -623,6 +621,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { private FontScaleSettingObserver mFontScaleSettingObserver; + private String mDeviceOwnerPackageName; + private final class FontScaleSettingObserver extends ContentObserver { private final Uri mFontScaleUri = Settings.System.getUriFor(FONT_SCALE); private final Uri mHideErrorDialogsUri = Settings.Global.getUriFor(HIDE_ERROR_DIALOGS); @@ -838,13 +838,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mAppOpsService; } - DevicePolicyManager getDevicePolicyManager() { - if (mDpm == null) { - mDpm = mContext.getSystemService(DevicePolicyManager.class); - } - return mDpm; - } - boolean hasUserRestriction(String restriction, int userId) { return getUserManager().hasUserRestriction(restriction, userId); } @@ -1383,6 +1376,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { .setProfilerInfo(profilerInfo) .setActivityOptions(bOptions) .setMayWait(userId) + .setAllowBackgroundActivityStart(true) .execute(); } @@ -1398,6 +1392,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { .setResolvedType(resolvedType) .setActivityOptions(bOptions) .setMayWait(userId) + .setAllowBackgroundActivityStart(true) .execute(); } @@ -1718,7 +1713,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (r == null) { return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } - return r.getRequestedOrientation(); + return r.getOrientation(); } } @@ -2450,6 +2445,40 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } + @Override + public void offsetPinnedStackBounds(int stackId, Rect compareBounds, int xOffset, int yOffset, + int animationDuration) { + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "offsetPinnedStackBounds()"); + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + if (xOffset == 0 && yOffset == 0) { + return; + } + final ActivityStack stack = mRootActivityContainer.getStack(stackId); + if (stack == null) { + Slog.w(TAG, "offsetPinnedStackBounds: stackId " + stackId + " not found."); + return; + } + if (stack.getWindowingMode() != WINDOWING_MODE_PINNED) { + throw new IllegalArgumentException("Stack: " + stackId + + " doesn't support animated resize."); + } + final Rect destBounds = new Rect(); + stack.getAnimationOrCurrentBounds(destBounds); + if (!destBounds.isEmpty() || !destBounds.equals(compareBounds)) { + Slog.w(TAG, "The current stack bounds does not matched! It may be obsolete."); + return; + } + destBounds.offset(xOffset, yOffset); + stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds, + animationDuration, false /* fromFullscreen */); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } /** * Moves the specified task to the primary-split-screen stack. * @@ -5689,6 +5718,17 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { || mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid); } + boolean isDeviceOwner(String packageName) { + if (packageName == null) { + return false; + } + return packageName.equals(mDeviceOwnerPackageName); + } + + void setDeviceOwnerPackageName(String deviceOwnerPkg) { + mDeviceOwnerPackageName = deviceOwnerPkg; + } + /** * @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on * the whitelist @@ -7106,5 +7146,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return ActivityTaskManagerService.this.isUidForeground(uid); } } + + @Override + public void setDeviceOwnerPackageName(String deviceOwnerPkg) { + synchronized (mGlobalLock) { + ActivityTaskManagerService.this.setDeviceOwnerPackageName(deviceOwnerPkg); + } + } } } diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java index 0e14e46e77de..5519729c17f5 100644 --- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java +++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java @@ -143,7 +143,7 @@ class AppWindowThumbnail implements Animatable { void destroy() { mSurfaceAnimator.cancelAnimation(); - mSurfaceControl.remove(); + getPendingTransaction().remove(mSurfaceControl); } /** diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 2cc85e2076e0..88c8b953a2e9 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -239,6 +239,17 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>(); ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>(); + /** + * The scale to fit at least one side of the activity to its parent. If the activity uses + * 1920x1080, and the actually size on the screen is 960x540, then the scale is 0.5. + */ + private float mSizeCompatScale = 1f; + /** + * The bounds in global coordinates for activity in size compatibility mode. + * @see ActivityRecord#inSizeCompatMode + */ + private Rect mSizeCompatBounds; + private boolean mDisablePreviewScreenshots; private Task mLastParent; @@ -884,6 +895,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree dc.setFocusedApp(null); mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); } + if (mLetterbox != null) { + mLetterbox.destroy(); + mLetterbox = null; + } if (!delayed) { updateReportedVisibilityLocked(); @@ -1275,7 +1290,19 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree void onDisplayChanged(DisplayContent dc) { DisplayContent prevDc = mDisplayContent; super.onDisplayChanged(dc); - if (prevDc != null && prevDc.mFocusedApp == this) { + if (prevDc == null) { + return; + } + if (prevDc.mChangingApps.contains(this)) { + // This gets called *after* the AppWindowToken has been reparented to the new display. + // That reparenting resulted in this window changing modes (eg. FREEFORM -> FULLSCREEN), + // so this token is now "frozen" while waiting for the animation to start on prevDc + // (which will be cancelled since the window is no-longer a child). However, since this + // is no longer a child of prevDc, this won't be notified of the cancelled animation, + // so we need to cancel the change transition here. + clearChangeLeash(getPendingTransaction(), true /* cancel */); + } + if (prevDc.mFocusedApp == this) { prevDc.setFocusedApp(null); final TaskStack stack = dc.getTopStack(); if (stack != null) { @@ -1285,6 +1312,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } } } + + if (prevDc != mDisplayContent && mLetterbox != null) { + mLetterbox.onMovedToDisplay(mDisplayContent.getDisplayId()); + } } /** @@ -1543,11 +1574,52 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return mOrientation; } + /** @return {@code true} if the compatibility bounds is taking effect. */ + boolean inSizeCompatMode() { + return mSizeCompatBounds != null; + } + + @Override + float getSizeCompatScale() { + return inSizeCompatMode() ? mSizeCompatScale : super.getSizeCompatScale(); + } + + /** + * @return Non-empty bounds if the activity has override bounds. + * @see ActivityRecord#resolveOverrideConfiguration(Configuration) + */ + Rect getResolvedOverrideBounds() { + // Get bounds from resolved override configuration because it is computed with orientation. + return getResolvedOverrideConfiguration().windowConfiguration.getBounds(); + } + @Override public void onConfigurationChanged(Configuration newParentConfig) { final int prevWinMode = getWindowingMode(); mTmpPrevBounds.set(getBounds()); super.onConfigurationChanged(newParentConfig); + + final Task task = getTask(); + final Rect overrideBounds = getResolvedOverrideBounds(); + if (task != null && !overrideBounds.isEmpty() + // If the changes come from change-listener, the incoming parent configuration is + // still the old one. Make sure their orientations are the same to reduce computing + // the compatibility bounds for the intermediate state. + && getResolvedOverrideConfiguration().orientation == newParentConfig.orientation) { + final Rect taskBounds = task.getBounds(); + // Since we only center the activity horizontally, if only the fixed height is smaller + // than its container, the override bounds don't need to take effect. + if ((overrideBounds.width() != taskBounds.width() + || overrideBounds.height() > taskBounds.height())) { + calculateCompatBoundsTransformation(newParentConfig); + updateSurfacePosition(); + } else if (mSizeCompatBounds != null) { + mSizeCompatBounds = null; + mSizeCompatScale = 1f; + updateSurfacePosition(); + } + } + final int winMode = getWindowingMode(); if (prevWinMode == winMode) { @@ -1584,7 +1656,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) { - if (!isVisible() || getDisplayContent().mAppTransition.isTransitionSet()) { + if (mWmService.mDisableTransitionAnimation + || !isVisible() + || getDisplayContent().mAppTransition.isTransitionSet() + || getSurfaceControl() == null) { return false; } // Only do an animation into and out-of freeform mode for now. Other mode @@ -1642,8 +1717,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree final ActivityManager.TaskSnapshot snapshot = snapshotCtrl.getSnapshot( getTask().mTaskId, getTask().mUserId, false /* restoreFromDisk */, false /* reducedResolution */); - mThumbnail = new AppWindowThumbnail(t, this, snapshot.getSnapshot(), - true /* relative */); + if (snapshot != null) { + mThumbnail = new AppWindowThumbnail(t, this, snapshot.getSnapshot(), + true /* relative */); + } } } @@ -1656,6 +1733,54 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return mThumbnail; } + /** + * Calculates the scale and offset to horizontal center the size compatibility bounds into the + * region which is available to application. + */ + private void calculateCompatBoundsTransformation(Configuration newParentConfig) { + final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds(); + final Rect viewportBounds = parentAppBounds != null + ? parentAppBounds : newParentConfig.windowConfiguration.getBounds(); + final Rect contentBounds = getResolvedOverrideBounds(); + final float contentW = contentBounds.width(); + final float contentH = contentBounds.height(); + final float viewportW = viewportBounds.width(); + final float viewportH = viewportBounds.height(); + // Only allow to scale down. + mSizeCompatScale = (contentW <= viewportW && contentH <= viewportH) + ? 1 : Math.min(viewportW / contentW, viewportH / contentH); + final int offsetX = (int) ((viewportW - contentW * mSizeCompatScale + 1) * 0.5f) + + viewportBounds.left; + + if (mSizeCompatBounds == null) { + mSizeCompatBounds = new Rect(); + } + mSizeCompatBounds.set(contentBounds); + mSizeCompatBounds.offsetTo(0, 0); + mSizeCompatBounds.scale(mSizeCompatScale); + mSizeCompatBounds.left += offsetX; + mSizeCompatBounds.right += offsetX; + } + + @Override + public Rect getBounds() { + if (mSizeCompatBounds != null) { + return mSizeCompatBounds; + } + return super.getBounds(); + } + + @Override + public boolean matchParentBounds() { + if (super.matchParentBounds()) { + return true; + } + // An activity in size compatibility mode may have override bounds which equals to its + // parent bounds, so the exact bounds should also be checked. + final WindowContainer parent = getParent(); + return parent == null || parent.getBounds().equals(getResolvedOverrideBounds()); + } + @Override void checkAppWindowsReadyToShow() { if (allDrawn == mLastAllDrawn) { @@ -1829,6 +1954,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (needsLetterbox) { if (mLetterbox == null) { mLetterbox = new Letterbox(() -> makeChildSurface(null)); + mLetterbox.attachInput(w); } getPosition(mTmpPoint); mLetterbox.layout(getParent().getBounds(), w.getFrameLw(), mTmpPoint); @@ -2561,9 +2687,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return; } else if (mTransitChangeLeash != null) { // unparent mTransitChangeLeash for clean-up - t.hide(mTransitChangeLeash); - t.reparent(mTransitChangeLeash, null); - mTransitChangeLeash = null; + clearChangeLeash(t, false /* cancel */); } if (mAnimatingAppWindowTokenRegistry != null) { @@ -2659,15 +2783,36 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return super.isSelfAnimating(); } + /** + * @param cancel {@code true} if clearing the leash due to cancelling instead of transferring + * to another leash. + */ + private void clearChangeLeash(Transaction t, boolean cancel) { + if (mTransitChangeLeash == null) { + return; + } + if (cancel) { + clearThumbnail(); + SurfaceControl sc = getSurfaceControl(); + SurfaceControl parentSc = getParentSurfaceControl(); + // Don't reparent if surface is getting destroyed + if (parentSc != null && sc != null) { + t.reparent(sc, getParentSurfaceControl()); + } + } + t.hide(mTransitChangeLeash); + t.reparent(mTransitChangeLeash, null); + mTransitChangeLeash = null; + if (cancel) { + onAnimationLeashDestroyed(t); + } + } + @Override void cancelAnimation() { cancelAnimationOnly(); clearThumbnail(); - if (mTransitChangeLeash != null) { - getPendingTransaction().hide(mTransitChangeLeash); - getPendingTransaction().reparent(mTransitChangeLeash, null); - mTransitChangeLeash = null; - } + clearChangeLeash(getPendingTransaction(), true /* cancel */); } /** @@ -2830,6 +2975,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (mPendingRelaunchCount != 0) { pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount); } + if (mSizeCompatScale != 1f || mSizeCompatBounds != null) { + pw.println(prefix + "mSizeCompatScale=" + mSizeCompatScale + " mSizeCompatBounds=" + + mSizeCompatBounds); + } if (mRemovingFromDisplay) { pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay); } @@ -3003,7 +3152,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree void removeFromPendingTransition() { if (isWaitingForTransitionStart() && mDisplayContent != null) { mDisplayContent.mOpeningApps.remove(this); - mDisplayContent.mChangingApps.remove(this); + if (mDisplayContent.mChangingApps.remove(this)) { + clearChangeLeash(getPendingTransaction(), true /* cancel */); + } mDisplayContent.mClosingApps.remove(this); } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 928b57cf050b..5cfc20b6339f 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -23,7 +23,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -38,6 +37,7 @@ import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import static android.view.View.GONE; +import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.WindowManager.DOCKED_BOTTOM; import static android.view.WindowManager.DOCKED_INVALID; import static android.view.WindowManager.DOCKED_TOP; @@ -138,6 +138,7 @@ import android.content.pm.PackageManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; @@ -172,6 +173,7 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.SurfaceSession; import android.view.View; +import android.view.ViewRootImpl; import android.view.WindowManager; import android.view.WindowManagerPolicyConstants.PointerEventListener; @@ -3251,6 +3253,36 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mInputMethodTargetWaitingAnim = targetWaitingAnim; assignWindowLayers(false /* setLayoutNeeded */); mInsetsStateController.onImeTargetChanged(target); + updateImeParent(); + } + + private void updateImeParent() { + if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE) { + return; + } + final SurfaceControl newParent = computeImeParent(); + if (newParent != null) { + mPendingTransaction.reparent(mImeWindowsContainers.mSurfaceControl, newParent); + scheduleAnimation(); + } + } + + /** + * Computes the window the IME should be attached to. + */ + @VisibleForTesting + SurfaceControl computeImeParent() { + + // Attach it to app if the target is part of an app and such app is covering the entire + // screen. If it's not covering the entire screen the IME might extend beyond the apps + // bounds. + if (mInputMethodTarget != null && mInputMethodTarget.mAppToken != null && + mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) { + return mInputMethodTarget.mAppToken.getSurfaceControl(); + } + + // Otherwise, we just attach it to the display. + return mWindowingLayer; } boolean getNeedsMenu(WindowState top, WindowManagerPolicy.WindowState bottom) { @@ -4885,6 +4917,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo .reparent(mWindowingLayer, sc).reparent(mOverlayLayer, sc); } + @VisibleForTesting + SurfaceControl getWindowingLayer() { + return mWindowingLayer; + } + /** * Create a portal window handle for input. This window transports any touch to the display * indicated by {@link InputWindowHandle#portalToDisplayId} if the touch hits this window. @@ -4909,4 +4946,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo portalWindowHandle.portalToDisplayId = mDisplayId; return portalWindowHandle; } + + /** + * @see IWindowManager#setForwardedInsets + */ + public void setForwardedInsets(Insets insets) { + if (insets == null) { + insets = Insets.NONE; + } + if (mDisplayPolicy.getForwardedInsets().equals(insets)) { + return; + } + mDisplayPolicy.setForwardedInsets(insets); + setLayoutNeeded(); + mWmService.mWindowPlacerLocked.requestTraversal(); + } } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index bbf115f17969..2ee30ac5c8ff 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -27,6 +27,7 @@ import static android.content.res.Configuration.UI_MODE_TYPE_CAR; import static android.content.res.Configuration.UI_MODE_TYPE_MASK; import static android.view.InsetsState.TYPE_TOP_BAR; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW; @@ -103,6 +104,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.localLOGV; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityThread; @@ -110,6 +112,7 @@ import android.app.StatusBarManager; import android.content.Context; import android.content.Intent; import android.content.res.Resources; +import android.graphics.Insets; import android.graphics.Rect; import android.hardware.input.InputManager; import android.hardware.power.V1_0.PowerHint; @@ -134,6 +137,7 @@ import android.view.MotionEvent; import android.view.PointerIcon; import android.view.Surface; import android.view.View; +import android.view.ViewRootImpl; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.view.WindowManagerGlobal; @@ -339,6 +343,16 @@ public class DisplayPolicy { private InputConsumer mInputConsumer = null; + /** + * The area covered by system windows which belong to another display. Forwarded insets is set + * in case this is a virtual display, this is displayed on another display that has insets, and + * the bounds of this display is overlapping with the insets of the host display (e.g. IME is + * displayed on the host display, and it covers a part of this virtual display.) + * The forwarded insets is used to compute display frames of this virtual display, which will + * be then used to layout windows in the virtual display. + */ + @NonNull private Insets mForwardedInsets = Insets.NONE; + // -------- PolicyHandler -------- private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1; private static final int MSG_REQUEST_TRANSIENT_BARS = 2; @@ -1362,6 +1376,15 @@ public class DisplayPolicy { displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top, displayFrames.mStable.top); } + + // In case this is a virtual display, and the host display has insets that overlap this + // virtual display, apply the insets of the overlapped area onto the current and content + // frame of this virtual display. This let us layout windows in the virtual display as + // expected when the window needs to avoid overlap with the system windows. + // TODO: Generalize the forwarded insets, so that we can handle system windows other than + // IME. + displayFrames.mCurrent.inset(mForwardedInsets); + displayFrames.mContent.inset(mForwardedInsets); } private void layoutScreenDecorWindows(DisplayFrames displayFrames) { @@ -1900,7 +1923,10 @@ public class DisplayPolicy { if (win.isVoiceInteraction()) { cf.set(displayFrames.mVoiceContent); } else { - if (adjust != SOFT_INPUT_ADJUST_RESIZE) { + // IME Insets are handled on the client for ADJUST_RESIZE in the new + // insets world + if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE + || adjust != SOFT_INPUT_ADJUST_RESIZE) { cf.set(displayFrames.mDock); } else { cf.set(displayFrames.mContent); @@ -1991,7 +2017,11 @@ public class DisplayPolicy { of.set(displayFrames.mRestricted); df.set(displayFrames.mRestricted); pf.set(displayFrames.mRestricted); - if (adjust != SOFT_INPUT_ADJUST_RESIZE) { + + // IME Insets are handled on the client for ADJUST_RESIZE in the new insets + // world + if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE + || adjust != SOFT_INPUT_ADJUST_RESIZE) { cf.set(displayFrames.mDock); } else { cf.set(displayFrames.mContent); @@ -2718,6 +2748,18 @@ public class DisplayPolicy { } } + /** + * @see IWindowManager#setForwardedInsets + */ + public void setForwardedInsets(@NonNull Insets forwardedInsets) { + mForwardedInsets = forwardedInsets; + } + + @NonNull + public Insets getForwardedInsets() { + return mForwardedInsets; + } + @NavigationBarPosition int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) { if (navigationBarCanMove() && displayWidth > displayHeight) { diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index afae9c4ac228..a1b52f424fee 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -112,6 +112,7 @@ class InsetsStateController { * Called when a layout pass has occurred. */ void onPostLayout() { + mState.setDisplayFrame(mDisplayContent.getBounds()); for (int i = mControllers.size() - 1; i>= 0; i--) { mControllers.valueAt(i).onPostLayout(); } diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index 987492024546..d67193ea9e69 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -20,7 +20,15 @@ import static android.view.SurfaceControl.HIDDEN; import android.graphics.Point; import android.graphics.Rect; +import android.os.Binder; +import android.os.Process; +import android.view.InputChannel; +import android.view.InputEventReceiver; +import android.view.InputWindowHandle; import android.view.SurfaceControl; +import android.view.WindowManager; + +import com.android.server.UiThread; import java.util.function.Supplier; @@ -40,6 +48,7 @@ public class Letterbox { private final LetterboxSurface mLeft = new LetterboxSurface("left"); private final LetterboxSurface mBottom = new LetterboxSurface("bottom"); private final LetterboxSurface mRight = new LetterboxSurface("right"); + private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom }; /** * Constructs a Letterbox. @@ -87,8 +96,12 @@ public class Letterbox { * Returns true if any part of the letterbox overlaps with the given {@code rect}. */ public boolean isOverlappingWith(Rect rect) { - return mTop.isOverlappingWith(rect) || mLeft.isOverlappingWith(rect) - || mBottom.isOverlappingWith(rect) || mRight.isOverlappingWith(rect); + for (LetterboxSurface surface : mSurfaces) { + if (surface.isOverlappingWith(rect)) { + return true; + } + } + return false; } /** @@ -107,25 +120,94 @@ public class Letterbox { mOuter.setEmpty(); mInner.setEmpty(); - mTop.remove(); - mLeft.remove(); - mBottom.remove(); - mRight.remove(); + for (LetterboxSurface surface : mSurfaces) { + surface.remove(); + } } /** Returns whether a call to {@link #applySurfaceChanges} would change the surface. */ public boolean needsApplySurfaceChanges() { - return mTop.needsApplySurfaceChanges() - || mLeft.needsApplySurfaceChanges() - || mBottom.needsApplySurfaceChanges() - || mRight.needsApplySurfaceChanges(); + for (LetterboxSurface surface : mSurfaces) { + if (surface.needsApplySurfaceChanges()) { + return true; + } + } + return false; } public void applySurfaceChanges(SurfaceControl.Transaction t) { - mTop.applySurfaceChanges(t); - mLeft.applySurfaceChanges(t); - mBottom.applySurfaceChanges(t); - mRight.applySurfaceChanges(t); + for (LetterboxSurface surface : mSurfaces) { + surface.applySurfaceChanges(t); + } + } + + /** Enables touches to slide into other neighboring surfaces. */ + void attachInput(WindowState win) { + for (LetterboxSurface surface : mSurfaces) { + surface.attachInput(win); + } + } + + void onMovedToDisplay(int displayId) { + for (LetterboxSurface surface : mSurfaces) { + if (surface.mInputInterceptor != null) { + surface.mInputInterceptor.mWindowHandle.displayId = displayId; + } + } + } + + private static class InputInterceptor { + final InputChannel mServerChannel; + final InputChannel mClientChannel; + final InputWindowHandle mWindowHandle; + final InputEventReceiver mInputEventReceiver; + final WindowManagerService mWmService; + + InputInterceptor(String namePrefix, WindowState win) { + mWmService = win.mWmService; + final String name = namePrefix + (win.mAppToken != null ? win.mAppToken : win); + final InputChannel[] channels = InputChannel.openInputChannelPair(name); + mServerChannel = channels[0]; + mClientChannel = channels[1]; + mInputEventReceiver = new SimpleInputReceiver(mClientChannel); + + final Binder token = new Binder(); + mWmService.mInputManager.registerInputChannel(mServerChannel, token); + + mWindowHandle = new InputWindowHandle(null /* inputApplicationHandle */, + null /* clientWindow */, win.getDisplayId()); + mWindowHandle.name = name; + mWindowHandle.token = token; + mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH + | WindowManager.LayoutParams.FLAG_SLIPPERY; + mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER; + mWindowHandle.dispatchingTimeoutNanos = + WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; + mWindowHandle.visible = true; + mWindowHandle.ownerPid = Process.myPid(); + mWindowHandle.ownerUid = Process.myUid(); + mWindowHandle.scaleFactor = 1.0f; + } + + void updateTouchableRegion(Rect frame) { + mWindowHandle.touchableRegion.set(frame); + mWindowHandle.touchableRegion.translate(-frame.left, -frame.top); + } + + void dispose() { + mWmService.mInputManager.unregisterInputChannel(mServerChannel); + mInputEventReceiver.dispose(); + mServerChannel.dispose(); + mClientChannel.dispose(); + } + + private static class SimpleInputReceiver extends InputEventReceiver { + SimpleInputReceiver(InputChannel inputChannel) { + super(inputChannel, UiThread.getHandler().getLooper()); + } + } } private class LetterboxSurface { @@ -137,6 +219,8 @@ public class Letterbox { private final Rect mLayoutFrameGlobal = new Rect(); private final Rect mLayoutFrameRelative = new Rect(); + private InputInterceptor mInputInterceptor; + public LetterboxSurface(String type) { mType = type; } @@ -154,11 +238,22 @@ public class Letterbox { mSurface.setColor(new float[]{0, 0, 0}); } + void attachInput(WindowState win) { + if (mInputInterceptor != null) { + mInputInterceptor.dispose(); + } + mInputInterceptor = new InputInterceptor("Letterbox_" + mType + "_", win); + } + public void remove() { if (mSurface != null) { mSurface.remove(); mSurface = null; } + if (mInputInterceptor != null) { + mInputInterceptor.dispose(); + mInputInterceptor = null; + } } public int getWidth() { @@ -193,6 +288,10 @@ public class Letterbox { t.setPosition(mSurface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top); t.setWindowCrop(mSurface, mSurfaceFrameRelative.width(), mSurfaceFrameRelative.height()); + if (mInputInterceptor != null) { + mInputInterceptor.updateTouchableRegion(mSurfaceFrameRelative); + t.setInputWindowInfo(mSurface, mInputInterceptor.mWindowHandle); + } t.show(mSurface); } else if (mSurface != null) { t.hide(mSurface); diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 5ea24518370b..35b8641371be 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -251,7 +251,7 @@ class SurfaceAnimator { if (DEBUG_ANIM) Slog.i(TAG, "Cancelling animation restarting=" + restarting); final SurfaceControl leash = mLeash; final AnimationAdapter animation = mAnimation; - reset(t, forwardCancel); + reset(t, false); if (animation != null) { if (!mAnimationStartDelayed && forwardCancel) { animation.onAnimationCancelled(leash); @@ -260,6 +260,12 @@ class SurfaceAnimator { mAnimationFinishedCallback.run(); } } + + if (forwardCancel && leash != null) { + t.remove(leash); + mService.scheduleAnimationLocked(); + } + if (!restarting) { mAnimationStartDelayed = false; } diff --git a/services/core/java/com/android/server/wm/TEST_MAPPING b/services/core/java/com/android/server/wm/TEST_MAPPING index bbe542458b87..b2e8bbe3b885 100644 --- a/services/core/java/com/android/server/wm/TEST_MAPPING +++ b/services/core/java/com/android/server/wm/TEST_MAPPING @@ -1,34 +1,4 @@ { - "presubmit": [ - { - "name": "FrameworksServicesTests", - "options": [ - { - "include-filter": "com.android.server.wm." - }, - { - "include-annotation": "android.platform.test.annotations.Presubmit" - }, - { - "exclude-annotation": "androidx.test.filters.FlakyTest" - } - ] - }, - { - "name": "WmTests", - "options": [ - { - "include-filter": "com.android.server.wm." - }, - { - "include-annotation": "android.platform.test.annotations.Presubmit" - }, - { - "exclude-annotation": "androidx.test.filters.FlakyTest" - } - ] - } - ], "postsubmit": [ { "name": "CtsWindowManagerDeviceTestCases" diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index 69f0012b69ba..59d7560fc5b0 100644 --- a/services/core/java/com/android/server/wm/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -119,6 +119,7 @@ import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Slog; import android.util.proto.ProtoOutputStream; +import android.view.Display; import android.view.DisplayInfo; import com.android.internal.annotations.VisibleForTesting; @@ -1288,22 +1289,7 @@ class TaskRecord extends ConfigurationContainer { || top == null) { return getRequestedOverrideConfiguration().orientation; } - int screenOrientation = top.getOrientation(); - if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { - // NOSENSOR means the display's "natural" orientation, so return that. - ActivityDisplay display = mStack != null ? mStack.getDisplay() : null; - if (display != null && display.mDisplayContent != null) { - return mStack.getDisplay().mDisplayContent.getNaturalOrientation(); - } - } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { - // LOCKED means the activity's orientation remains unchanged, so return existing value. - return top.getConfiguration().orientation; - } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) { - return ORIENTATION_LANDSCAPE; - } else if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) { - return ORIENTATION_PORTRAIT; - } - return ORIENTATION_UNDEFINED; + return top.getRequestedConfigurationOrientation(); } /** @@ -2084,6 +2070,11 @@ class TaskRecord extends ConfigurationContainer { return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; } + void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, + @NonNull Configuration parentConfig) { + computeConfigResourceOverrides(inOutConfig, parentConfig, true /* insideParentBounds */); + } + /** * Calculates configuration values used by the client to get resources. This should be run * using app-facing bounds (bounds unmodified by animations or transient interactions). @@ -2093,7 +2084,7 @@ class TaskRecord extends ConfigurationContainer { * just be inherited from the parent configuration. **/ void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, - @NonNull Configuration parentConfig) { + @NonNull Configuration parentConfig, boolean insideParentBounds) { int windowingMode = inOutConfig.windowConfiguration.getWindowingMode(); if (windowingMode == WINDOWING_MODE_UNDEFINED) { windowingMode = parentConfig.windowConfiguration.getWindowingMode(); @@ -2111,7 +2102,7 @@ class TaskRecord extends ConfigurationContainer { inOutConfig.windowConfiguration.setAppBounds(bounds); outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); } - if (windowingMode != WINDOWING_MODE_FREEFORM) { + if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) { final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds(); if (parentAppBounds != null && !parentAppBounds.isEmpty()) { outAppBounds.intersect(parentAppBounds); @@ -2120,7 +2111,7 @@ class TaskRecord extends ConfigurationContainer { if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { - if (mStack != null) { + if (insideParentBounds && mStack != null) { final DisplayInfo di = new DisplayInfo(); mStack.getDisplay().mDisplay.getDisplayInfo(di); @@ -2135,12 +2126,16 @@ class TaskRecord extends ConfigurationContainer { } if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) { - inOutConfig.screenWidthDp = Math.min((int) (mTmpStableBounds.width() / density), - parentConfig.screenWidthDp); + final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density); + inOutConfig.screenWidthDp = insideParentBounds + ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp) + : overrideScreenWidthDp; } if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { - inOutConfig.screenHeightDp = Math.min((int) (mTmpStableBounds.height() / density), - parentConfig.screenHeightDp); + final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density); + inOutConfig.screenHeightDp = insideParentBounds + ? Math.min(overrideScreenHeightDp, parentConfig.screenWidthDp) + : overrideScreenHeightDp; } if (inOutConfig.smallestScreenWidthDp @@ -2162,7 +2157,7 @@ class TaskRecord extends ConfigurationContainer { if (inOutConfig.orientation == ORIENTATION_UNDEFINED) { inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp) - ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; + ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; } if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) { // For calculating screen layout, we need to use the non-decor inset screen area for the @@ -2332,6 +2327,7 @@ class TaskRecord extends ConfigurationContainer { info.userId = userId; info.stackId = getStackId(); info.taskId = taskId; + info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId; info.isRunning = getTopActivity() != null; info.baseIntent = new Intent(getBaseIntent()); info.baseActivity = reuseActivitiesReport.base != null diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 3bb660825843..c747c6d95fcd 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -47,7 +47,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; @@ -134,6 +133,7 @@ import android.content.pm.PackageManagerInternal; import android.content.res.Configuration; import android.database.ContentObserver; import android.graphics.Bitmap; +import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Point; import android.graphics.Rect; @@ -187,6 +187,7 @@ import android.util.SparseBooleanArray; import android.util.TimeUtils; import android.util.TypedValue; import android.util.proto.ProtoOutputStream; +import android.view.Choreographer; import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayInfo; @@ -842,7 +843,7 @@ public class WindowManagerService extends IWindowManager.Stub Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "closeSurfaceTransaction"); synchronized (mGlobalLock) { SurfaceControl.closeTransaction(); - traceStateLocked(where); + mWindowTracing.logState(where); } } finally { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); @@ -966,7 +967,8 @@ public class WindowManagerService extends IWindowManager.Stub mWindowPlacerLocked = new WindowSurfacePlacer(this); mTaskSnapshotController = new TaskSnapshotController(this); - mWindowTracing = WindowTracing.createDefaultAndStartLooper(context); + mWindowTracing = WindowTracing.createDefaultAndStartLooper(this, + Choreographer.getInstance()); LocalServices.addService(WindowManagerPolicy.class, mPolicy); @@ -1836,6 +1838,9 @@ public class WindowManagerService extends IWindowManager.Stub return; } outDisplayFrame.set(win.getDisplayFrameLw()); + if (win.inSizeCompatMode()) { + outDisplayFrame.scale(win.mInvGlobalScale); + } } } @@ -1960,8 +1965,6 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Relayout " + win + ": viewVisibility=" + viewVisibility + " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs); winAnimator.mSurfaceDestroyDeferred = (flags & RELAYOUT_DEFER_SURFACE_DESTROY) != 0; - win.mEnforceSizeCompat = - (win.mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0; if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) { winAnimator.mAlpha = attrs.alpha; } @@ -5764,17 +5767,6 @@ public class WindowManagerService extends IWindowManager.Stub proto.write(LAST_ORIENTATION, defaultDisplayContent.getLastOrientation()); } - void traceStateLocked(String where) { - Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "traceStateLocked"); - try { - mWindowTracing.traceStateLocked(where, this); - } catch (Exception e) { - Log.wtf(TAG, "Exception while tracing state", e); - } finally { - Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - } - } - private void dumpWindowsLocked(PrintWriter pw, boolean dumpAll, ArrayList<WindowState> windows) { pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)"); @@ -6438,6 +6430,23 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public void setForwardedInsets(int displayId, Insets insets) throws RemoteException { + synchronized (mGlobalLock) { + final DisplayContent dc = mRoot.getDisplayContent(displayId); + if (dc == null) { + return; + } + final int callingUid = Binder.getCallingUid(); + final int displayOwnerUid = dc.getDisplay().getOwnerUid(); + if (callingUid != displayOwnerUid) { + throw new SecurityException( + "Only owner of the display can set ForwardedInsets to it."); + } + dc.setForwardedInsets(insets); + } + } + void intersectDisplayInsetBounds(Rect display, Rect insets, Rect inOutBounds) { mTmpRect3.set(display); mTmpRect3.inset(insets); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 85b251a99f83..48cd6b68c416 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -246,7 +246,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final boolean mIsWallpaper; private final boolean mIsFloatingLayer; int mSeq; - boolean mEnforceSizeCompat; int mViewVisibility; int mSystemUiVisibility; /** @@ -505,7 +504,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ private PowerManager.WakeLock mDrawLock; - final private Rect mTmpRect = new Rect(); + private final Rect mTmpRect = new Rect(); + private final Point mTmpPoint = new Point(); /** * Whether the window was resized by us while it was gone for layout. @@ -655,7 +655,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mContext = mWmService.mContext; DeathRecipient deathRecipient = new DeathRecipient(); mSeq = seq; - mEnforceSizeCompat = (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0; mPowerManagerWrapper = powerManagerWrapper; mForceSeamlesslyRotate = token.mRoundedCornerOverlay; if (localLOGV) Slog.v( @@ -733,6 +732,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } /** + * @return {@code true} if the application runs in size compatibility mode. + * @see android.content.res.CompatibilityInfo#supportsScreen + * @see ActivityRecord#inSizeCompatMode + */ + boolean inSizeCompatMode() { + return (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0 + || (mAppToken != null && mAppToken.inSizeCompatMode() + // Exclude starting window because it is not displayed by the application. + && mAttrs.type != TYPE_APPLICATION_STARTING); + } + + /** * Returns whether this {@link WindowState} has been considered for drawing by its parent. */ boolean getDrawnStateEvaluated() { @@ -995,7 +1006,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mWindowFrames.offsetFrames(-layoutXDiff, -layoutYDiff); mWindowFrames.mCompatFrame.set(mWindowFrames.mFrame); - if (mEnforceSizeCompat) { + if (inSizeCompatMode()) { // If there is a size compatibility scale being applied to the // window, we need to apply this to its insets so that they are // reported to the app in its coordinate space. @@ -1354,8 +1365,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } void prelayout() { - if (mEnforceSizeCompat) { - mGlobalScale = getDisplayContent().mCompatibleScreenScale; + if (inSizeCompatMode()) { + mGlobalScale = mToken.getSizeCompatScale(); mInvGlobalScale = 1 / mGlobalScale; } else { mGlobalScale = mInvGlobalScale = 1; @@ -2145,6 +2156,30 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP int getSurfaceTouchableRegion(Region region, int flags) { final boolean modal = (flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0; + if (mAppToken != null && !mAppToken.getResolvedOverrideBounds().isEmpty()) { + // There may have touchable letterboxes around the activity, so in order to let the + // letterboxes are able to receive touch event and slip to activity, the activity with + // compatibility bounds cannot occupy full screen touchable region. + if (modal) { + // A modal window uses the whole compatibility bounds. + flags |= FLAG_NOT_TOUCH_MODAL; + mTmpRect.set(mAppToken.getResolvedOverrideBounds()); + // TODO(b/112288258): Remove the forced offset when the override bounds always + // starts from zero (See {@link ActivityRecord#resolveOverrideConfiguration}). + mTmpRect.offsetTo(0, 0); + } else { + // Non-modal uses the application based frame. + mTmpRect.set(mWindowFrames.mCompatFrame); + } + // The offset of compatibility bounds is applied to surface of {@link #AppWindowToken} + // and frame, so it is unnecessary to translate twice in surface based coordinates. + final int surfaceOffsetX = mAppToken.inSizeCompatMode() + ? mAppToken.getBounds().left : 0; + mTmpRect.offset(surfaceOffsetX - mWindowFrames.mFrame.left, -mWindowFrames.mFrame.top); + region.set(mTmpRect); + return flags; + } + if (modal && mAppToken != null) { // Limit the outer touch to the activity stack region. flags |= FLAG_NOT_TOUCH_MODAL; @@ -2943,7 +2978,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == DRAW_PENDING) Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING"); - final Rect frame = mWindowFrames.mFrame; + final Rect frame = mWindowFrames.mCompatFrame; final Rect overscanInsets = mWindowFrames.mLastOverscanInsets; final Rect contentInsets = mWindowFrames.mLastContentInsets; final Rect visibleInsets = mWindowFrames.mLastVisibleInsets; @@ -3353,7 +3388,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP pw.println(prefix + "mHasSurface=" + mHasSurface + " isReadyForDisplay()=" + isReadyForDisplay() + " mWindowRemovalAllowed=" + mWindowRemovalAllowed); - if (mEnforceSizeCompat) { + if (inSizeCompatMode()) { pw.println(prefix + "mCompatFrame=" + mWindowFrames.mCompatFrame.toShortString(sTmpSB)); } if (dumpAll) { @@ -3477,17 +3512,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP float x, y; int w,h; + final boolean inSizeCompatMode = inSizeCompatMode(); if ((mAttrs.flags & FLAG_SCALED) != 0) { if (mAttrs.width < 0) { w = pw; - } else if (mEnforceSizeCompat) { + } else if (inSizeCompatMode) { w = (int)(mAttrs.width * mGlobalScale + .5f); } else { w = mAttrs.width; } if (mAttrs.height < 0) { h = ph; - } else if (mEnforceSizeCompat) { + } else if (inSizeCompatMode) { h = (int)(mAttrs.height * mGlobalScale + .5f); } else { h = mAttrs.height; @@ -3495,21 +3531,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } else { if (mAttrs.width == MATCH_PARENT) { w = pw; - } else if (mEnforceSizeCompat) { + } else if (inSizeCompatMode) { w = (int)(mRequestedWidth * mGlobalScale + .5f); } else { w = mRequestedWidth; } if (mAttrs.height == MATCH_PARENT) { h = ph; - } else if (mEnforceSizeCompat) { + } else if (inSizeCompatMode) { h = (int)(mRequestedHeight * mGlobalScale + .5f); } else { h = mRequestedHeight; } } - if (mEnforceSizeCompat) { + if (inSizeCompatMode) { x = mAttrs.x * mGlobalScale; y = mAttrs.y * mGlobalScale; } else { @@ -3537,7 +3573,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // We need to make sure we update the CompatFrame as it is used for // cropping decisions, etc, on systems where we lack a decor layer. mWindowFrames.mCompatFrame.set(mWindowFrames.mFrame); - if (mEnforceSizeCompat) { + if (inSizeCompatMode) { // See comparable block in computeFrameLw. mWindowFrames.mCompatFrame.scale(mInvGlobalScale); } @@ -3650,7 +3686,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP float translateToWindowX(float x) { float winX = x - mWindowFrames.mFrame.left; - if (mEnforceSizeCompat) { + if (inSizeCompatMode()) { winX *= mGlobalScale; } return winX; @@ -3658,7 +3694,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP float translateToWindowY(float y) { float winY = y - mWindowFrames.mFrame.top; - if (mEnforceSizeCompat) { + if (inSizeCompatMode()) { winY *= mGlobalScale; } return winY; @@ -4233,12 +4269,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ void calculatePolicyCrop(Rect policyCrop) { final DisplayContent displayContent = getDisplayContent(); - final DisplayInfo displayInfo = displayContent.getDisplayInfo(); - if (!isDefaultDisplay()) { + if (!displayContent.isDefaultDisplay && !displayContent.supportsSystemDecorations()) { // On a different display there is no system decor. Crop the window // by the screen boundaries. - // TODO(multi-display) + final DisplayInfo displayInfo = displayContent.getDisplayInfo(); policyCrop.set(0, 0, mWindowFrames.mCompatFrame.width(), mWindowFrames.mCompatFrame.height()); policyCrop.intersect(-mWindowFrames.mCompatFrame.left, -mWindowFrames.mCompatFrame.top, @@ -4304,7 +4339,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // scale function because we want to round things to make the crop // always round to a larger rect to ensure we don't crop too // much and hide part of the window that should be seen. - if (mEnforceSizeCompat && mInvGlobalScale != 1.0f) { + if (inSizeCompatMode() && mInvGlobalScale != 1.0f) { final float scale = mInvGlobalScale; systemDecorRect.left = (int) (systemDecorRect.left * scale - 0.5f); systemDecorRect.top = (int) (systemDecorRect.top * scale - 0.5f); @@ -4664,8 +4699,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Since the parent was outset by its surface insets, we need to undo the outsetting // with insetting by the same amount. final WindowState parent = getParentWindow(); - outPoint.offset(-parent.mWindowFrames.mFrame.left + parent.mAttrs.surfaceInsets.left, - -parent.mWindowFrames.mFrame.top + parent.mAttrs.surfaceInsets.top); + transformSurfaceInsetsPosition(mTmpPoint, parent.mAttrs.surfaceInsets); + outPoint.offset(-parent.mWindowFrames.mFrame.left + mTmpPoint.x, + -parent.mWindowFrames.mFrame.top + mTmpPoint.y); } else if (parentWindowContainer != null) { final Rect parentBounds = parentWindowContainer.getDisplayedBounds(); outPoint.offset(-parentBounds.left, -parentBounds.top); @@ -4683,7 +4719,22 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } // Expand for surface insets. See WindowState.expandForSurfaceInsets. - outPoint.offset(-mAttrs.surfaceInsets.left, -mAttrs.surfaceInsets.top); + transformSurfaceInsetsPosition(mTmpPoint, mAttrs.surfaceInsets); + outPoint.offset(-mTmpPoint.x, -mTmpPoint.y); + } + + /** + * The surface insets from layout parameter are in application coordinate. If the window is + * scaled, the insets also need to be scaled for surface position in global coordinate. + */ + private void transformSurfaceInsetsPosition(Point outPos, Rect surfaceInsets) { + if (!inSizeCompatMode()) { + outPos.x = surfaceInsets.left; + outPos.y = surfaceInsets.top; + return; + } + outPos.x = (int) (surfaceInsets.left * mGlobalScale + 0.5f); + outPos.y = (int) (surfaceInsets.top * mGlobalScale + 0.5f); } boolean needsRelativeLayeringToIme() { diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 3b9b8bab9e61..f0b9c62f2843 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -182,6 +182,14 @@ class WindowToken extends WindowContainer<WindowState> { } /** + * @return The scale for applications running in compatibility mode. Multiply the size in the + * application by this scale will be the size in the screen. + */ + float getSizeCompatScale() { + return mDisplayContent.mCompatibleScreenScale; + } + + /** * Returns true if the new window is considered greater than the existing window in terms of * z-order. */ diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java index 8b1ffa8387d7..abc474d756b7 100644 --- a/services/core/java/com/android/server/wm/WindowTracing.java +++ b/services/core/java/com/android/server/wm/WindowTracing.java @@ -24,12 +24,14 @@ import static com.android.server.wm.WindowManagerTraceProto.WHERE; import static com.android.server.wm.WindowManagerTraceProto.WINDOW_MANAGER_SERVICE; import android.annotation.Nullable; -import android.content.Context; import android.os.ShellCommand; import android.os.SystemClock; import android.os.Trace; import android.util.Log; import android.util.proto.ProtoOutputStream; +import android.view.Choreographer; + +import com.android.internal.annotations.VisibleForTesting; import java.io.File; import java.io.IOException; @@ -48,6 +50,10 @@ class WindowTracing { private static final int WINDOW_TRACE_BUFFER_SIZE = 512 * 1024; private static final String TAG = "WindowTracing"; + private final WindowManagerService mService; + private final Choreographer mChoreographer; + private final WindowManagerGlobalLock mGlobalLock; + private final Object mLock = new Object(); private final WindowTraceBuffer.Builder mBufferBuilder; @@ -57,11 +63,24 @@ class WindowTracing { private boolean mContinuousMode; private boolean mEnabled; private volatile boolean mEnabledLockFree; + private boolean mScheduled; + private Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) -> + log("onFrame" /* where */); + + private WindowTracing(File file, WindowManagerService service, Choreographer choreographer) { + this(file, service, choreographer, service.mGlobalLock); + } - WindowTracing(File file) { + @VisibleForTesting + WindowTracing(File file, WindowManagerService service, Choreographer choreographer, + WindowManagerGlobalLock globalLock) { mBufferBuilder = new WindowTraceBuffer.Builder() .setTraceFile(file) .setBufferCapacity(WINDOW_TRACE_BUFFER_SIZE); + + mChoreographer = choreographer; + mService = service; + mGlobalLock = globalLock; } void startTrace(@Nullable PrintWriter pw) throws IOException { @@ -111,7 +130,8 @@ class WindowTracing { } } - private void setContinuousMode(boolean continuous, PrintWriter pw) { + @VisibleForTesting + void setContinuousMode(boolean continuous, PrintWriter pw) { logAndPrintln(pw, "Setting window tracing continuous mode to " + continuous); if (mEnabled) { @@ -123,21 +143,14 @@ class WindowTracing { WindowTraceLogLevel.TRIM; } - private void appendTraceEntry(ProtoOutputStream proto) { - if (!mEnabledLockFree) { - return; - } - - mTraceBuffer.add(proto); - } - boolean isEnabled() { return mEnabledLockFree; } - static WindowTracing createDefaultAndStartLooper(Context context) { + static WindowTracing createDefaultAndStartLooper(WindowManagerService service, + Choreographer choreographer) { File file = new File("/data/misc/wmtrace/wm_trace.pb"); - return new WindowTracing(file); + return new WindowTracing(file, service, choreographer); } int onShellCommand(ShellCommand shell) { @@ -164,28 +177,65 @@ class WindowTracing { } } - void traceStateLocked(String where, WindowManagerService service) { + /** + * If tracing is enabled, log the current state or schedule the next frame to be logged, + * according to {@link #mContinuousMode}. + * + * @param where Logging point descriptor + */ + void logState(String where) { if (!isEnabled()) { return; } - Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToBufferLocked"); + if (mContinuousMode) { + schedule(); + } else { + log(where); + } + } + + /** + * Schedule the log to trace the next frame + */ + private void schedule() { + if (mScheduled) { + return; + } + + mScheduled = true; + mChoreographer.postFrameCallback(mFrameCallback); + } + + /** + * Write the current frame to the buffer + * + * @param where Logging point descriptor + */ + private void log(String where) { + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "traceStateLocked"); try { - ProtoOutputStream os = new ProtoOutputStream(); - long tokenOuter = os.start(ENTRY); - os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos()); - os.write(WHERE, where); - - Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToProtoLocked"); - try { - long tokenInner = os.start(WINDOW_MANAGER_SERVICE); - service.writeToProtoLocked(os, mWindowTraceLogLevel); - os.end(tokenInner); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); + synchronized (mGlobalLock) { + ProtoOutputStream os = new ProtoOutputStream(); + long tokenOuter = os.start(ENTRY); + os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos()); + os.write(WHERE, where); + + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToProtoLocked"); + try { + long tokenInner = os.start(WINDOW_MANAGER_SERVICE); + mService.writeToProtoLocked(os, mWindowTraceLogLevel); + os.end(tokenInner); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); + } + os.end(tokenOuter); + mTraceBuffer.add(os); + + mScheduled = false; } - os.end(tokenOuter); - appendTraceEntry(os); + } catch (Exception e) { + Log.wtf(TAG, "Exception while tracing state", e); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 33317b554988..c18e98bab9c4 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -373,6 +373,9 @@ void NativeInputManager::dump(std::string& dump) { mInputManager->getReader()->dump(dump); dump += "\n"; + mInputManager->getClassifier()->dump(dump); + dump += "\n"; + mInputManager->getDispatcher()->dump(dump); dump += "\n"; } diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp index bf96f9a3b71b..6cd9f2c718ee 100644 --- a/services/core/jni/com_android_server_security_VerityUtils.cpp +++ b/services/core/jni/com_android_server_security_VerityUtils.cpp @@ -122,7 +122,7 @@ class JavaByteArrayHolder { } ~JavaByteArrayHolder() { - LOG_ALWAYS_FATAL_IF(mElements == nullptr, "Elements are not released"); + LOG_ALWAYS_FATAL_IF(mElements != nullptr, "Elements are not released"); } private: diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 1155f499d619..9523202cbb0e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -17,8 +17,8 @@ package com.android.server.devicepolicy; import static android.Manifest.permission.BIND_DEVICE_ADMIN; -import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY; import static android.Manifest.permission.MANAGE_CA_CERTIFICATES; +import static android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; @@ -247,6 +247,7 @@ import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.pm.UserRestrictionsUtils; import com.android.server.storage.DeviceStorageMonitorInternal; import com.android.server.uri.UriGrantsManagerInternal; +import com.android.server.wm.ActivityTaskManagerInternal; import com.google.android.collect.Sets; @@ -1870,7 +1871,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Owners newOwners() { return new Owners(getUserManager(), getUserManagerInternal(), - getPackageManagerInternal()); + getPackageManagerInternal(), getActivityTaskManagerInternal()); } UserManager getUserManager() { @@ -1885,6 +1886,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return LocalServices.getService(PackageManagerInternal.class); } + ActivityTaskManagerInternal getActivityTaskManagerInternal() { + return LocalServices.getService(ActivityTaskManagerInternal.class); + } + UsageStatsManagerInternal getUsageStatsManagerInternal() { return LocalServices.getService(UsageStatsManagerInternal.class); } @@ -4773,8 +4778,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final int callingUserId = mInjector.userHandleGetCallingUserId(); enforceUserUnlocked(callingUserId); mContext.enforceCallingOrSelfPermission( - GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY, - "Must have " + GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY + " permission."); + REQUEST_SCREEN_LOCK_COMPLEXITY, + "Must have " + REQUEST_SCREEN_LOCK_COMPLEXITY + " permission."); synchronized (getLockObject()) { int targetUserId = getCredentialOwner(callingUserId, /* parent= */ false); @@ -12790,10 +12795,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - // TODO(b/22388012): When backup is available for secondary users and profiles, consider - // whether there are any privacy/security implications of enabling the backup service here - // if there are other users or profiles unmanaged or managed by a different entity (i.e. not - // affiliated). @Override public void setBackupServiceEnabled(ComponentName admin, boolean enabled) { if (!mHasFeature) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java index ee1c1df3f162..27cd70c9a606 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java @@ -41,6 +41,7 @@ import android.util.Xml; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FastXmlSerializer; import com.android.server.LocalServices; +import com.android.server.wm.ActivityTaskManagerInternal; import libcore.io.IoUtils; @@ -104,6 +105,7 @@ class Owners { private final UserManager mUserManager; private final UserManagerInternal mUserManagerInternal; private final PackageManagerInternal mPackageManagerInternal; + private final ActivityTaskManagerInternal mActivityTaskManagerInternal; private boolean mSystemReady; @@ -129,18 +131,22 @@ class Owners { public Owners(UserManager userManager, UserManagerInternal userManagerInternal, - PackageManagerInternal packageManagerInternal) { - this(userManager, userManagerInternal, packageManagerInternal, new Injector()); + PackageManagerInternal packageManagerInternal, + ActivityTaskManagerInternal activityTaskManagerInternal) { + this(userManager, userManagerInternal, packageManagerInternal, + activityTaskManagerInternal, new Injector()); } @VisibleForTesting Owners(UserManager userManager, UserManagerInternal userManagerInternal, PackageManagerInternal packageManagerInternal, + ActivityTaskManagerInternal activityTaskManagerInternal, Injector injector) { mUserManager = userManager; mUserManagerInternal = userManagerInternal; mPackageManagerInternal = packageManagerInternal; + mActivityTaskManagerInternal = activityTaskManagerInternal; mInjector = injector; } @@ -187,6 +193,7 @@ class Owners { getDeviceOwnerUserId())); } pushToPackageManagerLocked(); + pushToActivityTaskManagerLocked(); pushToAppOpsLocked(); } } @@ -201,6 +208,11 @@ class Owners { po); } + private void pushToActivityTaskManagerLocked() { + mActivityTaskManagerInternal.setDeviceOwnerPackageName(mDeviceOwner != null + ? mDeviceOwner.packageName : null); + } + String getDeviceOwnerPackageName() { synchronized (mLock) { return mDeviceOwner != null ? mDeviceOwner.packageName : null; @@ -275,6 +287,7 @@ class Owners { mUserManagerInternal.setDeviceManaged(true); pushToPackageManagerLocked(); + pushToActivityTaskManagerLocked(); pushToAppOpsLocked(); } } @@ -286,6 +299,7 @@ class Owners { mUserManagerInternal.setDeviceManaged(false); pushToPackageManagerLocked(); + pushToActivityTaskManagerLocked(); pushToAppOpsLocked(); } } @@ -333,6 +347,7 @@ class Owners { mDeviceOwner.remoteBugreportHash, /* canAccessDeviceIds =*/ mDeviceOwner.canAccessDeviceIds); pushToPackageManagerLocked(); + pushToActivityTaskManagerLocked(); pushToAppOpsLocked(); } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index ab30cda271f0..a6017f2c1e86 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -64,6 +64,7 @@ import android.util.EventLog; import android.util.Slog; import android.util.TimingsTraceLog; import android.view.WindowManager; +import android.view.contentcapture.ContentCaptureManager; import android.view.inputmethod.InputMethodSystemProperty; import com.android.internal.R; @@ -2214,33 +2215,30 @@ public final class SystemServer { } private void startContentCaptureService(@NonNull Context context) { - // Check if it was explicitly enabled by DeviceConfig - final String settings = DeviceConfig.getProperty(DeviceConfig.ContentCapture.NAMESPACE, - DeviceConfig.ContentCapture.PROPERTY_CONTENTCAPTURE_ENABLED); - if (settings == null) { - // Better be safe than sorry... - Slog.d(TAG, "ContentCaptureService disabled because its not set by OEM"); - return; - } - switch (settings) { - case "always": - // Should be used only during development + // First check if it was explicitly enabled by DeviceConfig + boolean explicitlySupported = false; + String settings = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE, + ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED); + if (settings != null && !settings.equalsIgnoreCase("default")) { + explicitlySupported = Boolean.parseBoolean(settings); + if (explicitlySupported) { Slog.d(TAG, "ContentCaptureService explicitly enabled by DeviceConfig"); - break; - case "default": - // Default case: check if OEM overlaid the resource that defines the service. - final String serviceName = context.getString( - com.android.internal.R.string.config_defaultContentCaptureService); - if (TextUtils.isEmpty(serviceName)) { - Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid"); - return; - } - break; - default: - // Kill switch for OEMs - Slog.d(TAG, "ContentCaptureService disabled because its set to: " + settings); + } else { + Slog.d(TAG, "ContentCaptureService explicitly disabled by DeviceConfig"); return; + } } + + // Then check if OEM overlaid the resource that defines the service. + if (!explicitlySupported) { + final String serviceName = context + .getString(com.android.internal.R.string.config_defaultContentCaptureService); + if (TextUtils.isEmpty(serviceName)) { + Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid"); + return; + } + } + traceBeginAndSlog("StartContentCaptureService"); mSystemServiceManager.startService(CONTENT_CAPTURE_MANAGER_SERVICE_CLASS); traceEnd(); diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java index 4354db72554a..24e5573b891d 100644 --- a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java +++ b/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 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. @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.backup.encryption.chunk; @@ -36,7 +36,7 @@ import java.util.Arrays; @RunWith(RobolectricTestRunner.class) @Presubmit -public class ChunkListingTest { +public class ChunkListingMapTest { private static final String CHUNK_A = "CHUNK_A"; private static final String CHUNK_B = "CHUNK_B"; private static final String CHUNK_C = "CHUNK_C"; @@ -62,13 +62,13 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - boolean chunkAInList = chunkListing.hasChunk(mChunkHashA); - boolean chunkBInList = chunkListing.hasChunk(mChunkHashB); - boolean chunkCInList = chunkListing.hasChunk(mChunkHashC); + boolean chunkAInList = chunkListingMap.hasChunk(mChunkHashA); + boolean chunkBInList = chunkListingMap.hasChunk(mChunkHashB); + boolean chunkCInList = chunkListingMap.hasChunk(mChunkHashC); assertThat(chunkAInList).isTrue(); assertThat(chunkBInList).isTrue(); @@ -81,13 +81,13 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); ChunkHash chunkHashEmpty = getHash(""); - boolean chunkCInList = chunkListing.hasChunk(mChunkHashC); - boolean emptyChunkInList = chunkListing.hasChunk(chunkHashEmpty); + boolean chunkCInList = chunkListingMap.hasChunk(mChunkHashC); + boolean emptyChunkInList = chunkListingMap.hasChunk(chunkHashEmpty); assertThat(chunkCInList).isFalse(); assertThat(emptyChunkInList).isFalse(); @@ -99,13 +99,13 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA); - ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB); - ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC); + ChunkListingMap.Entry entryA = chunkListingMap.getChunkEntry(mChunkHashA); + ChunkListingMap.Entry entryB = chunkListingMap.getChunkEntry(mChunkHashB); + ChunkListingMap.Entry entryC = chunkListingMap.getChunkEntry(mChunkHashC); assertThat(entryA.getLength()).isEqualTo(CHUNK_A_LENGTH); assertThat(entryB.getLength()).isEqualTo(CHUNK_B_LENGTH); @@ -118,13 +118,13 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA); - ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB); - ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC); + ChunkListingMap.Entry entryA = chunkListingMap.getChunkEntry(mChunkHashA); + ChunkListingMap.Entry entryB = chunkListingMap.getChunkEntry(mChunkHashB); + ChunkListingMap.Entry entryC = chunkListingMap.getChunkEntry(mChunkHashC); assertThat(entryA.getStart()).isEqualTo(0); assertThat(entryB.getStart()).isEqualTo(CHUNK_A_LENGTH); @@ -137,22 +137,24 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - ChunkListing.Entry chunkEntryNonexistentChunk = chunkListing.getChunkEntry(mChunkHashC); + ChunkListingMap.Entry chunkEntryNonexistentChunk = + chunkListingMap.getChunkEntry(mChunkHashC); assertThat(chunkEntryNonexistentChunk).isNull(); } @Test - public void testReadFromProto_whenEmptyProto_returnsChunkListingWith0Chunks() throws Exception { + public void testReadFromProto_whenEmptyProto_returnsChunkListingMapWith0Chunks() + throws Exception { ProtoInputStream emptyProto = new ProtoInputStream(new ByteArrayInputStream(new byte[] {})); - ChunkListing chunkListing = ChunkListing.readFromProto(emptyProto); + ChunkListingMap chunkListingMap = ChunkListingMap.readFromProto(emptyProto); - assertThat(chunkListing.getChunkCount()).isEqualTo(0); + assertThat(chunkListingMap.getChunkCount()).isEqualTo(0); } @Test @@ -162,11 +164,11 @@ public class ChunkListingTest { new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - assertThat(chunkListing.getChunkCount()).isEqualTo(3); + assertThat(chunkListingMap.getChunkCount()).isEqualTo(3); } private byte[] createChunkListingProto(ChunkHash[] hashes, int[] lengths) { diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java index 53d72bb9a415..e51ee947cba1 100644 --- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java @@ -19,6 +19,7 @@ import static androidx.test.InstrumentationRegistry.getContext; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -51,6 +52,9 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; import android.app.ActivityManagerInternal; import android.app.AlarmManager; @@ -82,6 +86,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; @@ -105,6 +110,8 @@ public class DeviceIdleControllerTest { @Mock private ContentResolver mContentResolver; @Mock + private DeviceIdleController.MyHandler mHandler; + @Mock private IActivityManager mIActivityManager; @Mock private LocationManager mLocationManager; @@ -154,7 +161,7 @@ public class DeviceIdleControllerTest { @Override DeviceIdleController.MyHandler getHandler(DeviceIdleController controller) { - return mock(DeviceIdleController.MyHandler.class, Answers.RETURNS_DEEP_STUBS); + return mHandler; } @Override @@ -232,10 +239,12 @@ public class DeviceIdleControllerTest { .when(() -> LocalServices.getService(ActivityManagerInternal.class)); doReturn(mock(ActivityTaskManagerInternal.class)) .when(() -> LocalServices.getService(ActivityTaskManagerInternal.class)); + doReturn(mock(AlarmManagerInternal.class)) + .when(() -> LocalServices.getService(AlarmManagerInternal.class)); doReturn(mPowerManagerInternal) .when(() -> LocalServices.getService(PowerManagerInternal.class)); - when(mPowerManagerInternal.getLowPowerState(anyInt())).thenReturn( - mock(PowerSaveState.class)); + when(mPowerManagerInternal.getLowPowerState(anyInt())) + .thenReturn(mock(PowerSaveState.class)); doReturn(mock(NetworkPolicyManagerInternal.class)) .when(() -> LocalServices.getService(NetworkPolicyManagerInternal.class)); when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock); @@ -246,8 +255,11 @@ public class DeviceIdleControllerTest { doReturn(true).when(mSensorManager).registerListener(any(), any(), anyInt()); mAppStateTracker = new AppStateTrackerForTest(getContext(), Looper.getMainLooper()); mAnyMotionDetector = new AnyMotionDetectorForTest(); + mHandler = mock(DeviceIdleController.MyHandler.class, Answers.RETURNS_DEEP_STUBS); + doNothing().when(mHandler).handleMessage(any()); mInjector = new InjectorForTest(getContext()); doNothing().when(mContentResolver).registerContentObserver(any(), anyBoolean(), any()); + mDeviceIdleController = new DeviceIdleController(getContext(), mInjector); spyOn(mDeviceIdleController); doNothing().when(mDeviceIdleController).publishBinderService(any(), any()); @@ -423,6 +435,29 @@ public class DeviceIdleControllerTest { mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyStateConditions(STATE_ACTIVE); + + mConstants.WAIT_FOR_UNLOCK = false; + setScreenLocked(true); + setScreenOn(true); + setChargingOn(false); + + mDeviceIdleController.becomeInactiveIfAppropriateLocked(); + verifyStateConditions(STATE_ACTIVE); + + setScreenLocked(false); + setScreenOn(true); + setChargingOn(false); + + mDeviceIdleController.becomeInactiveIfAppropriateLocked(); + verifyStateConditions(STATE_ACTIVE); + + mConstants.WAIT_FOR_UNLOCK = true; + setScreenLocked(false); + setScreenOn(true); + setChargingOn(false); + + mDeviceIdleController.becomeInactiveIfAppropriateLocked(); + verifyStateConditions(STATE_ACTIVE); } @Test @@ -1307,7 +1342,7 @@ public class DeviceIdleControllerTest { } @Test - public void testbecomeActiveLocked_deep() { + public void testBecomeActiveLocked_deep() { // becomeActiveLocked should put everything into ACTIVE. enterDeepState(STATE_ACTIVE); @@ -1344,7 +1379,7 @@ public class DeviceIdleControllerTest { } @Test - public void testbecomeActiveLocked_light() { + public void testBecomeActiveLocked_light() { // becomeActiveLocked should put everything into ACTIVE. enterLightState(LIGHT_STATE_ACTIVE); @@ -1376,6 +1411,163 @@ public class DeviceIdleControllerTest { verifyLightStateConditions(LIGHT_STATE_ACTIVE); } + /** Test based on b/119058625. */ + @Test + public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOn_ScreenThenMotion() { + mConstants.WAIT_FOR_UNLOCK = true; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + mDeviceIdleController.keyguardShowingLocked(true); + setScreenOn(true); + // With WAIT_FOR_UNLOCK = true and the screen locked, turning the screen on by itself + // shouldn't bring the device out of deep IDLE. + verifyStateConditions(STATE_IDLE); + mDeviceIdleController.handleMotionDetectedLocked(1000, "test"); + // Motion should bring the device out of Doze. Since the screen is still locked (albeit + // on), the states should go back into INACTIVE. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt()); + } + + /** Test based on b/119058625. */ + @Test + public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOff_ScreenThenMotion() { + mConstants.WAIT_FOR_UNLOCK = true; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + mDeviceIdleController.keyguardShowingLocked(false); + setScreenOn(true); + // With WAIT_FOR_UNLOCK = true and the screen unlocked, turning the screen on by itself + // should bring the device out of deep IDLE. + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt()); + } + + /** Test based on b/119058625. */ + @Test + public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOn_MotionThenScreen() { + mConstants.WAIT_FOR_UNLOCK = true; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + InOrder alarmManagerInOrder = inOrder(mAlarmManager); + InOrder controllerInOrder = inOrder(mDeviceIdleController); + + mDeviceIdleController.keyguardShowingLocked(true); + mDeviceIdleController.handleMotionDetectedLocked(1000, "test"); + // The screen is still off, so motion should result in the INACTIVE state. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + + setScreenOn(true); + // With WAIT_FOR_UNLOCK = true and the screen locked, turning the screen on by itself + // shouldn't bring the device all the way to ACTIVE. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + alarmManagerInOrder.verify(mAlarmManager, never()).cancel( + eq(mDeviceIdleController.mDeepAlarmListener)); + + // User finally unlocks the device. Device should be fully active. + mDeviceIdleController.keyguardShowingLocked(false); + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + } + + /** Test based on b/119058625. */ + @Test + public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOff_MotionThenScreen() { + mConstants.WAIT_FOR_UNLOCK = true; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + InOrder alarmManagerInOrder = inOrder(mAlarmManager); + InOrder controllerInOrder = inOrder(mDeviceIdleController); + + mDeviceIdleController.keyguardShowingLocked(false); + mDeviceIdleController.handleMotionDetectedLocked(1000, "test"); + // The screen is still off, so motion should result in the INACTIVE state. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + + setScreenOn(true); + // With WAIT_FOR_UNLOCK = true and the screen unlocked, turning the screen on by itself + // should bring the device out of deep IDLE. + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + } + + @Test + public void testExitNotifiesDependencies_WaitForUnlockOff_Screen() { + mConstants.WAIT_FOR_UNLOCK = false; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + setScreenOn(true); + // With WAIT_FOR_UNLOCK = false and the screen locked, turning the screen on by itself + // should bring the device out of deep IDLE. + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt()); + } + + @Test + public void testExitNotifiesDependencies_WaitForUnlockOff_MotionThenScreen() { + mConstants.WAIT_FOR_UNLOCK = false; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + InOrder alarmManagerInOrder = inOrder(mAlarmManager); + InOrder controllerInOrder = inOrder(mDeviceIdleController); + + mDeviceIdleController.handleMotionDetectedLocked(1000, "test"); + // The screen is still off, so motion should result in the INACTIVE state. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + + setScreenOn(true); + // With WAIT_FOR_UNLOCK = false and the screen locked, turning the screen on by itself + // should bring the device out of deep IDLE. + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + } + @Test public void testStepToIdleMode() { float delta = mDeviceIdleController.MIN_PRE_IDLE_FACTOR_CHANGE; @@ -1508,6 +1700,10 @@ public class DeviceIdleControllerTest { mDeviceIdleController.updateChargingLocked(on); } + private void setScreenLocked(boolean locked) { + mDeviceIdleController.keyguardShowingLocked(locked); + } + private void setScreenOn(boolean on) { doReturn(on).when(mPowerManager).isInteractive(); mDeviceIdleController.updateInteractivityLocked(); @@ -1549,7 +1745,8 @@ public class DeviceIdleControllerTest { assertFalse(mDeviceIdleController.mMotionListener.isActive()); assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_IDLE_PENDING: assertEquals( @@ -1557,7 +1754,8 @@ public class DeviceIdleControllerTest { mDeviceIdleController.mMotionListener.isActive()); assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_SENSING: assertEquals( @@ -1567,14 +1765,16 @@ public class DeviceIdleControllerTest { mDeviceIdleController.hasMotionSensor(), mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_LOCATING: assertEquals( mDeviceIdleController.hasMotionSensor(), mDeviceIdleController.mMotionListener.isActive()); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_IDLE: if (mDeviceIdleController.hasMotionSensor()) { @@ -1584,7 +1784,8 @@ public class DeviceIdleControllerTest { } assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); // Light state should be OVERRIDE at this point. verifyLightStateConditions(LIGHT_STATE_OVERRIDE); break; @@ -1596,14 +1797,16 @@ public class DeviceIdleControllerTest { } assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_QUICK_DOZE_DELAY: // If quick doze is enabled, the motion listener should NOT be active. assertFalse(mDeviceIdleController.mMotionListener.isActive()); assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; default: fail("Conditions for " + stateToString(expectedState) + " unknown."); @@ -1632,7 +1835,8 @@ public class DeviceIdleControllerTest { case LIGHT_STATE_IDLE_MAINTENANCE: case LIGHT_STATE_OVERRIDE: assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; default: fail("Conditions for " + lightStateToString(expectedLightState) + " unknown."); diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index dc31c0f7ebbb..fce7599d0b59 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -66,6 +66,8 @@ <uses-permission android:name="android.permission.CONTROL_KEYGUARD"/> <uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"/> <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" /> + <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> + <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <!-- Uses API introduced in O (26) --> <uses-sdk android:minSdkVersion="1" diff --git a/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java b/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java index 2f8e5456a695..63015be6ef3f 100644 --- a/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java +++ b/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java @@ -147,10 +147,10 @@ public final class AppCompactorTest { KEY_USE_COMPACTION, "true", false); DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE, KEY_COMPACT_ACTION_1, - Integer.toString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 3) + 1), false); + Integer.toString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 4) + 1), false); DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE, KEY_COMPACT_ACTION_2, - Integer.toString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 3) + 1), false); + Integer.toString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 4) + 1), false); DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE, KEY_COMPACT_THROTTLE_1, Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1), false); @@ -173,9 +173,9 @@ public final class AppCompactorTest { assertThat(mCompactorUnderTest.mCompactionThread.isAlive(), is(true)); assertThat(mCompactorUnderTest.mCompactActionSome, - is(compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 3) + 1))); + is(compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 4) + 1))); assertThat(mCompactorUnderTest.mCompactActionFull, - is(compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 3) + 1))); + is(compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 4) + 1))); assertThat(mCompactorUnderTest.mCompactThrottleSomeSome, is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1)); assertThat(mCompactorUnderTest.mCompactThrottleSomeFull, @@ -233,13 +233,13 @@ public final class AppCompactorTest { // When we override new values for the compaction action with reasonable values... - // There are three possible values for compactAction[Some|Full]. - for (int i = 1; i < 4; i++) { + // There are four possible values for compactAction[Some|Full]. + for (int i = 1; i < 5; i++) { mCountDown = new CountDownLatch(2); - int expectedSome = (mCompactorUnderTest.DEFAULT_COMPACT_ACTION_1 + i) % 3 + 1; + int expectedSome = (mCompactorUnderTest.DEFAULT_COMPACT_ACTION_1 + i) % 4 + 1; DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE, KEY_COMPACT_ACTION_1, Integer.toString(expectedSome), false); - int expectedFull = (mCompactorUnderTest.DEFAULT_COMPACT_ACTION_2 + i) % 3 + 1; + int expectedFull = (mCompactorUnderTest.DEFAULT_COMPACT_ACTION_2 + i) % 4 + 1; DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE, KEY_COMPACT_ACTION_2, Integer.toString(expectedFull), false); assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true)); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index a847b6ab105c..2ce4c54a932b 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -65,7 +65,8 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi public OwnersTestable(MockSystemServices services) { super(services.userManager, services.userManagerInternal, - services.packageManagerInternal, new MockInjector(services)); + services.packageManagerInternal, services.activityTaskManagerInternal, + new MockInjector(services)); } static class MockInjector extends Injector { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 9ac91ddba5ec..de782a52eb53 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -5199,7 +5199,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testGetPasswordComplexity_currentUserNoPassword() { when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE)) .thenReturn(true); - mServiceContext.permissions.add(permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY); + mServiceContext.permissions.add(permission.REQUEST_SCREEN_LOCK_COMPLEXITY); when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE)) .thenReturn(DpmMockContext.CALLER_USER_HANDLE); @@ -5209,7 +5209,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testGetPasswordComplexity_currentUserHasPassword() { when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE)) .thenReturn(true); - mServiceContext.permissions.add(permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY); + mServiceContext.permissions.add(permission.REQUEST_SCREEN_LOCK_COMPLEXITY); when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE)) .thenReturn(DpmMockContext.CALLER_USER_HANDLE); dpms.mUserPasswordMetrics.put( @@ -5222,7 +5222,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testGetPasswordComplexity_unifiedChallengeReturnsParentUserPassword() { when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE)) .thenReturn(true); - mServiceContext.permissions.add(permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY); + mServiceContext.permissions.add(permission.REQUEST_SCREEN_LOCK_COMPLEXITY); UserInfo parentUser = new UserInfo(); parentUser.id = DpmMockContext.CALLER_USER_HANDLE + 10; diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java index 4724f1cdd324..8f0aeea3dbf8 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java @@ -64,6 +64,7 @@ import android.view.IWindowManager; import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.widget.LockPatternUtils; import com.android.server.net.NetworkPolicyManagerInternal; +import com.android.server.wm.ActivityTaskManagerInternal; import java.io.File; import java.io.IOException; @@ -94,6 +95,7 @@ public class MockSystemServices { public final IActivityManager iactivityManager; public final IActivityTaskManager iactivityTaskManager; public ActivityManagerInternal activityManagerInternal; + public ActivityTaskManagerInternal activityTaskManagerInternal; public final IPackageManager ipackageManager; public final IBackupManager ibackupManager; public final IAudioService iaudioService; @@ -133,6 +135,7 @@ public class MockSystemServices { iactivityManager = mock(IActivityManager.class); iactivityTaskManager = mock(IActivityTaskManager.class); activityManagerInternal = mock(ActivityManagerInternal.class); + activityTaskManagerInternal = mock(ActivityTaskManagerInternal.class); ipackageManager = mock(IPackageManager.class); ibackupManager = mock(IBackupManager.class); iaudioService = mock(IAudioService.class); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java index 13436e7f8674..821d97acc230 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java @@ -24,14 +24,21 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.testng.Assert.expectThrows; import android.app.KeyguardManager; import android.content.Context; +import android.os.RemoteException; +import android.security.GateKeeper; +import android.security.keystore.AndroidKeyStoreSecretKey; +import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; +import android.service.gatekeeper.IGateKeeperService; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -53,6 +60,8 @@ import java.security.KeyStore; import java.security.UnrecoverableKeyException; import java.util.List; +import javax.crypto.KeyGenerator; + @SmallTest @RunWith(AndroidJUnit4.class) public class PlatformKeyManagerTest { @@ -60,10 +69,15 @@ public class PlatformKeyManagerTest { private static final String DATABASE_FILE_NAME = "recoverablekeystore.db"; private static final int USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS = 15; private static final int USER_ID_FIXTURE = 42; + private static final long USER_SID = 4200L; + private static final String KEY_ALGORITHM = "AES"; + private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore"; + private static final String TESTING_KEYSTORE_KEY_ALIAS = "testing-key-store-key-alias"; @Mock private Context mContext; @Mock private KeyStoreProxy mKeyStoreProxy; @Mock private KeyguardManager mKeyguardManager; + @Mock private IGateKeeperService mGateKeeperService; @Captor private ArgumentCaptor<KeyStore.ProtectionParameter> mProtectionParameterCaptor; @Captor private ArgumentCaptor<KeyStore.Entry> mEntryArgumentCaptor; @@ -74,18 +88,19 @@ public class PlatformKeyManagerTest { private PlatformKeyManager mPlatformKeyManager; @Before - public void setUp() { + public void setUp() throws Exception { MockitoAnnotations.initMocks(this); Context context = InstrumentationRegistry.getTargetContext(); mDatabaseFile = context.getDatabasePath(DATABASE_FILE_NAME); mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context); - mPlatformKeyManager = new PlatformKeyManager( - mContext, mKeyStoreProxy, mRecoverableKeyStoreDb); + mPlatformKeyManager = new PlatformKeyManagerTestable( + mContext, mKeyStoreProxy, mRecoverableKeyStoreDb, mGateKeeperService); when(mContext.getSystemService(anyString())).thenReturn(mKeyguardManager); when(mContext.getSystemServiceName(any())).thenReturn("test"); when(mKeyguardManager.isDeviceSecure(USER_ID_FIXTURE)).thenReturn(true); + when(mGateKeeperService.getSecureUserId(USER_ID_FIXTURE)).thenReturn(USER_SID); } @After @@ -192,11 +207,36 @@ public class PlatformKeyManagerTest { mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals( - USER_ID_FIXTURE, + USER_SID, getDecryptKeyProtection().getBoundToSpecificSecureUserId()); } @Test + public void init_doesNotCreateDecryptKeyIfNoSid() throws Exception { + when(mGateKeeperService.getSecureUserId(USER_ID_FIXTURE)) + .thenReturn(GateKeeper.INVALID_SECURE_USER_ID); + + mPlatformKeyManager.init(USER_ID_FIXTURE); + + verify(mKeyStoreProxy, never()).setEntry( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), + any(), + any()); + } + + @Test + public void init_doesNotCreateDecryptKeyOnGateKeeperException() throws Exception { + when(mGateKeeperService.getSecureUserId(USER_ID_FIXTURE)).thenThrow(new RemoteException()); + + expectThrows(RemoteException.class, () -> mPlatformKeyManager.init(USER_ID_FIXTURE)); + + verify(mKeyStoreProxy, never()).setEntry( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), + any(), + any()); + } + + @Test public void init_createsBothKeysWithSameMaterial() throws Exception { mPlatformKeyManager.init(USER_ID_FIXTURE); @@ -259,6 +299,9 @@ public class PlatformKeyManagerTest { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); + when(mKeyStoreProxy.getKey( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), + any())).thenReturn(generateAndroidKeyStoreKey()); mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); @@ -281,6 +324,9 @@ public class PlatformKeyManagerTest { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/decrypt")).thenReturn(true); + when(mKeyStoreProxy.getKey( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"), + any())).thenReturn(generateAndroidKeyStoreKey()); mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); @@ -352,6 +398,9 @@ public class PlatformKeyManagerTest { doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), any()); + when(mKeyStoreProxy.getKey( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"), + any())).thenReturn(generateAndroidKeyStoreKey()); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" @@ -536,4 +585,34 @@ public class PlatformKeyManagerTest { mProtectionParameterCaptor.capture()); return (KeyProtection) mProtectionParameterCaptor.getValue(); } + + private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception { + KeyGenerator keyGenerator = KeyGenerator.getInstance( + KEY_ALGORITHM, + ANDROID_KEY_STORE_PROVIDER); + keyGenerator.init(new KeyGenParameterSpec.Builder(TESTING_KEYSTORE_KEY_ALIAS, + KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) + .setBlockModes(KeyProperties.BLOCK_MODE_GCM) + .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) + .build()); + return (AndroidKeyStoreSecretKey) keyGenerator.generateKey(); + } + + class PlatformKeyManagerTestable extends PlatformKeyManager { + private IGateKeeperService mGateKeeperService; + + PlatformKeyManagerTestable( + Context context, + KeyStoreProxy keyStoreProxy, + RecoverableKeyStoreDb database, + IGateKeeperService gateKeeperService) { + super(context, keyStoreProxy, database); + mGateKeeperService = gateKeeperService; + } + + @Override + IGateKeeperService getGateKeeperService() { + return mGateKeeperService; + } + } } diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java index 4e43d002d4ae..8caa39dfc9e7 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java @@ -1035,6 +1035,15 @@ public class AppTimeLimitControllerTests { 0L, group.getUsageRemaining()); } + /** Verify that a limit of 0 is allowed for the special case of re-registering an observer. */ + @Test + public void testAppUsageLimitObserver_ZeroTimeLimitIsAllowed() { + addAppUsageLimitObserver(OBS_ID1, GROUP1, 0); + AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1); + assertNotNull("Observer wasn't added", group); + assertEquals("Usage remaining was not 0.", 0, group.getUsageRemaining()); + } + private void startUsage(String packageName) { mController.noteUsageStart(packageName, USER_ID); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index 2de4ae02828c..23bae8881aa1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions; + import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.anyInt; @@ -35,9 +36,7 @@ import android.content.Intent; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.SparseIntArray; -import android.util.proto.ProtoOutputStream; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto; diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 192915fe903c..8c36905d8422 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -24,6 +24,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM; @@ -34,6 +35,9 @@ import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING; +import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE; +import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; +import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -179,11 +183,14 @@ public class ActivityRecordTests extends ActivityTestsBase { .thenReturn(navBarPosition); mTask.getConfiguration().windowConfiguration.setAppBounds(taskBounds); mActivity.info.maxAspectRatio = aspectRatio; - mActivity.ensureActivityConfiguration( - 0 /* globalChanges */, false /* preserveWindow */); + ensureActivityConfiguration(); assertEquals(expectedActivityBounds, mActivity.getBounds()); } + private void ensureActivityConfiguration() { + mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); + } + @Test public void testCanBeLaunchedOnDisplay() { mService.mSupportsMultiWindow = true; @@ -277,7 +284,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; - mActivity.ensureActivityConfiguration(0, false, false); + ensureActivityConfiguration(); assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE, mActivity.mRelaunchReason); @@ -301,7 +308,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; - mActivity.ensureActivityConfiguration(0, false, false); + ensureActivityConfiguration(); assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE, mActivity.mRelaunchReason); @@ -323,7 +330,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; - mActivity.ensureActivityConfiguration(0, false, false); + ensureActivityConfiguration(); assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE, mActivity.mRelaunchReason); @@ -381,6 +388,21 @@ public class ActivityRecordTests extends ActivityTestsBase { } @Test + public void testShouldResume_stackVisibility() { + mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); + spyOn(mStack); + + doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null); + assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */)); + + doReturn(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null); + assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */)); + + doReturn(STACK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null); + assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */)); + } + + @Test public void testPushConfigurationWhenLaunchTaskBehind() throws Exception { mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); @@ -414,4 +436,46 @@ public class ActivityRecordTests extends ActivityTestsBase { stack.getDisplay().removeChild(stack); } } + + @Test + public void testFixedScreenConfigurationWhenMovingToDisplay() { + // Initialize different bounds on a new display. + final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); + newDisplay.setBounds(0, 0, 1000, 2000); + newDisplay.getConfiguration().densityDpi = 300; + + mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds()); + mTask.getConfiguration().densityDpi = 200; + when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn( + ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); + mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE; + mActivity.info.maxAspectRatio = 1.5f; + ensureActivityConfiguration(); + final Rect originalBounds = new Rect(mActivity.getBounds()); + final int originalDpi = mActivity.getConfiguration().densityDpi; + + // Move the non-resizable activity to the new display. + mStack.reparent(newDisplay, true /* onTop */, false /* displayRemoved */); + ensureActivityConfiguration(); + + assertEquals(originalBounds, mActivity.getBounds()); + assertEquals(originalDpi, mActivity.getConfiguration().densityDpi); + } + + @Test + public void testFixedScreenBoundsWhenDisplaySizeChanged() { + when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn( + ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds()); + mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; + mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE; + ensureActivityConfiguration(); + final Rect originalBounds = new Rect(mActivity.getBounds()); + + // Change the size of current display. + mStack.getDisplay().setBounds(0, 0, 1000, 2000); + ensureActivityConfiguration(); + + assertEquals(originalBounds, mActivity.getBounds()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index 986943aaf146..822700f48dd5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -37,6 +37,9 @@ import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; +import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE; +import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; +import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; @@ -321,12 +324,23 @@ public class ActivityStackTests extends ActivityTestsBase { assertFalse(homeStack.shouldBeVisible(null /* starting */)); assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); + assertEquals(STACK_VISIBILITY_INVISIBLE, homeStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + splitScreenPrimary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + splitScreenSecondary.getVisibility(null /* starting */)); // Home stack should be visible if one of the halves of split-screen is translucent. splitScreenPrimary.setIsTranslucent(true); assertTrue(homeStack.shouldBeVisible(null /* starting */)); assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, + homeStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + splitScreenPrimary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + splitScreenSecondary.getVisibility(null /* starting */)); final TestActivityStack splitScreenSecondary2 = createStackForShouldBeVisibleTest(mDefaultDisplay, @@ -336,12 +350,20 @@ public class ActivityStackTests extends ActivityTestsBase { splitScreenSecondary2.setIsTranslucent(false); assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */)); + assertEquals(STACK_VISIBILITY_INVISIBLE, + splitScreenSecondary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + splitScreenSecondary2.getVisibility(null /* starting */)); // First split-screen secondary should be visible behind another translucent split-screen // secondary. splitScreenSecondary2.setIsTranslucent(true); assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, + splitScreenSecondary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + splitScreenSecondary2.getVisibility(null /* starting */)); final TestActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */); @@ -352,6 +374,14 @@ public class ActivityStackTests extends ActivityTestsBase { assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */)); assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + assistantStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_INVISIBLE, + splitScreenPrimary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_INVISIBLE, + splitScreenSecondary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_INVISIBLE, + splitScreenSecondary2.getVisibility(null /* starting */)); // Split-screen stacks should be visible behind a translucent fullscreen stack. assistantStack.setIsTranslucent(true); @@ -359,6 +389,14 @@ public class ActivityStackTests extends ActivityTestsBase { assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + assistantStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, + splitScreenPrimary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, + splitScreenSecondary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, + splitScreenSecondary2.getVisibility(null /* starting */)); // Assistant stack shouldn't be visible behind translucent split-screen stack assistantStack.setIsTranslucent(false); @@ -369,6 +407,113 @@ public class ActivityStackTests extends ActivityTestsBase { assertFalse(assistantStack.shouldBeVisible(null /* starting */)); assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */)); + assertEquals(STACK_VISIBILITY_INVISIBLE, + assistantStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + splitScreenPrimary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_INVISIBLE, + splitScreenSecondary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + splitScreenSecondary2.getVisibility(null /* starting */)); + } + + @Test + public void testGetVisibility_FullscreenBehindTranslucent() { + final TestActivityStack bottomStack = + createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, + false /* translucent */); + final TestActivityStack translucentStack = + createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, + true /* translucent */); + + assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, + bottomStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + translucentStack.getVisibility(null /* starting */)); + } + + @Test + public void testGetVisibility_FullscreenBehindTranslucentAndOpaque() { + final TestActivityStack bottomStack = + createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, + false /* translucent */); + final TestActivityStack translucentStack = + createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, + true /* translucent */); + final TestActivityStack opaqueStack = + createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, + false /* translucent */); + + assertEquals(STACK_VISIBILITY_INVISIBLE, bottomStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_INVISIBLE, + translucentStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, opaqueStack.getVisibility(null /* starting */)); + } + + @Test + public void testGetVisibility_FullscreenBehindOpaqueAndTranslucent() { + final TestActivityStack bottomStack = + createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, + false /* translucent */); + final TestActivityStack opaqueStack = + createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, + false /* translucent */); + final TestActivityStack translucentStack = + createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, + true /* translucent */); + + assertEquals(STACK_VISIBILITY_INVISIBLE, bottomStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, + opaqueStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + translucentStack.getVisibility(null /* starting */)); + } + + @Test + public void testGetVisibility_FullscreenTranslucentBehindTranslucent() { + final TestActivityStack bottomTranslucentStack = + createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, + true /* translucent */); + final TestActivityStack translucentStack = + createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, + true /* translucent */); + + assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, + bottomTranslucentStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + translucentStack.getVisibility(null /* starting */)); + } + + @Test + public void testGetVisibility_FullscreenTranslucentBehindOpaque() { + final TestActivityStack bottomTranslucentStack = + createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, + true /* translucent */); + final TestActivityStack opaqueStack = + createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, + false /* translucent */); + + assertEquals(STACK_VISIBILITY_INVISIBLE, + bottomTranslucentStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, opaqueStack.getVisibility(null /* starting */)); + } + + @Test + public void testGetVisibility_FullscreenBehindTranslucentAndPip() { + final TestActivityStack bottomStack = + createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, + false /* translucent */); + final TestActivityStack translucentStack = + createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, + true /* translucent */); + final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); + + assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, + bottomStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, + translucentStack.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, pinnedStack.getVisibility(null /* starting */)); } @Test @@ -628,6 +773,14 @@ public class ActivityStackTests extends ActivityTestsBase { assertFalse(assistantStack.shouldBeVisible(null /* starting */)); } + private TestActivityStack createStandardStackForVisibilityTest(int windowingMode, + boolean translucent) { + final TestActivityStack stack = createStackForShouldBeVisibleTest(mDefaultDisplay, + windowingMode, ACTIVITY_TYPE_STANDARD, true /* onTop */); + stack.setIsTranslucent(translucent); + return stack; + } + @SuppressWarnings("TypeParameterUnusedInFormals") private <T extends ActivityStack> T createStackForShouldBeVisibleTest( ActivityDisplay display, int windowingMode, int activityType, boolean onTop) { diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 60f1ae26f5dd..392b0106c8e5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -61,7 +61,6 @@ import static org.mockito.ArgumentMatchers.eq; import android.app.ActivityOptions; import android.app.IApplicationThread; -import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -643,7 +642,7 @@ public class ActivityStarterTests extends ActivityTestsBase { UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, false, false, false, true, false); runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callingPackageIsDeviceOwner_notAborted", false, + "disallowed_callingPackageNameIsDeviceOwner_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, false, false, false, false, true); @@ -655,7 +654,7 @@ public class ActivityStarterTests extends ActivityTestsBase { boolean hasForegroundActivities, boolean callerIsRecents, boolean callerIsTempWhitelisted, boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges, - boolean isCallingPackageDeviceOwner) { + boolean isCallingPackageNameDeviceOwner) { // window visibility doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot) .isAnyNonToastWindowVisibleForUid(callingUid); @@ -681,9 +680,8 @@ public class ActivityStarterTests extends ActivityTestsBase { // caller is instrumenting with background activity starts privileges callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges, callerIsInstrumentingWithBackgroundActivityStartPrivileges); - // caller is device owner - DevicePolicyManager dpmMock = mService.getDevicePolicyManager(); - doReturn(isCallingPackageDeviceOwner).when(dpmMock).isDeviceOwnerApp(any()); + // calling package name is whitelisted + doReturn(isCallingPackageNameDeviceOwner).when(mService).isDeviceOwner(any()); final ActivityOptions options = spy(ActivityOptions.makeBasic()); ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK) diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index e27dd94b1a2c..abc0bd64c0e0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -42,7 +42,6 @@ import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.IApplicationThread; -import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -72,8 +71,10 @@ import com.android.server.am.PendingIntentController; import com.android.server.appop.AppOpsService; import com.android.server.firewall.IntentFirewall; import com.android.server.uri.UriGrantsManagerInternal; +import com.android.server.wm.utils.MockTracker; import org.junit.After; +import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; @@ -88,6 +89,8 @@ import java.util.List; class ActivityTestsBase { private static int sNextDisplayId = DEFAULT_DISPLAY + 1; + private static MockTracker sMockTracker; + @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = new DexmakerShareClassLoaderRule(); @@ -107,9 +110,17 @@ class ActivityTestsBase { @BeforeClass public static void setUpOnceBase() { + sMockTracker = new MockTracker(); + AttributeCache.init(getInstrumentation().getTargetContext()); } + @AfterClass + public static void tearDownOnceBase() { + sMockTracker.close(); + sMockTracker = null; + } + @Before public void setUpBase() { mTestInjector.setUp(); @@ -425,7 +436,6 @@ class ActivityTestsBase { spyOn(getLifecycleManager()); spyOn(getLockTaskController()); doReturn(mock(IPackageManager.class)).when(this).getPackageManager(); - doReturn(mock(DevicePolicyManager.class)).when(this).getDevicePolicyManager(); // allow background activity starts by default doReturn(true).when(this).isBackgroundActivityStartsEnabled(); doNothing().when(this).updateCpuStats(); @@ -657,12 +667,11 @@ class ActivityTestsBase { private static WindowManagerService sMockWindowManagerService; private static WindowManagerService prepareMockWindowManager() { - if (sMockWindowManagerService != null) { - return sMockWindowManagerService; + if (sMockWindowManagerService == null) { + sMockWindowManagerService = mock(WindowManagerService.class); } - final WindowManagerService service = mock(WindowManagerService.class); - service.mRoot = mock(RootWindowContainer.class); + sMockWindowManagerService.mRoot = mock(RootWindowContainer.class); doAnswer((InvocationOnMock invocationOnMock) -> { final Runnable runnable = invocationOnMock.<Runnable>getArgument(0); @@ -670,10 +679,9 @@ class ActivityTestsBase { runnable.run(); } return null; - }).when(service).inSurfaceTransaction(any()); + }).when(sMockWindowManagerService).inSurfaceTransaction(any()); - sMockWindowManagerService = service; - return service; + return sMockWindowManagerService; } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java index defe9811ebcf..a7520dcbcff9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java @@ -16,24 +16,29 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import android.graphics.Rect; import android.os.IBinder; +import android.view.Display; import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationDefinition; import android.view.RemoteAnimationTarget; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import org.junit.Before; import org.junit.Test; /** @@ -49,14 +54,20 @@ public class AppChangeTransitionTests extends WindowTestsBase { private Task mTask; private WindowTestUtils.TestAppWindowToken mToken; - @Before - public void setUp() throws Exception { - mStack = createTaskStackOnDisplay(mDisplayContent); + public void setUpOnDisplay(DisplayContent dc) { + mStack = createTaskStackOnDisplay(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, dc); mTask = createTaskInStack(mStack, 0 /* userId */); - mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent); + mToken = WindowTestUtils.createTestAppWindowToken(dc); mToken.mSkipOnParentChanged = false; mTask.addChild(mToken, 0); + + // Set a remote animator with snapshot disabled. Snapshots don't work in wmtests. + RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); + RemoteAnimationAdapter adapter = + new RemoteAnimationAdapter(new TestRemoteAnimationRunner(), 10, 1, false); + definition.addRemoteAnimation(TRANSIT_TASK_CHANGE_WINDOWING_MODE, adapter); + dc.registerRemoteAnimations(definition); } class TestRemoteAnimationRunner implements IRemoteAnimationRunner { @@ -85,14 +96,58 @@ public class AppChangeTransitionTests extends WindowTestsBase { @Test public void testModeChangeRemoteAnimatorNoSnapshot() { - RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); - RemoteAnimationAdapter adapter = - new RemoteAnimationAdapter(new TestRemoteAnimationRunner(), 10, 1, false); - definition.addRemoteAnimation(TRANSIT_TASK_CHANGE_WINDOWING_MODE, adapter); - mDisplayContent.registerRemoteAnimations(definition); + // setup currently defaults to no snapshot. + setUpOnDisplay(mDisplayContent); mTask.setWindowingMode(WINDOWING_MODE_FREEFORM); assertEquals(1, mDisplayContent.mChangingApps.size()); + + // Verify we are in a change transition, but without a snapshot. + // Though, the test will actually have crashed by now if a snapshot is attempted. + assertNull(mToken.getThumbnail()); + assertTrue(mToken.isInChangeTransition()); + + waitUntilHandlersIdle(); + mToken.removeImmediately(); + } + + @Test + public void testCancelPendingChangeOnRemove() { + // setup currently defaults to no snapshot. + setUpOnDisplay(mDisplayContent); + + mTask.setWindowingMode(WINDOWING_MODE_FREEFORM); + assertEquals(1, mDisplayContent.mChangingApps.size()); + assertTrue(mToken.isInChangeTransition()); + + // Removing the app-token from the display should clean-up the + // the change leash. + mDisplayContent.removeAppToken(mToken.token); + assertEquals(0, mDisplayContent.mChangingApps.size()); + assertFalse(mToken.isInChangeTransition()); + + waitUntilHandlersIdle(); + mToken.removeImmediately(); + } + + @Test + public void testNoChangeWhenMoveDisplay() { + mDisplayContent.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + final DisplayContent dc1 = createNewDisplay(Display.STATE_ON); + dc1.setWindowingMode(WINDOWING_MODE_FREEFORM); + setUpOnDisplay(dc1); + + assertEquals(WINDOWING_MODE_FREEFORM, mTask.getWindowingMode()); + + // Reparenting to a display with different windowing mode may trigger + // a change transition internally, but it should be cleaned-up once + // the display change is complete. + mStack.reparent(mDisplayContent.getDisplayId(), new Rect(), true); + + assertEquals(WINDOWING_MODE_FULLSCREEN, mTask.getWindowingMode()); + + // Make sure we're not waiting for a change animation (no leash) + assertFalse(mToken.isInChangeTransition()); assertNull(mToken.getThumbnail()); waitUntilHandlersIdle(); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index bc62de12373d..cd1320986972 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -44,6 +44,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; +import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; @@ -62,7 +63,6 @@ import org.junit.Test; * Build/Install/Run: * atest FrameworksServicesTests:AppWindowTokenTests */ -@FlakyTest(bugId = 68267650) @SmallTest @Presubmit public class AppWindowTokenTests extends WindowTestsBase { @@ -79,6 +79,7 @@ public class AppWindowTokenTests extends WindowTestsBase { mTask = createTaskInStack(mStack, 0 /* userId */); mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent); + mToken.mSkipOnParentChanged = false; mTask.addChild(mToken, 0); } @@ -141,6 +142,7 @@ public class AppWindowTokenTests extends WindowTestsBase { mToken.removeImmediately(); } + @FlakyTest(detail = "Promote to presubmit when shown to be stable.") @Test public void testLandscapeSeascapeRotationByApp() { // Some plumbing to get the service ready for rotation updates. @@ -166,6 +168,8 @@ public class AppWindowTokenTests extends WindowTestsBase { mDisplayContent.updateOrientationFromAppTokens( mDisplayContent.getRequestedOverrideConfiguration(), null /* freezeThisOneIfNeeded */, false /* forceUpdate */); + // In this test, DC will not get config update. Set the waiting flag to false. + mDisplayContent.mWaitingForConfig = false; mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */); assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation()); assertTrue(appWindow.mResizeReported); @@ -211,6 +215,48 @@ public class AppWindowTokenTests extends WindowTestsBase { } @Test + public void testSizeCompatBounds() { + // The real surface transaction is unnecessary. + mToken.setSkipPrepareSurfaces(true); + + final Rect fixedBounds = mToken.getRequestedOverrideConfiguration().windowConfiguration + .getBounds(); + fixedBounds.set(0, 0, 1200, 1600); + final Configuration newParentConfig = mTask.getConfiguration(); + + // Change the size of the container to two times smaller with insets. + newParentConfig.windowConfiguration.setAppBounds(200, 0, 800, 800); + final Rect containerAppBounds = newParentConfig.windowConfiguration.getAppBounds(); + final Rect containerBounds = newParentConfig.windowConfiguration.getBounds(); + containerBounds.set(0, 0, 600, 800); + mToken.onConfigurationChanged(newParentConfig); + + assertTrue(mToken.inSizeCompatMode()); + assertEquals(containerAppBounds, mToken.getBounds()); + assertEquals((float) containerAppBounds.width() / fixedBounds.width(), + mToken.getSizeCompatScale(), 0.0001f /* delta */); + + // Change the width of the container to two times bigger. + containerAppBounds.set(0, 0, 2400, 1600); + containerBounds.set(containerAppBounds); + mToken.onConfigurationChanged(newParentConfig); + + assertTrue(mToken.inSizeCompatMode()); + // Don't scale up, so the bounds keep the same as the fixed width. + assertEquals(fixedBounds.width(), mToken.getBounds().width()); + // Assert the position is horizontal center. + assertEquals((containerAppBounds.width() - fixedBounds.width()) / 2, + mToken.getBounds().left); + assertEquals(1f, mToken.getSizeCompatScale(), 0.0001f /* delta */); + + // Change the width of the container to fit the fixed bounds. + containerBounds.set(0, 0, 1200, 2000); + mToken.onConfigurationChanged(newParentConfig); + // Assert don't use fixed bounds because the region is enough. + assertFalse(mToken.inSizeCompatMode()); + } + + @Test @Presubmit public void testGetOrientation() { mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); @@ -300,6 +346,7 @@ public class AppWindowTokenTests extends WindowTestsBase { assertNoStartingWindow(mToken); } + @FlakyTest(detail = "Promote to presubmit when shown to be stable.") @Test public void testAddRemoveRace() { // There was once a race condition between adding and removing starting windows @@ -384,6 +431,7 @@ public class AppWindowTokenTests extends WindowTestsBase { // bottom one. tokenTop.setVisibility(false, false); tokenBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded(); + waitUntilHandlersIdle(); // Assert that the bottom window now has the starting window. assertNoStartingWindow(tokenTop); diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java index 2f90baaceb99..3f83caea613a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java @@ -71,7 +71,6 @@ import java.util.concurrent.TimeUnit; * atest WmTests:AssistDataRequesterTest */ @MediumTest -@FlakyTest(bugId = 113616538) public class AssistDataRequesterTest extends ActivityTestsBase { private static final String TAG = AssistDataRequesterTest.class.getSimpleName(); @@ -154,6 +153,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { .checkOpNoThrow(eq(OP_ASSIST_SCREENSHOT), anyInt(), anyString()); } + @FlakyTest(bugId = 124088319) @Test public void testRequestData() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -174,6 +174,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 0, 0, 0); } + @FlakyTest(bugId = 124088319) @Test public void testCurrentAppDisallow_expectNullCallbacks() throws Exception { setupMocks(!CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -184,6 +185,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 1, 0, 1); } + @FlakyTest(bugId = 124088319) @Test public void testProcessPendingData() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -241,6 +243,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 1, 0, 1); } + @FlakyTest(bugId = 124088319) @Test public void testDisallowAssistContextExtras_expectNullDataCallbacks() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -254,6 +257,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 1, 0, 1); } + @FlakyTest(bugId = 124088319) @Test public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -264,6 +268,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(5, 5, 0, 0); } + @FlakyTest(bugId = 124088319) @Test public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 3826fac22b05..a62bc713db40 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -51,17 +51,22 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; import android.annotation.SuppressLint; +import android.app.WindowConfiguration; import android.content.res.Configuration; import android.graphics.Rect; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.DisplayMetrics; import android.view.DisplayCutout; +import android.view.DisplayInfo; import android.view.Gravity; import android.view.MotionEvent; import android.view.Surface; +import android.view.ViewRootImpl; +import android.view.test.InsetsModeSession; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; @@ -628,6 +633,39 @@ public class DisplayContentTests extends WindowTestsBase { eq(activityRecord), anyBoolean(), eq(dc.getDisplayId())); } + @Test + public void testComputeImeParent_app() throws Exception { + try (final InsetsModeSession session = + new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) { + final DisplayContent dc = createNewDisplay(); + dc.mInputMethodTarget = createWindow(null, TYPE_BASE_APPLICATION, "app"); + assertEquals(dc.mInputMethodTarget.mAppToken.getSurfaceControl(), + dc.computeImeParent()); + } + } + + @Test + public void testComputeImeParent_app_notFullscreen() throws Exception { + try (final InsetsModeSession session = + new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) { + final DisplayContent dc = createNewDisplay(); + dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "app"); + dc.mInputMethodTarget.setWindowingMode( + WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + assertEquals(dc.getWindowingLayer(), dc.computeImeParent()); + } + } + + @Test + public void testComputeImeParent_noApp() throws Exception { + try (final InsetsModeSession session = + new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) { + final DisplayContent dc = createNewDisplay(); + dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "statusBar"); + assertEquals(dc.getWindowingLayer(), dc.computeImeParent()); + } + } + private boolean isOptionsPanelAtRight(int displayId) { return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT; } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java index 845a09f44b82..4279c4152836 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -28,6 +28,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; @@ -37,6 +39,7 @@ import static org.junit.Assert.assertThat; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; +import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; @@ -350,6 +353,48 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { } @Test + public void layoutWindowLw_withForwardInset_SoftInputAdjustResize() { + synchronized (mWm.mGlobalLock) { + mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE; + addWindow(mWindow); + + final int forwardedInsetBottom = 50; + mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom)); + mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); + mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); + + assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0); + assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrameLw(), + STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT + forwardedInsetBottom); + assertInsetByTopBottom(mWindow.getVisibleFrameLw(), + STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT + forwardedInsetBottom); + assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0); + assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0); + } + } + + @Test + public void layoutWindowLw_withForwardInset_SoftInputAdjustNothing() { + synchronized (mWm.mGlobalLock) { + mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_NOTHING; + addWindow(mWindow); + + final int forwardedInsetBottom = 50; + mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom)); + mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); + mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); + + assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0); + assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0); + assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0); + } + } + + @Test public void layoutHint_appWindow() { synchronized (mWm.mGlobalLock) { // Initialize DisplayFrames diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java index 0c363de36328..a0546d7623e7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java @@ -19,11 +19,11 @@ package com.android.server.wm; import static android.view.InsetsState.TYPE_TOP_BAR; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import android.graphics.Insets; import android.graphics.Rect; @@ -31,8 +31,6 @@ import android.platform.test.annotations.Presubmit; import android.view.InsetsSource; import android.view.InsetsState; -import org.junit.Before; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Before; diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index 11526a85aafb..bc62e8c5ab24 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -35,7 +35,6 @@ import androidx.test.filters.SmallTest; import org.junit.Test; @SmallTest -@FlakyTest(detail = "Promote once confirmed non-flaky") @Presubmit public class InsetsStateControllerTest extends WindowTestsBase { @@ -48,6 +47,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertNotNull(getController().getInsetsForDispatch(app).getSource(TYPE_TOP_BAR)); } + @FlakyTest(bugId = 69229402) @Test public void testStripForDispatch_own() { final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); @@ -57,6 +57,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertEquals(new InsetsState(), getController().getInsetsForDispatch(topBar)); } + @FlakyTest(bugId = 124088319) @Test public void testStripForDispatch_navBar() { final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); @@ -68,6 +69,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertEquals(new InsetsState(), getController().getInsetsForDispatch(navBar)); } + @FlakyTest(bugId = 124088319) @Test public void testBarControllingWinChanged() { final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); @@ -80,6 +82,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertEquals(2, controls.length); } + @FlakyTest(bugId = 124088319) @Test public void testControlRevoked() { final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); @@ -91,6 +94,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertNull(getController().getControlsForDispatch(app)); } + @FlakyTest(bugId = 124088319) @Test public void testControlRevoked_animation() { final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java index 86bf3dbb6973..b769fcecc469 100644 --- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java @@ -24,7 +24,6 @@ import android.app.ActivityOptions; import android.platform.test.annotations.Presubmit; import android.view.RemoteAnimationAdapter; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.testutils.OffsettableClock; diff --git a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java index c3d2f33b17dd..83274401f13d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java @@ -28,7 +28,6 @@ import static org.junit.Assert.assertTrue; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import org.junit.After; diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index 67ee4ad91d91..94def2bb7846 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -67,6 +67,7 @@ import org.junit.Before; import org.junit.Test; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -142,7 +143,8 @@ public class RootActivityContainerTests extends ActivityTestsBase { private static void ensureStackPlacement(ActivityStack stack, TaskRecord... tasks) { final ArrayList<TaskRecord> stackTasks = stack.getAllTasks(); - assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0); + assertEquals("Expecting " + Arrays.deepToString(tasks) + " got " + stackTasks, + stackTasks.size(), tasks != null ? tasks.length : 0); if (tasks == null) { return; diff --git a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java index dad6c952d7ab..71118521acf5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java @@ -21,7 +21,6 @@ import static org.junit.Assert.assertEquals; import android.app.ActivityOptions; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import org.junit.Test; diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java index dfdbf323365f..6cce9f088ee4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java @@ -167,7 +167,6 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase { verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L)); } - @FlakyTest(bugId = 74780584) @Test public void testDeferStartingAnimations() throws Exception { mSurfaceAnimationRunner.deferStartingAnimations(); diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java index 8c32e8cea93c..88ac96d74df6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java @@ -34,7 +34,6 @@ import android.view.SurfaceControl.Builder; import android.view.SurfaceControl.Transaction; import android.view.SurfaceSession; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.wm.SurfaceAnimator.Animatable; @@ -51,7 +50,7 @@ import org.mockito.MockitoAnnotations; * Test class for {@link SurfaceAnimatorTest}. * * Build/Install/Run: - * atest FrameworksServicesTests:SurfaceAnimatorTest + * atest WmTests:SurfaceAnimatorTest */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java index 12ed3c28161f..9dfeadf878e0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java @@ -29,8 +29,6 @@ import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.util.SparseBooleanArray; -import androidx.test.filters.FlakyTest; - import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java index 8c6ac23c9202..1e58e413dd1b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java @@ -43,7 +43,6 @@ import org.junit.Test; * Build/Install/Run: * atest FrameworksServicesTests:TaskPositioningControllerTests */ -@FlakyTest(bugId = 117924387) @SmallTest @Presubmit public class TaskPositioningControllerTests extends WindowTestsBase { @@ -90,6 +89,7 @@ public class TaskPositioningControllerTests extends WindowTestsBase { assertNull(mTarget.getDragWindowHandleLocked()); } + @FlakyTest(bugId = 69229402) @Test public void testHandleTapOutsideTask() { synchronized (mWm.mGlobalLock) { diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java index 4a734e5256f6..dcca3167c752 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java @@ -35,9 +35,11 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; import android.support.test.uiautomator.UiDevice; import android.text.TextUtils; +import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import com.android.internal.annotations.GuardedBy; @@ -76,6 +78,7 @@ public class TaskStackChangedListenerTest { } @Test + @Presubmit public void testTaskStackChanged_afterFinish() throws Exception { registerTaskStackChangedListener(new TaskStackListener() { @Override @@ -87,7 +90,8 @@ public class TaskStackChangedListenerTest { }); Context context = getInstrumentation().getContext(); - context.startActivity(new Intent(context, ActivityA.class)); + context.startActivity( + new Intent(context, ActivityA.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); UiDevice.getInstance(getInstrumentation()).waitForIdle(); synchronized (sLock) { assertTrue(sTaskStackChangedCalled); @@ -96,6 +100,7 @@ public class TaskStackChangedListenerTest { } @Test + @FlakyTest(bugId = 119893767) public void testTaskDescriptionChanged() throws Exception { final Object[] params = new Object[2]; final CountDownLatch latch = new CountDownLatch(1); @@ -124,6 +129,7 @@ public class TaskStackChangedListenerTest { } @Test + @FlakyTest(bugId = 119893767) public void testActivityRequestedOrientationChanged() throws Exception { final int[] params = new int[2]; final CountDownLatch latch = new CountDownLatch(1); @@ -146,6 +152,7 @@ public class TaskStackChangedListenerTest { * Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted. */ @Test + @FlakyTest(bugId = 119893767) public void testTaskChangeCallBacks() throws Exception { final Object[] params = new Object[2]; final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1); @@ -221,7 +228,8 @@ public class TaskStackChangedListenerTest { final ActivityMonitor monitor = new ActivityMonitor(activityClass.getName(), null, false); getInstrumentation().addMonitor(monitor); final Context context = getInstrumentation().getContext(); - context.startActivity(new Intent(context, activityClass)); + context.startActivity( + new Intent(context, activityClass).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); final TestActivity activity = (TestActivity) monitor.waitForActivityWithTimeout(1000); if (activity == null) { throw new RuntimeException("Timed out waiting for Activity"); diff --git a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java index b151fb7a613c..e540b3a9db89 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java @@ -61,7 +61,7 @@ import com.android.server.policy.WindowManagerPolicy; import org.mockito.invocation.InvocationOnMock; import org.mockito.quality.Strictness; -import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; /** * A Test utility class to create a mock {@link WindowManagerService} instance for tests. @@ -71,6 +71,8 @@ class TestSystemServices { private static WindowManagerService sService; private static TestWindowManagerPolicy sPolicy; + static AtomicBoolean sCurrentMessagesProcessed = new AtomicBoolean(false); + static void setUpWindowManagerService() { sMockitoSession = mockitoSession() .spyStatic(LockGuard.class) @@ -88,6 +90,7 @@ class TestSystemServices { sPolicy = null; sMockitoSession.finishMocking(); + sMockitoSession = null; } private static void setUpTestWindowService() { @@ -194,21 +197,23 @@ class TestSystemServices { } private static void waitHandlerIdle(Handler handler) { - if (!handler.hasMessagesOrCallbacks()) { - return; - } - final CountDownLatch latch = new CountDownLatch(1); - // Wait for delayed messages are processed. - handler.getLooper().getQueue().addIdleHandler(() -> { - if (handler.hasMessagesOrCallbacks()) { - return true; // keep idle handler. + synchronized (sCurrentMessagesProcessed) { + // Add a message to the handler queue and make sure it is fully processed before we move + // on. This makes sure all previous messages in the handler are fully processed vs. just + // popping them from the message queue. + sCurrentMessagesProcessed.set(false); + handler.post(() -> { + synchronized (sCurrentMessagesProcessed) { + sCurrentMessagesProcessed.set(true); + sCurrentMessagesProcessed.notifyAll(); + } + }); + while (!sCurrentMessagesProcessed.get()) { + try { + sCurrentMessagesProcessed.wait(); + } catch (InterruptedException e) { + } } - latch.countDown(); - return false; // remove idle handler. - }); - try { - latch.await(); - } catch (InterruptedException e) { } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java index 64ceb1bf8dff..d6608f1cabdc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java @@ -49,7 +49,7 @@ import org.junit.Test; * Test class to for {@link android.app.WindowConfiguration}. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowConfigurationTests + * atest WmTests:WindowConfigurationTests */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java index af8ccc981bae..fc7863524240 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java @@ -26,7 +26,6 @@ import static org.junit.Assert.assertTrue; import android.content.res.Configuration; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Test; @@ -35,7 +34,7 @@ import org.junit.Test; * Test class for {@link WindowContainerController}. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowContainerControllerTests + * atest WmTests:WindowContainerControllerTests */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index a9a76c2e9506..b93c994f4d8f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -47,7 +47,6 @@ import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; import android.view.SurfaceSession; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Test; @@ -59,11 +58,10 @@ import java.util.Comparator; * Test class for {@link WindowContainer}. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowContainerTests + * atest WmTests:WindowContainerTests */ @SmallTest @Presubmit -@FlakyTest(bugId = 74078662) public class WindowContainerTests extends WindowTestsBase { @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java index 0a4a8a43fbc5..fb30f8b2b107 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java @@ -449,8 +449,7 @@ public class WindowFrameTests extends WindowTestsBase { // Now simulate switch to fullscreen for letterboxed app. final int xInset = logicalWidth / 10; - final int yInset = logicalWidth / 10; - final Rect cf = new Rect(xInset, yInset, logicalWidth - xInset, logicalHeight - yInset); + final Rect cf = new Rect(xInset, 0, logicalWidth - xInset, logicalHeight); Configuration config = new Configuration(w.mAppToken.getRequestedOverrideConfiguration()); config.windowConfiguration.setBounds(cf); w.mAppToken.onRequestedOverrideConfigurationChanged(config); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 8876214b9636..3eb9085b68f6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -39,6 +39,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static org.hamcrest.Matchers.is; @@ -53,6 +54,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; import android.graphics.Insets; import android.graphics.Matrix; @@ -65,11 +67,13 @@ import android.view.SurfaceControl; import android.view.ViewRootImpl; import android.view.WindowManager; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.wm.utils.WmDisplayCutout; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -88,6 +92,7 @@ public class WindowStateTests extends WindowTestsBase { @BeforeClass public static void setUpOnce() { + // TODO: Make use of SettingsSession when it becomes feasible for this. sPreviousNewInsetsMode = ViewRootImpl.sNewInsetsMode; // To let the insets provider control the insets visibility, the insets mode has to be // NEW_INSETS_MODE_FULL. @@ -99,6 +104,15 @@ public class WindowStateTests extends WindowTestsBase { ViewRootImpl.sNewInsetsMode = sPreviousNewInsetsMode; } + @Before + public void setUp() { + // TODO: Let the insets source with new mode keep the visibility control, and remove this + // setup code. Now mTopFullscreenOpaqueWindowState will take back the control of insets + // visibility. + spyOn(mDisplayContent); + doNothing().when(mDisplayContent).layoutAndAssignWindowLayersIfNeeded(); + } + @Test public void testIsParentWindowHidden() { final WindowState parentWindow = createWindow(null, TYPE_APPLICATION, "parentWindow"); @@ -345,6 +359,7 @@ public class WindowStateTests extends WindowTestsBase { assertFalse(app.canAffectSystemUiFlags()); } + @FlakyTest(detail = "Promote to presubmit when shown to be stable.") @Test public void testVisibleWithInsetsProvider() throws Exception { final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar"); @@ -356,6 +371,7 @@ public class WindowStateTests extends WindowTestsBase { mDisplayContent.getInsetsStateController().onBarControllingWindowChanged(app); mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR) .onInsetsModified(app, new InsetsSource(TYPE_TOP_BAR)); + waitUntilHandlersIdle(); assertFalse(topBar.isVisible()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index a4948899c855..114eac911bd7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -151,6 +151,7 @@ public class WindowTestUtils { /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */ public static class TestAppWindowToken extends AppWindowToken { boolean mOnTop = false; + private boolean mSkipPrepareSurfaces; private Transaction mPendingTransactionOverride; boolean mSkipOnParentChanged = true; @@ -213,6 +214,17 @@ public class WindowTestUtils { return mOnTop; } + @Override + void prepareSurfaces() { + if (!mSkipPrepareSurfaces) { + super.prepareSurfaces(); + } + } + + void setSkipPrepareSurfaces(boolean ignore) { + mSkipPrepareSurfaces = ignore; + } + void setPendingTransaction(Transaction transaction) { mPendingTransactionOverride = transaction; } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 3cb28140e2ea..a83bf2af613e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -50,6 +50,7 @@ import android.view.IWindow; import android.view.WindowManager; import com.android.server.AttributeCache; +import com.android.server.wm.utils.MockTracker; import org.junit.After; import org.junit.AfterClass; @@ -77,6 +78,8 @@ class WindowTestsBase { private static int sNextDisplayId = DEFAULT_DISPLAY + 1; static int sNextStackId = 1000; + private static MockTracker sMockTracker; + /** Non-default display. */ DisplayContent mDisplayContent; DisplayInfo mDisplayInfo = new DisplayInfo(); @@ -109,11 +112,18 @@ class WindowTestsBase { TestSystemServices.setUpWindowManagerService(); + // MockTracker needs to be initialized after TestSystemServices because we don't want to + // track static mocks. + sMockTracker = new MockTracker(); + sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class); } @AfterClass - public static void tearDonwOnceBase() { + public static void tearDownOnceBase() { + sMockTracker.close(); + sMockTracker = null; + TestSystemServices.tearDownWindowManagerService(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index d55688665f70..4cdbea0bfb56 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -28,7 +28,6 @@ import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Test; @@ -37,7 +36,7 @@ import org.junit.Test; * Tests for the {@link WindowToken} class. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowTokenTests + * atest WmTests:WindowTokenTests */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java index b6b9a861a282..3c6e2405adff 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java @@ -34,8 +34,8 @@ import android.content.Context; import android.platform.test.annotations.Presubmit; import android.testing.DexmakerShareClassLoaderRule; import android.util.proto.ProtoOutputStream; +import android.view.Choreographer; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.internal.util.Preconditions; @@ -58,7 +58,7 @@ import java.nio.charset.StandardCharsets; * Test class for {@link WindowTracing}. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowTracingTest + * atest WmTests:WindowTracingTest */ @SmallTest @Presubmit @@ -74,6 +74,8 @@ public class WindowTracingTest { @Mock private WindowManagerService mWmMock; + @Mock + private Choreographer mChoreographer; private WindowTracing mWindowTracing; private File mFile; @@ -85,7 +87,9 @@ public class WindowTracingTest { mFile = testContext.getFileStreamPath("tracing_test.dat"); mFile.delete(); - mWindowTracing = new WindowTracing(mFile); + mWindowTracing = new WindowTracing(mFile, mWmMock, mChoreographer, + new WindowManagerGlobalLock()); + mWindowTracing.setContinuousMode(false /* continuous */, null /* pw */); } @After @@ -113,15 +117,14 @@ public class WindowTracingTest { @Test public void trace_discared_whenNotTracing() { - mWindowTracing.traceStateLocked("where", mWmMock); + mWindowTracing.logState("where"); verifyZeroInteractions(mWmMock); } @Test public void trace_dumpsWindowManagerState_whenTracing() throws Exception { mWindowTracing.startTrace(mock(PrintWriter.class)); - mWindowTracing.traceStateLocked("where", mWmMock); - + mWindowTracing.logState("where"); verify(mWmMock).writeToProtoLocked(any(), eq(WindowTraceLogLevel.TRIM)); } @@ -147,7 +150,7 @@ public class WindowTracingTest { WindowManagerTraceProto.WHERE, "TEST_WM_PROTO"); return null; }).when(mWmMock).writeToProtoLocked(any(), any()); - mWindowTracing.traceStateLocked("TEST_WHERE", mWmMock); + mWindowTracing.logState("TEST_WHERE"); mWindowTracing.stopTrace(mock(PrintWriter.class)); diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java index 3dcea75b8ae5..f3b8a6265eb3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java @@ -51,9 +51,8 @@ import java.util.LinkedList; * Tests for the {@link DisplayContent#assignChildLayers(SurfaceControl.Transaction)} method. * * Build/Install/Run: - * atest FrameworksServicesTests:ZOrderingTests + * atest WmTests:ZOrderingTests */ -@FlakyTest(bugId = 74078662) @SmallTest @Presubmit public class ZOrderingTests extends WindowTestsBase { @@ -207,6 +206,7 @@ public class ZOrderingTests extends WindowTestsBase { return createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, name); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeWithNoTarget() { mDisplayContent.mInputMethodTarget = null; @@ -224,6 +224,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeWithAppTarget() { final WindowState imeAppTarget = createWindow("imeAppTarget"); @@ -243,6 +244,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() { final WindowState imeAppTarget = createWindow("imeAppTarget"); @@ -269,6 +271,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() { final WindowState appBelowImeTarget = createWindow("appBelowImeTarget"); @@ -292,6 +295,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeNonAppImeTarget() { final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY, @@ -319,6 +323,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForStatusBarImeTarget() { mDisplayContent.mInputMethodTarget = mStatusBarWindow; @@ -333,6 +338,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testStackLayers() { final WindowState anyWindow1 = createWindow("anyWindow"); @@ -398,6 +404,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mediaOverlayChild, child); } + @FlakyTest(bugId = 124088319) @Test public void testDockedDividerPosition() { final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED, diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java new file mode 100644 index 000000000000..1ce463bbbd9e --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 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.wm.utils; + +import android.util.Log; + +import org.mockito.Mockito; +import org.mockito.MockitoFramework; +import org.mockito.internal.creation.settings.CreationSettings; +import org.mockito.listeners.MockCreationListener; +import org.mockito.mock.MockCreationSettings; + +import java.lang.reflect.Field; +import java.util.IdentityHashMap; + +/** + * An util class used to track mock creation, and reset them when closing. Note only one instance is + * allowed at anytime, as Mockito framework throws exception if there is already a listener of the + * same type registered. + */ +public class MockTracker implements MockCreationListener, AutoCloseable { + private static final String TAG = "MockTracker"; + + private static final Field SPIED_INSTANCE_FIELD; + + static { + try { + SPIED_INSTANCE_FIELD = CreationSettings.class.getDeclaredField("spiedInstance"); + SPIED_INSTANCE_FIELD.setAccessible(true); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + } + + private final MockitoFramework mMockitoFramework = Mockito.framework(); + + private final IdentityHashMap<Object, Void> mMocks = new IdentityHashMap<>(); + + public MockTracker() { + mMockitoFramework.addListener(this); + } + + @Override + public void onMockCreated(Object mock, MockCreationSettings settings) { + mMocks.put(mock, null); + clearSpiedInstanceIfNeeded(mock, settings); + } + + // HACK: Changing Mockito core implementation details. + // TODO(b/123984854): Remove this once there is a real fix. + private void clearSpiedInstanceIfNeeded(Object mock, MockCreationSettings settings) { + if (mock != settings.getSpiedInstance()) { + // Not a spyOn instance. + return; + } + if (!(settings instanceof CreationSettings)) { + throw new IllegalStateException("Unexpected type of settings: " + settings.getClass()); + } + try { + SPIED_INSTANCE_FIELD.set(settings, null); + Log.d(TAG, "Setting spiedInstance for " + mock + " to null."); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @Override + public void close() { + mMockitoFramework.removeListener(this); + + for (final Object mock : mMocks.keySet()) { + try { + Mockito.reset(mock); + } catch (Exception e) { + Log.e(TAG, "Failed to reset " + mock, e); + } + } + mMocks.clear(); + } +} diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java index 873ada05bc27..731cbf42eca7 100644 --- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java +++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java @@ -840,7 +840,8 @@ public class AppTimeLimitController { */ public void addAppUsageLimitObserver(int requestingUid, int observerId, String[] observed, long timeLimit, PendingIntent callbackIntent, @UserIdInt int userId) { - if (timeLimit < getMinTimeLimit()) { + // Allow the special case of the limit being 0, but with no callback. + if (timeLimit != 0L && timeLimit < getMinTimeLimit()) { throw new IllegalArgumentException("Time limit must be >= " + getMinTimeLimit()); } synchronized (mLock) { @@ -858,7 +859,7 @@ public class AppTimeLimitController { "Too many app usage observers added by uid " + requestingUid); } group = new AppUsageLimitGroup(user, observerApp, observerId, observed, timeLimit, - callbackIntent); + timeLimit == 0L ? null : callbackIntent); observerApp.appUsageLimitGroups.append(observerId, group); if (DEBUG) { diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index df2f45512465..af5278f222b8 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -1377,7 +1377,7 @@ public class UsageStatsService extends SystemService implements if (packages == null || packages.length == 0) { throw new IllegalArgumentException("Must specify at least one package"); } - if (callbackIntent == null) { + if (callbackIntent == null && timeLimitMs != 0L) { throw new NullPointerException("callbackIntent can't be null"); } final int callingUid = Binder.getCallingUid(); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 7cab43233f35..93f758c2a9ad 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -1307,13 +1307,15 @@ public class VoiceInteractionManagerService extends SystemService { List<String> roleHolders = mRm.getRoleHoldersAsUser(roleName, user); + int userId = user.getIdentifier(); if (roleHolders.isEmpty()) { - Settings.Secure.putString(getContext().getContentResolver(), - Settings.Secure.ASSISTANT, ""); - Settings.Secure.putString(getContext().getContentResolver(), - Settings.Secure.VOICE_INTERACTION_SERVICE, ""); - Settings.Secure.putString(getContext().getContentResolver(), - Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer(user)); + Settings.Secure.putStringForUser(getContext().getContentResolver(), + Settings.Secure.ASSISTANT, "", userId); + Settings.Secure.putStringForUser(getContext().getContentResolver(), + Settings.Secure.VOICE_INTERACTION_SERVICE, "", userId); + Settings.Secure.putStringForUser(getContext().getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer(user), + userId); } else { // Assistant is singleton role String pkg = roleHolders.get(0); @@ -1321,7 +1323,7 @@ public class VoiceInteractionManagerService extends SystemService { // Try to set role holder as VoiceInteractionService List<ResolveInfo> services = mPm.queryIntentServicesAsUser( new Intent(VoiceInteractionService.SERVICE_INTERFACE).setPackage(pkg), - PackageManager.GET_META_DATA, user.getIdentifier()); + PackageManager.GET_META_DATA, userId); for (ResolveInfo resolveInfo : services) { ServiceInfo serviceInfo = resolveInfo.serviceInfo; @@ -1339,12 +1341,14 @@ public class VoiceInteractionManagerService extends SystemService { voiceInteractionServiceInfo.getRecognitionService()) .flattenToShortString(); - Settings.Secure.putString(getContext().getContentResolver(), - Settings.Secure.ASSISTANT, serviceComponentName); - Settings.Secure.putString(getContext().getContentResolver(), - Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName); - Settings.Secure.putString(getContext().getContentResolver(), - Settings.Secure.VOICE_RECOGNITION_SERVICE, serviceRecognizerName); + Settings.Secure.putStringForUser(getContext().getContentResolver(), + Settings.Secure.ASSISTANT, serviceComponentName, userId); + Settings.Secure.putStringForUser(getContext().getContentResolver(), + Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName, + userId); + Settings.Secure.putStringForUser(getContext().getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE, serviceRecognizerName, + userId); return; } @@ -1352,19 +1356,19 @@ public class VoiceInteractionManagerService extends SystemService { // If no service could be found try to set assist activity final List<ResolveInfo> activities = mPm.queryIntentActivitiesAsUser( new Intent(Intent.ACTION_ASSIST).setPackage(pkg), - PackageManager.MATCH_DEFAULT_ONLY, user.getIdentifier()); + PackageManager.MATCH_DEFAULT_ONLY, userId); for (ResolveInfo resolveInfo : activities) { ActivityInfo activityInfo = resolveInfo.activityInfo; - Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.putStringForUser(getContext().getContentResolver(), Settings.Secure.ASSISTANT, - activityInfo.getComponentName().flattenToShortString()); - Settings.Secure.putString(getContext().getContentResolver(), - Settings.Secure.VOICE_INTERACTION_SERVICE, ""); - Settings.Secure.putString(getContext().getContentResolver(), + activityInfo.getComponentName().flattenToShortString(), userId); + Settings.Secure.putStringForUser(getContext().getContentResolver(), + Settings.Secure.VOICE_INTERACTION_SERVICE, "", userId); + Settings.Secure.putStringForUser(getContext().getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE, - getDefaultRecognizer(user)); + getDefaultRecognizer(user), userId); } } } diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java index 818ebd998f50..2fa388fa037e 100644 --- a/telecomm/java/android/telecom/CallScreeningService.java +++ b/telecomm/java/android/telecom/CallScreeningService.java @@ -75,7 +75,7 @@ import java.lang.annotation.RetentionPolicy; * * public void requestRole() { * RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE); - * Intent intent = roleManager.createRequestRoleIntent("android.app.role.CALL_SCREENING_APP"); + * Intent intent = roleManager.createRequestRoleIntent("android.app.role.CALL_SCREENING"); * startActivityForResult(intent, REQUEST_ID); * } * diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java index 7d1f8ce75919..6382acf0511d 100644 --- a/telecomm/java/android/telecom/Conference.java +++ b/telecomm/java/android/telecom/Conference.java @@ -19,6 +19,7 @@ package android.telecom; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.net.Uri; import android.os.Bundle; import android.os.SystemClock; @@ -571,6 +572,7 @@ public abstract class Conference extends Conferenceable { * @return The primary connection. * @hide */ + @TestApi @SystemApi public Connection getPrimaryConnection() { if (mUnmodifiableChildConnections == null || mUnmodifiableChildConnections.isEmpty()) { diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java index aac0956d4339..e43b2b715321 100644 --- a/telecomm/java/android/telecom/DefaultDialerManager.java +++ b/telecomm/java/android/telecom/DefaultDialerManager.java @@ -22,7 +22,6 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; @@ -163,9 +162,7 @@ public class DefaultDialerManager { final Intent dialIntentWithTelScheme = new Intent(Intent.ACTION_DIAL); dialIntentWithTelScheme.setData(Uri.fromParts(PhoneAccount.SCHEME_TEL, "", null)); - packageNames = filterByIntent(context, packageNames, dialIntentWithTelScheme, userId); - packageNames = requireInCallService(packageNames, userId, context); - return packageNames; + return filterByIntent(context, packageNames, dialIntentWithTelScheme, userId); } public static List<String> getInstalledDialerApplications(Context context) { @@ -223,35 +220,6 @@ public class DefaultDialerManager { return result; } - private static List<String> requireInCallService(List<String> packageNames, int userId, - Context context) { - if (packageNames == null || packageNames.isEmpty()) { - return new ArrayList<>(); - } - - final Intent intent = new Intent(InCallService.SERVICE_INTERFACE); - final List<ResolveInfo> resolveInfoList = context.getPackageManager() - .queryIntentServicesAsUser(intent, PackageManager.GET_META_DATA, userId); - final List<String> result = new ArrayList<>(); - final int length = resolveInfoList.size(); - for (int i = 0; i < length; i++) { - final ServiceInfo info = resolveInfoList.get(i).serviceInfo; - if (info == null || info.metaData == null) { - continue; - } - if (!info.metaData.getBoolean(TelecomManager.METADATA_IN_CALL_SERVICE_UI)) { - continue; - } - if (info.metaData.getBoolean(TelecomManager.METADATA_IN_CALL_SERVICE_CAR_MODE_UI)) { - continue; - } - if (packageNames.contains(info.packageName) && !result.contains(info.packageName)) { - result.add(info.packageName); - } - } - - return result; - } private static TelecomManager getTelecomManager(Context context) { return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java index f5f0af7e4666..cbcd40f15583 100644 --- a/telecomm/java/android/telecom/InCallService.java +++ b/telecomm/java/android/telecom/InCallService.java @@ -35,7 +35,6 @@ import com.android.internal.os.SomeArgs; import com.android.internal.telecom.IInCallAdapter; import com.android.internal.telecom.IInCallService; -import java.lang.String; import java.util.Collections; import java.util.List; @@ -212,7 +211,7 @@ import java.util.List; * {@link android.Manifest.permission.CALL_COMPANION_APP}.</li> * </ul> * <p> - * Your app should request to fill the role {@code android.app.role.CAR_MODE_DIALER_APP} in order to + * Your app should request to fill the role {@code android.app.role.CAR_MODE_DIALER} in order to * become the default (see <a href="#requestRole">above</a> for how to request your app fills this * role). * @@ -232,7 +231,7 @@ import java.util.List; * {@link android.Manifest.permission.CALL_COMPANION_APP}.</li> * </ul> * <p> - * Your app should request to fill the role {@code android.app.role.CALL_COMPANION_APP} in order to + * Your app should request to fill the role {@code android.app.role.CALL_COMPANION} in order to * become a call companion app (see <a href="#requestRole">above</a> for how to request your app * fills this role). */ diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 0e17a3373a65..e99a289729a4 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -22,6 +22,7 @@ import android.annotation.SuppressAutoDoc; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.app.role.RoleManagerCallback; import android.content.ComponentName; @@ -552,6 +553,7 @@ public class TelecomManager { * * @hide */ + @TestApi @SystemApi public static final int TTY_MODE_OFF = 0; @@ -561,6 +563,7 @@ public class TelecomManager { * * @hide */ + @TestApi @SystemApi public static final int TTY_MODE_FULL = 1; @@ -571,6 +574,7 @@ public class TelecomManager { * * @hide */ + @TestApi @SystemApi public static final int TTY_MODE_HCO = 2; @@ -581,6 +585,7 @@ public class TelecomManager { * * @hide */ + @TestApi @SystemApi public static final int TTY_MODE_VCO = 3; @@ -819,6 +824,7 @@ public class TelecomManager { * @hide */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @TestApi @SystemApi public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) { try { @@ -1521,6 +1527,7 @@ public class TelecomManager { * @hide */ @SystemApi + @TestApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public @TtyMode int getCurrentTtyMode() { try { @@ -1969,6 +1976,7 @@ public class TelecomManager { * @hide */ @SystemApi + @TestApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall() { try { diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index 4539ab3dc310..a1c32b5f80a3 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -2717,6 +2717,41 @@ public final class Telephony { Uri RCS_EVENT_QUERY_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY, RCS_EVENT_QUERY_URI_PATH); } + + /** + * Allows RCS specific canonical address handling. + */ + interface RcsCanonicalAddressHelper { + /** + * Returns the canonical address ID for a canonical address, if now row exists, this + * will add a row and return its ID. This helper works against the same table used by + * the SMS and MMS threads, but is accessible only by the phone process for use by RCS + * message storage. + * + * @throws IllegalArgumentException if unable to retrieve or create the canonical + * address entry. + */ + static long getOrCreateCanonicalAddressId( + ContentResolver contentResolver, String canonicalAddress) { + + Uri.Builder uriBuilder = CONTENT_AND_AUTHORITY.buildUpon(); + uriBuilder.appendPath("canonical-address"); + uriBuilder.appendQueryParameter("address", canonicalAddress); + Uri uri = uriBuilder.build(); + + try (Cursor cursor = contentResolver.query(uri, null, null, null)) { + if (cursor != null && cursor.moveToFirst()) { + return cursor.getLong(cursor.getColumnIndex(CanonicalAddressesColumns._ID)); + } else { + Rlog.e(TAG, "getOrCreateCanonicalAddressId returned no rows"); + } + } + + Rlog.e(TAG, "getOrCreateCanonicalAddressId failed"); + throw new IllegalArgumentException( + "Unable to find or allocate a canonical address ID"); + } + } } /** diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java index 9c64cf6ddd8f..75165afe097e 100644 --- a/telephony/java/android/telephony/AccessNetworkConstants.java +++ b/telephony/java/android/telephony/AccessNetworkConstants.java @@ -54,8 +54,15 @@ public final class AccessNetworkConstants { */ @SystemApi public static final class TransportType { + /** + * Invalid transport type. + * @hide + */ + public static final int INVALID = -1; + /** Wireless Wide Area Networks (i.e. Cellular) */ public static final int WWAN = 1; + /** Wireless Local Area Networks (i.e. Wifi) */ public static final int WLAN = 2; @@ -65,6 +72,7 @@ public final class AccessNetworkConstants { /** @hide */ public static String toString(int type) { switch (type) { + case INVALID: return "INVALID"; case WWAN: return "WWAN"; case WLAN: return "WLAN"; default: return Integer.toString(type); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 068b68eeb73b..0c63b60b030d 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -2589,6 +2589,16 @@ public class CarrierConfigManager { } } + /** + * An int array containing CDMA enhanced roaming indicator values for Home (non-roaming) network. + * The default values come from 3GPP2 C.R1001 table 8.1-1. + * Enhanced Roaming Indicator Number Assignments + * + * @hide + */ + public static final String KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY = + "cdma_enhanced_roaming_indicator_for_home_network_int_array"; + /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -2966,6 +2976,10 @@ public class CarrierConfigManager { /* Default value is 10 seconds. */ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG, 10000); sDefaults.putAll(Gps.getDefaults()); + sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY, + new int[] { + 1 /* Roaming Indicator Off */ + }); } /** diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java index 37847aef9167..d47b55ca4372 100644 --- a/telephony/java/android/telephony/CarrierRestrictionRules.java +++ b/telephony/java/android/telephony/CarrierRestrictionRules.java @@ -27,6 +27,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * Contains the list of carrier restrictions. @@ -93,6 +94,9 @@ public final class CarrierRestrictionRules implements Parcelable { value = {CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED, CARRIER_RESTRICTION_DEFAULT_ALLOWED}) public @interface CarrierRestrictionDefault {} + /* Wild character for comparison */ + private static final char WILD_CHARACTER = '?'; + private List<CarrierIdentifier> mAllowedCarriers; private List<CarrierIdentifier> mExcludedCarriers; @CarrierRestrictionDefault @@ -166,6 +170,124 @@ public final class CarrierRestrictionRules implements Parcelable { } /** + * Tests an array of carriers with the carrier restriction configuration. The list of carrier + * ids passed as argument does not need to be the same as currently present in the device. + * + * @param carrierIds list of {@link CarrierIdentifier}, one for each SIM slot on the device + * @return a list of boolean with the same size as input, indicating if each + * {@link CarrierIdentifier} is allowed or not. + */ + public List<Boolean> isCarrierIdentifiersAllowed(@NonNull List<CarrierIdentifier> carrierIds) { + ArrayList<Boolean> result = new ArrayList<>(carrierIds.size()); + + // First calculate the result for each slot independently + for (int i = 0; i < carrierIds.size(); i++) { + boolean inAllowedList = isCarrierIdInList(carrierIds.get(i), mAllowedCarriers); + boolean inExcludedList = isCarrierIdInList(carrierIds.get(i), mExcludedCarriers); + if (mCarrierRestrictionDefault == CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED) { + result.add((inAllowedList && !inExcludedList) ? true : false); + } else { + result.add((inExcludedList && !inAllowedList) ? false : true); + } + } + // Apply the multi-slot policy, if needed. + if (mMultiSimPolicy == MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT) { + for (boolean b : result) { + if (b) { + result.replaceAll(x -> true); + break; + } + } + } + return result; + } + + /** + * Indicates if a certain carrier {@code id} is present inside a {@code list} + * + * @return true if the carrier {@code id} is present, false otherwise + */ + private static boolean isCarrierIdInList(CarrierIdentifier id, List<CarrierIdentifier> list) { + for (CarrierIdentifier listItem : list) { + // Compare MCC and MNC + if (!patternMatch(id.getMcc(), listItem.getMcc()) + || !patternMatch(id.getMnc(), listItem.getMnc())) { + continue; + } + + // Compare SPN. Comparison is on the complete strings, case insensitive and with wild + // characters. + String listItemValue = convertNullToEmpty(listItem.getSpn()); + String idValue = convertNullToEmpty(id.getSpn()); + if (!listItemValue.isEmpty()) { + if (!patternMatch(idValue, listItemValue)) { + continue; + } + } + + // The IMSI of the configuration can be shorter than actual IMSI in the SIM card. + listItemValue = convertNullToEmpty(listItem.getImsi()); + idValue = convertNullToEmpty(id.getImsi()); + if (!patternMatch( + idValue.substring(0, Math.min(idValue.length(), listItemValue.length())), + listItemValue)) { + continue; + } + + // The GID1 of the configuration can be shorter than actual GID1 in the SIM card. + listItemValue = convertNullToEmpty(listItem.getGid1()); + idValue = convertNullToEmpty(id.getGid1()); + if (!patternMatch( + idValue.substring(0, Math.min(idValue.length(), listItemValue.length())), + listItemValue)) { + continue; + } + + // The GID2 of the configuration can be shorter than actual GID2 in the SIM card. + listItemValue = convertNullToEmpty(listItem.getGid2()); + idValue = convertNullToEmpty(id.getGid2()); + if (!patternMatch( + idValue.substring(0, Math.min(idValue.length(), listItemValue.length())), + listItemValue)) { + continue; + } + + // Valid match was found in the list + return true; + } + return false; + } + + private static String convertNullToEmpty(String value) { + return Objects.toString(value, ""); + } + + /** + * Performs a case insensitive string comparison against a given pattern. The character '?' + * is used in the pattern as wild character in the comparison. The string must have the same + * length as the pattern. + * + * @param str string to match + * @param pattern string containing the pattern + * @return true in case of match, false otherwise + */ + private static boolean patternMatch(String str, String pattern) { + if (str.length() != pattern.length()) { + return false; + } + String lowerCaseStr = str.toLowerCase(); + String lowerCasePattern = pattern.toLowerCase(); + + for (int i = 0; i < lowerCasePattern.length(); i++) { + if (lowerCasePattern.charAt(i) != lowerCaseStr.charAt(i) + && lowerCasePattern.charAt(i) != WILD_CHARACTER) { + return false; + } + } + return true; + } + + /** * {@link Parcelable#writeToParcel} */ @Override diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java index 30e641d61143..a4207c99ce4d 100644 --- a/telephony/java/android/telephony/CellSignalStrengthGsm.java +++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java @@ -63,6 +63,10 @@ public final class CellSignalStrengthGsm extends CellSignalStrength implements P public CellSignalStrengthGsm(android.hardware.radio.V1_0.GsmSignalStrength gsm) { // Convert from HAL values as part of construction. this(getRssiDbmFromAsu(gsm.signalStrength), gsm.bitErrorRate, gsm.timingAdvance); + + if (mRssi == CellInfo.UNAVAILABLE) { + setDefaultValues(); + } } /** @hide */ diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java index 6f52b853d23b..5ae89b0f8b3d 100644 --- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java @@ -72,6 +72,10 @@ public final class CellSignalStrengthTdscdma extends CellSignalStrength implemen // Convert from HAL values as part of construction. this(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, tdscdma.rscp != CellInfo.UNAVAILABLE ? -tdscdma.rscp : tdscdma.rscp); + + if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) { + setDefaultValues(); + } } /** @hide */ @@ -79,6 +83,10 @@ public final class CellSignalStrengthTdscdma extends CellSignalStrength implemen // Convert from HAL values as part of construction. this(getRssiDbmFromAsu(tdscdma.signalStrength), tdscdma.bitErrorRate, getRscpDbmFromAsu(tdscdma.rscp)); + + if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) { + setDefaultValues(); + } } /** @hide */ diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java index 0760407171ae..efa3647f0e9b 100644 --- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java @@ -92,8 +92,12 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements /** @hide */ public CellSignalStrengthWcdma(android.hardware.radio.V1_0.WcdmaSignalStrength wcdma) { // Convert from HAL values as part of construction. - this(getRssiDbmFromAsu(wcdma.signalStrength), - wcdma.bitErrorRate, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE); + this(getRssiDbmFromAsu(wcdma.signalStrength), wcdma.bitErrorRate, + CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE); + + if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) { + setDefaultValues(); + } } /** @hide */ @@ -103,6 +107,10 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements wcdma.base.bitErrorRate, getRscpDbmFromAsu(wcdma.rscp), getEcNoDbFromAsu(wcdma.ecno)); + + if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) { + setDefaultValues(); + } } /** @hide */ diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index fea1b7b08a20..2c9ba1dfff7b 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -45,7 +45,8 @@ import java.util.concurrent.Executor; * <p> * Override the methods for the state that you wish to receive updates for, and * pass your PhoneStateListener object, along with bitwise-or of the LISTEN_ - * flags to {@link TelephonyManager#listen TelephonyManager.listen()}. + * flags to {@link TelephonyManager#listen TelephonyManager.listen()}. Methods are + * called when the state changes, os well as once on initial registration. * <p> * Note that access to some telephony information is * permission-protected. Your application won't receive updates for protected diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java index e40bae18d4f0..099015fd3d0e 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -187,15 +187,7 @@ public class SmsMessage { int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); String format = (PHONE_TYPE_CDMA == activePhone) ? SmsConstants.FORMAT_3GPP2 : SmsConstants.FORMAT_3GPP; - message = createFromPdu(pdu, format); - - if (null == message || null == message.mWrappedSmsMessage) { - // decoding pdu failed based on activePhone type, must be other format - format = (PHONE_TYPE_CDMA == activePhone) ? - SmsConstants.FORMAT_3GPP : SmsConstants.FORMAT_3GPP2; - message = createFromPdu(pdu, format); - } - return message; + return createFromPdu(pdu, format); } /** @@ -211,11 +203,18 @@ public class SmsMessage { * {@link android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION} intent */ public static SmsMessage createFromPdu(byte[] pdu, String format) { - SmsMessageBase wrappedMessage; + return createFromPdu(pdu, format, true); + } + + private static SmsMessage createFromPdu(byte[] pdu, String format, + boolean fallbackToOtherFormat) { if (pdu == null) { Rlog.i(LOG_TAG, "createFromPdu(): pdu is null"); return null; } + SmsMessageBase wrappedMessage; + String otherFormat = SmsConstants.FORMAT_3GPP2.equals(format) ? SmsConstants.FORMAT_3GPP : + SmsConstants.FORMAT_3GPP2; if (SmsConstants.FORMAT_3GPP2.equals(format)) { wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu); } else if (SmsConstants.FORMAT_3GPP.equals(format)) { @@ -228,8 +227,12 @@ public class SmsMessage { if (wrappedMessage != null) { return new SmsMessage(wrappedMessage); } else { - Rlog.e(LOG_TAG, "createFromPdu(): wrappedMessage is null"); - return null; + if (fallbackToOtherFormat) { + return createFromPdu(pdu, otherFormat, false); + } else { + Rlog.e(LOG_TAG, "createFromPdu(): wrappedMessage is null"); + return null; + } } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index dfe36efcd5d1..3a4d33c18485 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -59,6 +59,7 @@ import android.util.DisplayMetrics; import android.util.Log; import com.android.internal.telephony.IOnSubscriptionsChangedListener; +import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; import com.android.internal.telephony.ITelephonyRegistry; import com.android.internal.telephony.PhoneConstants; @@ -72,6 +73,7 @@ import java.util.List; import java.util.Locale; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import java.util.stream.Collectors; /** @@ -2047,6 +2049,8 @@ public class SubscriptionManager { putPhoneIdAndSubIdExtra(intent, phoneId, subIds[0]); } else { logd("putPhoneIdAndSubIdExtra: no valid subs"); + intent.putExtra(PhoneConstants.PHONE_KEY, phoneId); + intent.putExtra(PhoneConstants.SLOT_KEY, phoneId); } } @@ -2571,17 +2575,35 @@ public class SubscriptionManager { * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}, it means * it's unset and {@link SubscriptionManager#getDefaultDataSubscriptionId()} * is used to determine which modem is preferred. + * @param needValidation whether validation is needed before switch happens. + * @param executor The executor of where the callback will execute. + * @param callback Callback will be triggered once it succeeds or failed. + * See {@link TelephonyManager.SetOpportunisticSubscriptionResult} + * for more details. Pass null if don't care about the result. + * * @hide * */ + @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) - public void setPreferredDataSubscriptionId(int subId) { + public void setPreferredDataSubscriptionId(int subId, boolean needValidation, + @NonNull @CallbackExecutor Executor executor, Consumer<Integer> callback) { if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId); try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); - if (iSub != null) { - iSub.setPreferredDataSubscriptionId(subId); - } + if (iSub == null) return; + + ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() { + @Override + public void onComplete(int result) { + Binder.withCleanCallingIdentity(() -> executor.execute(() -> { + if (callback != null) { + callback.accept(result); + } + })); + } + }; + iSub.setPreferredDataSubscriptionId(subId, needValidation, callbackStub); } catch (RemoteException ex) { // ignore it } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index eab536f94290..6690bd0f10b5 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -4920,12 +4920,13 @@ public class TelephonyManager { * * <p>Apps targeting {@link android.os.Build.VERSION_CODES#Q Android Q} or higher will no * longer trigger a refresh of the cached CellInfo by invoking this API. Instead, those apps - * will receive the latest cached results. Apps targeting + * will receive the latest cached results, which may not be current. Apps targeting * {@link android.os.Build.VERSION_CODES#Q Android Q} or higher that wish to request updated * CellInfo should call - * {android.telephony.TelephonyManager#requestCellInfoUpdate requestCellInfoUpdate()} and - * listen for responses via {@link android.telephony.PhoneStateListener#onCellInfoChanged - * onCellInfoChanged()}. + * {@link android.telephony.TelephonyManager#requestCellInfoUpdate requestCellInfoUpdate()}; + * however, in all cases, updates will be rate-limited and are not guaranteed. To determine the + * recency of CellInfo data, callers should check + * {@link android.telephony.CellInfo#getTimeStamp CellInfo#getTimeStamp()}. * * <p>This method returns valid data for devices with * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY FEATURE_TELEPHONY}. In cases @@ -10093,6 +10094,29 @@ public class TelephonyManager { return false; } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"SET_OPPORTUNISTIC_SUB"}, value = { + SET_OPPORTUNISTIC_SUB_SUCCESS, + SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED, + SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER}) + public @interface SetOpportunisticSubscriptionResult {} + + /** + * No error. Operation succeeded. + */ + public static final int SET_OPPORTUNISTIC_SUB_SUCCESS = 0; + + /** + * Validation failed when trying to switch to preferred subscription. + */ + public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1; + + /** + * The parameter passed in is invalid. + */ + public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2; + /** * Set preferred opportunistic data subscription id. * @@ -10308,11 +10332,14 @@ public class TelephonyManager { /** * Get whether reboot is required or not after making changes to modem configurations. - * @Return {@code True} if reboot is required after making changes to modem configurations, - * otherwise return {@code False}. + * The modem configuration change refers to switching from single SIM configuration to DSDS + * or the other way around. + * @Return {@code true} if reboot is required after making changes to modem configurations, + * otherwise return {@code false}. * * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isRebootRequiredForModemConfigChange() { try { diff --git a/telephony/java/android/telephony/ims/Rcs1To1Thread.java b/telephony/java/android/telephony/ims/Rcs1To1Thread.java index 3255f8d0786d..d4a78ffb77db 100644 --- a/telephony/java/android/telephony/ims/Rcs1To1Thread.java +++ b/telephony/java/android/telephony/ims/Rcs1To1Thread.java @@ -22,8 +22,6 @@ import android.annotation.WorkerThread; * Rcs1To1Thread represents a single RCS conversation thread with a total of two * {@link RcsParticipant}s. Please see Section 5 (1-to-1 Messaging) - GSMA RCC.71 (RCS Universal * Profile Service Definition Document) - * - * @hide - TODO: make public */ public class Rcs1To1Thread extends RcsThread { private int mThreadId; diff --git a/telephony/java/android/telephony/ims/RcsEvent.java b/telephony/java/android/telephony/ims/RcsEvent.java index ef359a124d47..df62277f9ac1 100644 --- a/telephony/java/android/telephony/ims/RcsEvent.java +++ b/telephony/java/android/telephony/ims/RcsEvent.java @@ -19,8 +19,6 @@ import android.os.Parcel; /** * The base class for events that can happen on {@link RcsParticipant}s and {@link RcsThread}s. - * - * @hide - TODO: make public */ public abstract class RcsEvent { /** diff --git a/telephony/java/android/telephony/ims/RcsEventQueryParams.java b/telephony/java/android/telephony/ims/RcsEventQueryParams.java index 5249becd476e..9dbfe4393213 100644 --- a/telephony/java/android/telephony/ims/RcsEventQueryParams.java +++ b/telephony/java/android/telephony/ims/RcsEventQueryParams.java @@ -37,8 +37,6 @@ import java.security.InvalidParameterException; * The parameters to pass into * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} in order to select a * subset of {@link RcsEvent}s present in the message store. - * - * @hide - TODO: make public */ public final class RcsEventQueryParams implements Parcelable { /** @@ -152,8 +150,8 @@ public final class RcsEventQueryParams implements Parcelable { } /** - * @return Returns the type of {@link RcsEvent}s that this {@link RcsEventQueryParams} is - * set to query for. + * @return Returns the number of {@link RcsEvent}s to be returned from the query. A value of + * 0 means there is no set limit. */ public int getLimit() { return mLimit; diff --git a/telephony/java/android/telephony/ims/RcsEventQueryResult.java b/telephony/java/android/telephony/ims/RcsEventQueryResult.java index f8d57fa5c09d..c30e4ccd7aa2 100644 --- a/telephony/java/android/telephony/ims/RcsEventQueryResult.java +++ b/telephony/java/android/telephony/ims/RcsEventQueryResult.java @@ -25,8 +25,6 @@ import java.util.List; * The result of a {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} * call. This class allows getting the token for querying the next batch of events in order to * prevent handling large amounts of data at once. - * - * @hide - TODO: make public */ public final class RcsEventQueryResult implements Parcelable { private RcsQueryContinuationToken mContinuationToken; diff --git a/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java b/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java index 663def5df50f..14af8ea63a67 100644 --- a/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java +++ b/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java @@ -24,8 +24,6 @@ import android.os.Parcelable; * Pass an instance of this class to * {@link RcsMessage#insertFileTransfer(RcsFileTransferCreationParams)} create an * {@link RcsFileTransferPart} and save it into storage. - * - * @hide - TODO: make public */ public final class RcsFileTransferCreationParams implements Parcelable { private String mRcsFileTransferSessionId; diff --git a/telephony/java/android/telephony/ims/RcsFileTransferPart.java b/telephony/java/android/telephony/ims/RcsFileTransferPart.java index 1ce799919e09..9531c2e2f981 100644 --- a/telephony/java/android/telephony/ims/RcsFileTransferPart.java +++ b/telephony/java/android/telephony/ims/RcsFileTransferPart.java @@ -26,8 +26,6 @@ import java.lang.annotation.RetentionPolicy; /** * A part of a composite {@link RcsMessage} that holds a file transfer. Please see Section 7 * (File Transfer) - GSMA RCC.71 (RCS Universal Profile Service Definition Document) - * - * @hide - TODO: make public */ public class RcsFileTransferPart { /** diff --git a/telephony/java/android/telephony/ims/RcsGroupThread.java b/telephony/java/android/telephony/ims/RcsGroupThread.java index 2c42494ee924..6e17bc2a685f 100644 --- a/telephony/java/android/telephony/ims/RcsGroupThread.java +++ b/telephony/java/android/telephony/ims/RcsGroupThread.java @@ -29,8 +29,6 @@ import java.util.Set; * RcsGroupThread represents a single RCS conversation thread where {@link RcsParticipant}s can join * or leave. Please see Section 6 (Group Chat) - GSMA RCC.71 (RCS Universal Profile Service * Definition Document) - * - * @hide - TODO: make public */ public class RcsGroupThread extends RcsThread { /** diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java index bc61877a81d6..609b1740a536 100644 --- a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java +++ b/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java @@ -20,8 +20,6 @@ import android.os.Parcel; /** * An event that happened on an {@link RcsGroupThread}. - * - * @hide - TODO: make public */ public abstract class RcsGroupThreadEvent extends RcsEvent { private final int mRcsGroupThreadId; diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java index 74af9738e976..e768439d6cfa 100644 --- a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java +++ b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java @@ -24,8 +24,6 @@ import android.os.Parcelable; /** * An event that indicates an {@link RcsGroupThread}'s icon was changed. Please see R6-2-5 - GSMA * RCC.71 (RCS Universal Profile Service Definition Document) - * - * @hide - TODO: make public */ public final class RcsGroupThreadIconChangedEvent extends RcsGroupThreadEvent implements Parcelable { diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java index 06f4d5b10bb4..02030bc6a2ec 100644 --- a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java +++ b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java @@ -23,8 +23,6 @@ import android.os.Parcelable; /** * An event that indicates an {@link RcsGroupThread}'s name was changed. Please see R6-2-5 - GSMA * RCC.71 (RCS Universal Profile Service Definition Document) - * - * @hide - TODO: make public */ public final class RcsGroupThreadNameChangedEvent extends RcsGroupThreadEvent implements Parcelable { diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java index 493270795e01..0d1a5730f0a0 100644 --- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java +++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java @@ -22,8 +22,6 @@ import android.os.Parcelable; /** * An event that indicates an RCS participant has joined an {@link RcsThread}. Please see US6-3 - * GSMA RCC.71 (RCS Universal Profile Service Definition Document) - * - * @hide - TODO: make public */ public final class RcsGroupThreadParticipantJoinedEvent extends RcsGroupThreadEvent implements Parcelable { diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java index 970a046e1105..cd525086749a 100644 --- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java +++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java @@ -22,8 +22,6 @@ import android.os.Parcelable; /** * An event that indicates an RCS participant has left an {@link RcsThread}. Please see US6-23 - * GSMA RCC.71 (RCS Universal Profile Service Definition Document) - * - * @hide - TODO: make public */ public final class RcsGroupThreadParticipantLeftEvent extends RcsGroupThreadEvent implements Parcelable { diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessage.java b/telephony/java/android/telephony/ims/RcsIncomingMessage.java index f3b7815c2453..61911abd00c5 100644 --- a/telephony/java/android/telephony/ims/RcsIncomingMessage.java +++ b/telephony/java/android/telephony/ims/RcsIncomingMessage.java @@ -19,8 +19,6 @@ import android.annotation.WorkerThread; /** * This is a single instance of a message received over RCS. - * - * @hide - TODO: make public */ public class RcsIncomingMessage extends RcsMessage { /** diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java index 64b2339905eb..61dedbc1578a 100644 --- a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java +++ b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java @@ -24,8 +24,6 @@ import android.os.Parcelable; * {@link RcsIncomingMessageCreationParams} is a collection of parameters that should be passed * into {@link RcsThread#addIncomingMessage(RcsIncomingMessageCreationParams)} to generate an * {@link RcsIncomingMessage} on that {@link RcsThread} - * - * @hide - TODO: make public */ public final class RcsIncomingMessageCreationParams extends RcsMessageCreationParams implements Parcelable { diff --git a/telephony/java/android/telephony/ims/RcsManager.java b/telephony/java/android/telephony/ims/RcsManager.java index 90bd0446d6f3..22e4b2249c36 100644 --- a/telephony/java/android/telephony/ims/RcsManager.java +++ b/telephony/java/android/telephony/ims/RcsManager.java @@ -20,8 +20,6 @@ import android.content.Context; /** * The manager class for RCS related utilities. - * - * @hide - TODO: make public */ @SystemService(Context.TELEPHONY_RCS_SERVICE) public class RcsManager { diff --git a/telephony/java/android/telephony/ims/RcsMessage.java b/telephony/java/android/telephony/ims/RcsMessage.java index 1700941b94ed..32274131a5ad 100644 --- a/telephony/java/android/telephony/ims/RcsMessage.java +++ b/telephony/java/android/telephony/ims/RcsMessage.java @@ -27,8 +27,6 @@ import java.util.Set; /** * This is a single instance of a message sent or received over RCS. - * - * @hide - TODO: make public */ public abstract class RcsMessage { /** diff --git a/telephony/java/android/telephony/ims/RcsMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsMessageCreationParams.java index 9ac4dcdf2d74..c46c605d861d 100644 --- a/telephony/java/android/telephony/ims/RcsMessageCreationParams.java +++ b/telephony/java/android/telephony/ims/RcsMessageCreationParams.java @@ -27,8 +27,6 @@ import android.os.Parcel; * {@link RcsThread#addIncomingMessage(RcsIncomingMessageCreationParams)} and * {@link RcsThread#addOutgoingMessage(RcsOutgoingMessageCreationParams)} to create and persist * {@link RcsMessage}s on an {@link RcsThread} - * - * @hide - TODO: make public */ public class RcsMessageCreationParams { // The globally unique id of the RcsMessage to be created. diff --git a/telephony/java/android/telephony/ims/RcsMessageQueryParams.java b/telephony/java/android/telephony/ims/RcsMessageQueryParams.java index fae0d97cd722..535a597f5e1e 100644 --- a/telephony/java/android/telephony/ims/RcsMessageQueryParams.java +++ b/telephony/java/android/telephony/ims/RcsMessageQueryParams.java @@ -31,8 +31,6 @@ import java.security.InvalidParameterException; * The parameters to pass into * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} in order to select a * subset of {@link RcsMessage}s present in the message store. - * - * @hide - TODO: make public */ public final class RcsMessageQueryParams implements Parcelable { /** diff --git a/telephony/java/android/telephony/ims/RcsMessageQueryResult.java b/telephony/java/android/telephony/ims/RcsMessageQueryResult.java index 5adab760d594..3514b48e80a1 100644 --- a/telephony/java/android/telephony/ims/RcsMessageQueryResult.java +++ b/telephony/java/android/telephony/ims/RcsMessageQueryResult.java @@ -32,8 +32,6 @@ import java.util.List; * The result of a {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} * call. This class allows getting the token for querying the next batch of messages in order to * prevent handling large amounts of data at once. - * - * @hide - TODO: make public */ public final class RcsMessageQueryResult implements Parcelable { // The token to continue the query to get the next batch of results diff --git a/telephony/java/android/telephony/ims/RcsMessageSnippet.java b/telephony/java/android/telephony/ims/RcsMessageSnippet.java index 565bb99de89a..b0b930c56e91 100644 --- a/telephony/java/android/telephony/ims/RcsMessageSnippet.java +++ b/telephony/java/android/telephony/ims/RcsMessageSnippet.java @@ -23,8 +23,6 @@ import android.telephony.ims.RcsMessage.RcsMessageStatus; /** * An immutable summary of the latest {@link RcsMessage} on an {@link RcsThread} - * - * @hide - TODO: make public */ public final class RcsMessageSnippet implements Parcelable { private final String mText; diff --git a/telephony/java/android/telephony/ims/RcsMessageStore.java b/telephony/java/android/telephony/ims/RcsMessageStore.java index eca5ed518521..d811c6e93a56 100644 --- a/telephony/java/android/telephony/ims/RcsMessageStore.java +++ b/telephony/java/android/telephony/ims/RcsMessageStore.java @@ -26,8 +26,6 @@ import java.util.List; /** * RcsMessageStore is the application interface to RcsProvider and provides access methods to * RCS related database tables. - * - * @hide - TODO: make public */ public class RcsMessageStore { /** diff --git a/telephony/java/android/telephony/ims/RcsMessageStoreException.java b/telephony/java/android/telephony/ims/RcsMessageStoreException.java index 7c00749b1690..f25bb173be37 100644 --- a/telephony/java/android/telephony/ims/RcsMessageStoreException.java +++ b/telephony/java/android/telephony/ims/RcsMessageStoreException.java @@ -19,8 +19,6 @@ package android.telephony.ims; /** * An exception that happened on {@link RcsMessageStore} or one of the derived storage classes in * {@link android.telephony.ims} - * - * @hide - TODO: make public */ public class RcsMessageStoreException extends Exception { diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessage.java b/telephony/java/android/telephony/ims/RcsOutgoingMessage.java index dfcdee4a803d..06fb83268afb 100644 --- a/telephony/java/android/telephony/ims/RcsOutgoingMessage.java +++ b/telephony/java/android/telephony/ims/RcsOutgoingMessage.java @@ -23,8 +23,6 @@ import java.util.List; /** * This is a single instance of a message sent over RCS. - * - * @hide - TODO: make public */ public class RcsOutgoingMessage extends RcsMessage { RcsOutgoingMessage(int id) { diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java index ca466e8c9d3e..979634a069df 100644 --- a/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java +++ b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java @@ -23,8 +23,6 @@ import android.os.Parcelable; * {@link RcsOutgoingMessageCreationParams} is a collection of parameters that should be passed * into {@link RcsThread#addOutgoingMessage(RcsOutgoingMessageCreationParams)} to generate an * {@link RcsOutgoingMessage} on that {@link RcsThread} - * - * @hide - TODO: make public */ public final class RcsOutgoingMessageCreationParams extends RcsMessageCreationParams implements Parcelable { diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java b/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java index 5a3062a69e3f..1c87b13f0dfb 100644 --- a/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java +++ b/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java @@ -21,8 +21,6 @@ import android.annotation.WorkerThread; /** * This class holds the delivery information of an {@link RcsOutgoingMessage} for each * {@link RcsParticipant} that the message was intended for. - * - * @hide - TODO: make public */ public class RcsOutgoingMessageDelivery { // The participant that this delivery is intended for diff --git a/telephony/java/android/telephony/ims/RcsParticipant.java b/telephony/java/android/telephony/ims/RcsParticipant.java index 37b827b8e83c..7ba5d8e65f76 100644 --- a/telephony/java/android/telephony/ims/RcsParticipant.java +++ b/telephony/java/android/telephony/ims/RcsParticipant.java @@ -20,8 +20,6 @@ import android.annotation.WorkerThread; /** * RcsParticipant is an RCS capable contact that can participate in {@link RcsThread}s. - * - * @hide - TODO: make public */ public class RcsParticipant { // The row ID of this participant in the database diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java index aa278b38cf81..c9a2b0d07bc8 100644 --- a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java +++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java @@ -23,8 +23,6 @@ import android.os.Parcelable; /** * An event that indicates an {@link RcsParticipant}'s alias was changed. Please see US18-2 - GSMA * RCC.71 (RCS Universal Profile Service Definition Document) - * - * @hide - TODO: make public */ public final class RcsParticipantAliasChangedEvent extends RcsEvent implements Parcelable { // The ID of the participant that changed their alias diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java b/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java index 57c67fa7aa03..d24d079d7038 100644 --- a/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java +++ b/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java @@ -30,8 +30,6 @@ import java.security.InvalidParameterException; * The parameters to pass into * {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParams)} in order to select a * subset of {@link RcsThread}s present in the message store. - * - * @hide - TODO: make public */ public final class RcsParticipantQueryParams implements Parcelable { /** diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java b/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java index 4eae39d1a2c6..505f1a55d1f0 100644 --- a/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java +++ b/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java @@ -28,8 +28,6 @@ import java.util.List; * The result of a {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParams)} * call. This class allows getting the token for querying the next batch of participants in order to * prevent handling large amounts of data at once. - * - * @hide - TODO: make public */ public final class RcsParticipantQueryResult implements Parcelable { // A token for the caller to continue their query for the next batch of results diff --git a/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java b/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java index c1ff39652397..08643de51d40 100644 --- a/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java +++ b/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java @@ -31,8 +31,6 @@ import java.lang.annotation.RetentionPolicy; * @see RcsMessageQueryResult#getContinuationToken() * @see RcsParticipantQueryResult#getContinuationToken() * @see RcsThreadQueryResult#getContinuationToken() - * - * @hide - TODO: make public */ public final class RcsQueryContinuationToken implements Parcelable { /** diff --git a/telephony/java/android/telephony/ims/RcsThread.java b/telephony/java/android/telephony/ims/RcsThread.java index 88655865f47b..e015dd3e9c0a 100644 --- a/telephony/java/android/telephony/ims/RcsThread.java +++ b/telephony/java/android/telephony/ims/RcsThread.java @@ -27,8 +27,6 @@ import com.android.internal.annotations.VisibleForTesting; /** * RcsThread represents a single RCS conversation thread. It holds messages that were sent and * received and events that occurred on that thread. - * - * @hide - TODO: make public */ public abstract class RcsThread { /** diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryParams.java b/telephony/java/android/telephony/ims/RcsThreadQueryParams.java index ba32e320c95b..05a5a3917691 100644 --- a/telephony/java/android/telephony/ims/RcsThreadQueryParams.java +++ b/telephony/java/android/telephony/ims/RcsThreadQueryParams.java @@ -35,8 +35,6 @@ import java.util.Set; /** * The parameters to pass into {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)} in * order to select a subset of {@link RcsThread}s present in the message store. - * - * @hide - TODO: make public */ public final class RcsThreadQueryParams implements Parcelable { /** diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryResult.java b/telephony/java/android/telephony/ims/RcsThreadQueryResult.java index a91126b89cce..1cac61d1aa64 100644 --- a/telephony/java/android/telephony/ims/RcsThreadQueryResult.java +++ b/telephony/java/android/telephony/ims/RcsThreadQueryResult.java @@ -32,8 +32,6 @@ import java.util.List; * The result of a {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)} * call. This class allows getting the token for querying the next batch of threads in order to * prevent handling large amounts of data at once. - * - * @hide - TODO: make public */ public final class RcsThreadQueryResult implements Parcelable { // A token for the caller to continue their query for the next batch of results diff --git a/telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl b/telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl new file mode 100644 index 000000000000..7a78f3454aac --- /dev/null +++ b/telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl @@ -0,0 +1,25 @@ +/* + * Copyright 2019 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.telephony; + +/** + * Callback to provide asynchronous result of setPreferredOpportunisticData. + * @hide + */ +oneway interface ISetOpportunisticDataCallback { + void onComplete(int result); +} diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index 6ce9de4ca677..75a4d8227e23 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -17,6 +17,7 @@ package com.android.internal.telephony; import android.telephony.SubscriptionInfo; +import com.android.internal.telephony.ISetOpportunisticDataCallback; interface ISub { /** @@ -217,10 +218,14 @@ interface ISub { * designed to overwrite default data subscription temporarily. * * @param subId which subscription is preferred to for cellular data. + * @param needValidation whether validation is needed before switching. + * @param callback callback upon request completion. + * * @hide * */ - void setPreferredDataSubscriptionId(int subId); + void setPreferredDataSubscriptionId(int subId, boolean needValidation, + ISetOpportunisticDataCallback callback); /** * Get which subscription is preferred for cellular data. diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index bc43feaf0e15..caa367fbaafe 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1837,7 +1837,7 @@ interface ITelephony { * @hide */ boolean isMultisimCarrierRestricted(); - + /** * Switch configs to enable multi-sim or switch back to single-sim * @hide @@ -1846,6 +1846,7 @@ interface ITelephony { /** * Get if reboot is required upon altering modems configurations + * @hide */ boolean isRebootRequiredForModemConfigChange(); diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java index b9ec7bf56370..9d78bf4bfb53 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java @@ -334,8 +334,7 @@ public final class TelephonyPermissions { // settings to individually disable the new restrictions for privileged, preloaded // non-privileged, and non-preinstalled apps. if (!isIdentifierCheckDisabled() && ( - (isPrivApp && !relaxPrivDeviceIdentifierCheck) - || (!isPreinstalled && !relax3PDeviceIdentifierCheck) + (!isPreinstalled && !relax3PDeviceIdentifierCheck) || (isPreinstalled && !isPrivApp && !relaxNonPrivDeviceIdentifierCheck))) { // The current package should only be reported in StatsLog if it has not previously been // reported for the currently invoked device identifier method. diff --git a/test-base/api/TEST_MAPPING b/test-base/api/TEST_MAPPING new file mode 100644 index 000000000000..3535954bc019 --- /dev/null +++ b/test-base/api/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "CtsAndroidTestBase27ApiSignatureTestCases" + } + ] +} diff --git a/test-mock/api/TEST_MAPPING b/test-mock/api/TEST_MAPPING new file mode 100644 index 000000000000..d1bd9afaf287 --- /dev/null +++ b/test-mock/api/TEST_MAPPING @@ -0,0 +1,10 @@ +{ + "presubmit": [ + { + "name": "CtsAndroidTestMockCurrentApiSignatureTestCases" + }, + { + "name": "CtsCurrentApiSignatureTestCases" + } + ] +} diff --git a/test-runner/Android.mk b/test-runner/Android.mk deleted file mode 100644 index 18bde8517351..000000000000 --- a/test-runner/Android.mk +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (C) 2008 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. -# - -LOCAL_PATH:= $(call my-dir) - -# additionally, build unit tests in a separate .apk -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/test-runner/api/TEST_MAPPING b/test-runner/api/TEST_MAPPING new file mode 100644 index 000000000000..76ade3c1e647 --- /dev/null +++ b/test-runner/api/TEST_MAPPING @@ -0,0 +1,10 @@ +{ + "presubmit": [ + { + "name": "CtsAndroidTestRunnerCurrentApiSignatureTestCases" + }, + { + "name": "CtsCurrentApiSignatureTestCases" + } + ] +} diff --git a/test-runner/tests/Android.bp b/test-runner/tests/Android.bp new file mode 100644 index 000000000000..03c73986118d --- /dev/null +++ b/test-runner/tests/Android.bp @@ -0,0 +1,40 @@ +// Copyright 2010, 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. + +android_test { + name: "FrameworkTestRunnerTests", + + // We only want this apk build for tests. + // + // Run the tests using the following commands: + // adb install -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworkTestRunnerTests/FrameworkTestRunnerTests.apk + // adb shell am instrument \ + // -e notAnnotation android.test.suitebuilder.examples.error.RunAsPartOfSeparateTest \ + // -w com.android.frameworks.testrunner.tests/android.test.InstrumentationTestRunner \ + // + + libs: [ + "android.test.runner", + "android.test.base", + "android.test.mock", + ], + static_libs: ["junit"], + + // Include all test java files. + srcs: ["src/**/*.java"], + + // Because of android.test.mock. + platform_apis: true, + +} diff --git a/test-runner/tests/Android.mk b/test-runner/tests/Android.mk deleted file mode 100644 index f97d1c986b1c..000000000000 --- a/test-runner/tests/Android.mk +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2010, 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. - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -# We only want this apk build for tests. -# -# Run the tests using the following commands: -# adb install -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworkTestRunnerTests/FrameworkTestRunnerTests.apk -# adb shell am instrument \ - -e notAnnotation android.test.suitebuilder.examples.error.RunAsPartOfSeparateTest \ - -w com.android.frameworks.testrunner.tests/android.test.InstrumentationTestRunner -# -LOCAL_MODULE_TAGS := tests - -LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock -LOCAL_STATIC_JAVA_LIBRARIES := junit - -# Include all test java files. -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_PACKAGE_NAME := FrameworkTestRunnerTests -# Because of android.test.mock. -LOCAL_PRIVATE_PLATFORM_APIS := true - -include $(BUILD_PACKAGE) - diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index e2d59d648563..a7c95c78d05d 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -554,7 +554,7 @@ public class ConnectivityServiceTest { if (mNmValidationRedirectUrl != null) { mNmCallbacks.showProvisioningNotification( - "test_provisioning_notif_action"); + "test_provisioning_notif_action", "com.android.test.package"); mNmProvNotificationRequested = true; } } catch (RemoteException e) { diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index b6356076db60..a4a735d1a89d 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -35,6 +35,7 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY; import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -274,6 +275,11 @@ public class TetheringTest { isTetheringSupportedCalls++; return true; } + + @Override + public int getDefaultDataSubscriptionId() { + return INVALID_SUBSCRIPTION_ID; + } } private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6, diff --git a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java index ec286759354a..193f3806dbf6 100644 --- a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java @@ -21,6 +21,7 @@ import static android.net.ConnectivityManager.TETHERING_WIFI; import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN; import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -140,7 +141,8 @@ public final class EntitlementManagerTest { mMockContext = new MockContext(mContext); mSM = new TestStateMachine(); mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, mSystemProperties); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog)); + mEnMgr.updateConfiguration( + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); } @After @@ -168,7 +170,8 @@ public final class EntitlementManagerTest { @Test public void canRequireProvisioning() { setupForRequiredProvisioning(); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog)); + mEnMgr.updateConfiguration( + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); assertTrue(mEnMgr.isTetherProvisioningRequired()); } @@ -177,7 +180,8 @@ public final class EntitlementManagerTest { setupForRequiredProvisioning(); when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE)) .thenReturn(null); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog)); + mEnMgr.updateConfiguration( + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); // Couldn't get the CarrierConfigManager, but still had a declared provisioning app. // Therefore provisioning still be required. assertTrue(mEnMgr.isTetherProvisioningRequired()); @@ -187,7 +191,8 @@ public final class EntitlementManagerTest { public void toleratesCarrierConfigMissing() { setupForRequiredProvisioning(); when(mCarrierConfigManager.getConfig()).thenReturn(null); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog)); + mEnMgr.updateConfiguration( + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); // We still have a provisioning app configured, so still require provisioning. assertTrue(mEnMgr.isTetherProvisioningRequired()); } @@ -197,11 +202,13 @@ public final class EntitlementManagerTest { setupForRequiredProvisioning(); when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app)) .thenReturn(null); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog)); + mEnMgr.updateConfiguration( + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); assertFalse(mEnMgr.isTetherProvisioningRequired()); when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app)) .thenReturn(new String[] {"malformedApp"}); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog)); + mEnMgr.updateConfiguration( + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); assertFalse(mEnMgr.isTetherProvisioningRequired()); } @@ -223,7 +230,8 @@ public final class EntitlementManagerTest { assertFalse(mEnMgr.everRunUiEntitlement); setupForRequiredProvisioning(); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog)); + mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog, + INVALID_SUBSCRIPTION_ID)); // 2. No cache value and don't need to run entitlement check. mEnMgr.everRunUiEntitlement = false; receiver = new ResultReceiver(null) { diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java index 521778484d91..01b904d8f088 100644 --- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java +++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java @@ -22,10 +22,12 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_NOT_REQUIRED; import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_REQUIRED; import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_UNSPECIFIED; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -44,26 +46,39 @@ import android.test.mock.MockContentResolver; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; -import java.util.Iterator; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Iterator; @RunWith(AndroidJUnit4.class) @SmallTest public class TetheringConfigurationTest { private final SharedLog mLog = new SharedLog("TetheringConfigurationTest"); + + private static final String[] PROVISIONING_APP_NAME = {"some", "app"}; @Mock private Context mContext; @Mock private TelephonyManager mTelephonyManager; @Mock private Resources mResources; + @Mock private Resources mResourcesForSubId; private MockContentResolver mContentResolver; private Context mMockContext; private boolean mHasTelephonyManager; + private class MockTetheringConfiguration extends TetheringConfiguration { + MockTetheringConfiguration(Context ctx, SharedLog log, int id) { + super(ctx, log, id); + } + + @Override + protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) { + return mResourcesForSubId; + } + } + private class MockContext extends BroadcastInterceptingContext { MockContext(Context base) { super(base); @@ -99,6 +114,9 @@ public class TetheringConfigurationTest { .thenReturn(new String[0]); when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[0]); + when(mResources.getStringArray( + com.android.internal.R.array.config_mobile_hotspot_provision_app)) + .thenReturn(new String[0]); mContentResolver = new MockContentResolver(); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); mMockContext = new MockContext(mContext); @@ -111,7 +129,8 @@ public class TetheringConfigurationTest { mHasTelephonyManager = true; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_REQUIRED); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertTrue(cfg.isDunRequired); assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); @@ -127,7 +146,8 @@ public class TetheringConfigurationTest { mHasTelephonyManager = true; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_NOT_REQUIRED); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertFalse(cfg.isDunRequired); assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); @@ -143,7 +163,8 @@ public class TetheringConfigurationTest { mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertTrue(cfg.isDunRequired); assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); // Just to prove we haven't clobbered Wi-Fi: @@ -160,7 +181,8 @@ public class TetheringConfigurationTest { mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); assertTrue(upstreamIterator.hasNext()); assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue()); @@ -181,7 +203,8 @@ public class TetheringConfigurationTest { mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); assertTrue(upstreamIterator.hasNext()); assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue()); @@ -199,7 +222,8 @@ public class TetheringConfigurationTest { mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); assertTrue(upstreamIterator.hasNext()); assertEquals(TYPE_WIFI, upstreamIterator.next().intValue()); @@ -214,7 +238,8 @@ public class TetheringConfigurationTest { public void testNewDhcpServerDisabled() { Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertTrue(cfg.enableLegacyDhcpServer); } @@ -222,7 +247,41 @@ public class TetheringConfigurationTest { public void testNewDhcpServerEnabled() { Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertFalse(cfg.enableLegacyDhcpServer); } + + @Test + public void testGetResourcesBySubId() { + setUpResourceForSubId(); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(cfg.provisioningApp.length == 0); + final int anyValidSubId = 1; + final MockTetheringConfiguration mockCfg = + new MockTetheringConfiguration(mMockContext, mLog, anyValidSubId); + assertEquals(mockCfg.provisioningApp[0], PROVISIONING_APP_NAME[0]); + assertEquals(mockCfg.provisioningApp[1], PROVISIONING_APP_NAME[1]); + } + + private void setUpResourceForSubId() { + when(mResourcesForSubId.getStringArray( + com.android.internal.R.array.config_tether_dhcp_range)).thenReturn(new String[0]); + when(mResourcesForSubId.getStringArray( + com.android.internal.R.array.config_tether_usb_regexs)).thenReturn(new String[0]); + when(mResourcesForSubId.getStringArray( + com.android.internal.R.array.config_tether_wifi_regexs)) + .thenReturn(new String[]{ "test_wlan\\d" }); + when(mResourcesForSubId.getStringArray( + com.android.internal.R.array.config_tether_bluetooth_regexs)) + .thenReturn(new String[0]); + when(mResourcesForSubId.getIntArray( + com.android.internal.R.array.config_tether_upstream_types)) + .thenReturn(new int[0]); + when(mResourcesForSubId.getStringArray( + com.android.internal.R.array.config_mobile_hotspot_provision_app)) + .thenReturn(PROVISIONING_APP_NAME); + } + } diff --git a/media/java/android/media/session/MediaSessionProviderService.java b/tests/utils/testutils/java/android/view/test/InsetsModeSession.java index 9a346ff4a12e..c83dfa41d260 100644 --- a/media/java/android/media/session/MediaSessionProviderService.java +++ b/tests/utils/testutils/java/android/view/test/InsetsModeSession.java @@ -14,22 +14,24 @@ * limitations under the License. */ -package android.media.session; +package android.view.test; -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; +import android.view.ViewRootImpl; /** - * Abstract class for mainline module services. - * - * @hide // TODO: Make it as a @SystemApi + * Session to set insets mode for {@link ViewRootImpl#sNewInsetsMode}. */ -public abstract class MediaSessionProviderService extends Service { +public class InsetsModeSession implements AutoCloseable { + + private int mOldMode; + + public InsetsModeSession(int flag) { + mOldMode = ViewRootImpl.sNewInsetsMode; + ViewRootImpl.sNewInsetsMode = flag; + } @Override - public IBinder onBind(Intent intent) { - // TODO: Return IMediaSessionProviderService.Stub() - return null; + public void close() throws Exception { + ViewRootImpl.sNewInsetsMode = mOldMode; } } diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp index 85bf6f218ba0..582a5b869c65 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -294,22 +294,6 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, } } - if (el->FindAttribute("", "platformBuildVersionCode") == nullptr) { - auto versionCode = el->FindAttribute(xml::kSchemaAndroid, "versionCode"); - if (versionCode != nullptr) { - el->attributes.push_back(xml::Attribute{"", "platformBuildVersionCode", - versionCode->value}); - } - } - - if (el->FindAttribute("", "platformBuildVersionName") == nullptr) { - auto versionName = el->FindAttribute(xml::kSchemaAndroid, "versionName"); - if (versionName != nullptr) { - el->attributes.push_back(xml::Attribute{"", "platformBuildVersionName", - versionName->value}); - } - } - return true; }); @@ -489,8 +473,14 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) { // Make sure we un-compile the value if it was set to something else. attr->compiled_value = {}; + attr->value = options_.compile_sdk_version.value(); + + attr = root->FindOrCreateAttribute("", "platformBuildVersionCode"); + // Make sure we un-compile the value if it was set to something else. + attr->compiled_value = {}; attr->value = options_.compile_sdk_version.value(); + } if (options_.compile_sdk_version_codename) { @@ -499,7 +489,12 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) { // Make sure we un-compile the value if it was set to something else. attr->compiled_value = {}; + attr->value = options_.compile_sdk_version_codename.value(); + attr = root->FindOrCreateAttribute("", "platformBuildVersionName"); + + // Make sure we un-compile the value if it was set to something else. + attr->compiled_value = {}; attr->value = options_.compile_sdk_version_codename.value(); } diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp index adea6273bc8b..4842f62e53b5 100644 --- a/tools/aapt2/link/ManifestFixer_test.cpp +++ b/tools/aapt2/link/ManifestFixer_test.cpp @@ -725,6 +725,43 @@ TEST_F(ManifestFixerTest, InsertCompileSdkVersions) { attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("P")); + + attr = manifest->root->FindAttribute("", "platformBuildVersionCode"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("28")); + + attr = manifest->root->FindAttribute("", "platformBuildVersionName"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("P")); +} + +TEST_F(ManifestFixerTest, OverrideCompileSdkVersions) { + std::string input = R"( + <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" + compileSdkVersion="27" compileSdkVersionCodename="O" + platformBuildVersionCode="27" platformBuildVersionName="O"/>)"; + ManifestFixerOptions options; + options.compile_sdk_version = {"28"}; + options.compile_sdk_version_codename = {"P"}; + + std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options); + ASSERT_THAT(manifest, NotNull()); + + xml::Attribute* attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersion"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("28")); + + attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("P")); + + attr = manifest->root->FindAttribute("", "platformBuildVersionCode"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("28")); + + attr = manifest->root->FindAttribute("", "platformBuildVersionName"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("P")); } TEST_F(ManifestFixerTest, UnexpectedElementsInManifest) { @@ -750,59 +787,6 @@ TEST_F(ManifestFixerTest, UnexpectedElementsInManifest) { ASSERT_THAT(manifest, IsNull()); } -TEST_F(ManifestFixerTest, InsertPlatformBuildVersions) { - // Test for insertion when versionCode and versionName are included in the manifest - { - std::string input = R"( - <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" - android:versionCode="27" android:versionName="O"/>)"; - std::unique_ptr<xml::XmlResource> manifest = Verify(input); - ASSERT_THAT(manifest, NotNull()); - - xml::Attribute* attr = manifest->root->FindAttribute("", "platformBuildVersionCode"); - ASSERT_THAT(attr, NotNull()); - EXPECT_THAT(attr->value, StrEq("27")); - attr = manifest->root->FindAttribute("", "platformBuildVersionName"); - ASSERT_THAT(attr, NotNull()); - EXPECT_THAT(attr->value, StrEq("O")); - } - - // Test for insertion when versionCode and versionName defaults are specified - { - std::string input = R"( - <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"/>)"; - ManifestFixerOptions options; - options.version_code_default = {"27"}; - options.version_name_default = {"O"}; - std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options); - ASSERT_THAT(manifest, NotNull()); - - xml::Attribute* attr = manifest->root->FindAttribute("", "platformBuildVersionCode"); - ASSERT_THAT(attr, NotNull()); - EXPECT_THAT(attr->value, StrEq("27")); - attr = manifest->root->FindAttribute("", "platformBuildVersionName"); - ASSERT_THAT(attr, NotNull()); - EXPECT_THAT(attr->value, StrEq("O")); - } - - // Test that the platform build version attributes are not changed if they are currently present - { - std::string input = R"( - <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" - android:versionCode="28" android:versionName="P" - platformBuildVersionCode="27" platformBuildVersionName="O"/>)"; - std::unique_ptr<xml::XmlResource> manifest = Verify(input); - ASSERT_THAT(manifest, NotNull()); - - xml::Attribute* attr = manifest->root->FindAttribute("", "platformBuildVersionCode"); - ASSERT_THAT(attr, NotNull()); - EXPECT_THAT(attr->value, StrEq("27")); - attr = manifest->root->FindAttribute("", "platformBuildVersionName"); - ASSERT_THAT(attr, NotNull()); - EXPECT_THAT(attr->value, StrEq("O")); - } -} - TEST_F(ManifestFixerTest, UsesLibraryMustHaveNonEmptyName) { std::string input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" diff --git a/tools/preload/Android.bp b/tools/preload/Android.bp new file mode 100644 index 000000000000..809ee474969a --- /dev/null +++ b/tools/preload/Android.bp @@ -0,0 +1,17 @@ +java_library_host { + name: "preload", + srcs: [ + "Compile.java", + "LoadedClass.java", + "MemoryUsage.java", + "Operation.java", + "Policy.java", + "PrintCsv.java", + "PrintHtmlDiff.java", + "PrintPsTree.java", + "Proc.java", + "Record.java", + "Root.java", + "WritePreloadedClassFile.java", + ], +} diff --git a/tools/preload/Android.mk b/tools/preload/Android.mk deleted file mode 100644 index 14a4547cccbf..000000000000 --- a/tools/preload/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - Compile.java \ - LoadedClass.java \ - MemoryUsage.java \ - Operation.java \ - Policy.java \ - PrintCsv.java \ - PrintHtmlDiff.java \ - PrintPsTree.java \ - Proc.java \ - Record.java \ - Root.java \ - WritePreloadedClassFile.java - -LOCAL_MODULE:= preload - -include $(BUILD_HOST_JAVA_LIBRARY) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tools/preload/loadclass/Android.bp b/tools/preload/loadclass/Android.bp new file mode 100644 index 000000000000..6f12015dae2b --- /dev/null +++ b/tools/preload/loadclass/Android.bp @@ -0,0 +1,4 @@ +java_test { + name: "loadclass", + srcs: ["**/*.java"], +} diff --git a/tools/preload/loadclass/Android.mk b/tools/preload/loadclass/Android.mk deleted file mode 100644 index 65828be617df..000000000000 --- a/tools/preload/loadclass/Android.mk +++ /dev/null @@ -1,9 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(call all-subdir-java-files) -LOCAL_MODULE_TAGS := tests - -LOCAL_MODULE := loadclass - -include $(BUILD_JAVA_LIBRARY) diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index 55440d2261d3..0270c72ff240 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -688,7 +688,7 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map); size_t i = 0; - // Print constants + // Print atom constants for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end(); atom++) { string constant = make_constant_name(atom->name); @@ -714,6 +714,30 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio fprintf(out, "};\n"); fprintf(out, "\n"); + // Print constants for the enum values. + fprintf(out, "//\n"); + fprintf(out, "// Constants for enum values\n"); + fprintf(out, "//\n\n"); + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + for (vector<AtomField>::const_iterator field = atom->fields.begin(); + field != atom->fields.end(); field++) { + if (field->javaType == JAVA_TYPE_ENUM) { + fprintf(out, "// Values for %s.%s\n", atom->message.c_str(), + field->name.c_str()); + for (map<int, string>::const_iterator value = field->enumValues.begin(); + value != field->enumValues.end(); value++) { + fprintf(out, "const int32_t %s__%s__%s = %d;\n", + make_constant_name(atom->message).c_str(), + make_constant_name(field->name).c_str(), + make_constant_name(value->second).c_str(), + value->first); + } + fprintf(out, "\n"); + } + } + } + fprintf(out, "struct BytesField {\n"); fprintf(out, " BytesField(char const* array, size_t len) : arg(array), " diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 1273a4aacf45..c88eee86ddea 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1037,9 +1037,6 @@ public class WifiManager { * Example use cases are real time gaming or virtual reality applications where * low latency is a key factor for user experience. * <p> - * When there is no support from the hardware, the {@link #WIFI_MODE_FULL_LOW_LATENCY} - * lock will cause the device not to go power save. - * <p> * Note: For an app which acquires both {@link #WIFI_MODE_FULL_LOW_LATENCY} and * {@link #WIFI_MODE_FULL_HIGH_PERF} locks, {@link #WIFI_MODE_FULL_LOW_LATENCY} * lock will be effective when app is running in foreground and screen is on, @@ -4724,7 +4721,6 @@ public class WifiManager { * * @hide */ - @SystemApi private static class EasyConnectCallbackProxy extends IDppCallback.Stub { private final Executor mExecutor; private final EasyConnectStatusCallback mEasyConnectStatusCallback; @@ -4877,4 +4873,4 @@ public class WifiManager { throw e.rethrowFromSystemServer(); } } -}
\ No newline at end of file +} diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java index a69c7a501452..333b82ccd146 100644 --- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java +++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java @@ -421,7 +421,7 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc * .setSsidPattern(new PatternMatcher("test", PatterMatcher.PATTERN_PREFIX)) * .setBssidPattern(MacAddress.fromString("10:03:23:00:00:00"), * MacAddress.fromString("ff:ff:ff:00:00:00")) - * .buildNetworkSpecifier() + * .build() * final NetworkRequest request = * new NetworkRequest.Builder() * .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java index 460c633e16bd..233fa2cb4fff 100644 --- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java +++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java @@ -413,17 +413,17 @@ public final class WifiNetworkSuggestion implements Parcelable { * final WifiNetworkSuggestion suggestion1 = * new Builder() * .setSsid("test111111") - * .buildNetworkSuggestion() + * .build() * final WifiNetworkSuggestion suggestion2 = * new Builder() * .setSsid("test222222") * .setWpa2Passphrase("test123456") - * .buildNetworkSuggestion() + * .build() * final WifiNetworkSuggestion suggestion3 = * new Builder() * .setSsid("test333333") * .setWpa3Passphrase("test6789") - * .buildNetworkSuggestion() + * .build() * final List<WifiNetworkSuggestion> suggestionsList = * new ArrayList<WifiNetworkSuggestion> {{ * add(suggestion1); diff --git a/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java b/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java new file mode 100644 index 000000000000..4ddf872f6cd2 --- /dev/null +++ b/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 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.wifi.aware; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A Parcelable {@link PeerHandle}. Can be constructed from a {@code PeerHandle} and then passed + * to any of the APIs which take a {@code PeerHandle} as inputs. + */ +public final class ParcelablePeerHandle extends PeerHandle implements Parcelable { + /** + * Construct a parcelable version of {@link PeerHandle}. + * + * @param peerHandle The {@link PeerHandle} to be made parcelable. + */ + public ParcelablePeerHandle(PeerHandle peerHandle) { + super(peerHandle.peerId); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(peerId); + } + + public static final Creator<ParcelablePeerHandle> CREATOR = + new Creator<ParcelablePeerHandle>() { + @Override + public ParcelablePeerHandle[] newArray(int size) { + return new ParcelablePeerHandle[size]; + } + + @Override + public ParcelablePeerHandle createFromParcel(Parcel in) { + int peerHandle = in.readInt(); + return new ParcelablePeerHandle(new PeerHandle(peerHandle)); + } + }; +} diff --git a/wifi/java/android/net/wifi/aware/PeerHandle.java b/wifi/java/android/net/wifi/aware/PeerHandle.java index 1603d00fd88a..422e177ed7ad 100644 --- a/wifi/java/android/net/wifi/aware/PeerHandle.java +++ b/wifi/java/android/net/wifi/aware/PeerHandle.java @@ -16,9 +16,6 @@ package android.net.wifi.aware; -import android.os.Parcel; -import android.os.Parcelable; - /** * Opaque object used to represent a Wi-Fi Aware peer. Obtained from discovery sessions in * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)} or @@ -35,8 +32,9 @@ import android.os.Parcelable; * configuration's service-specific information field, * {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])}, or match filter, * {@link PublishConfig.Builder#setMatchFilter(java.util.List)}. + * <p>A parcelable handle object is available with {@link ParcelablePeerHandle}. */ -public final class PeerHandle implements Parcelable { +public class PeerHandle { /** @hide */ public PeerHandle(int peerId) { this.peerId = peerId; @@ -62,29 +60,4 @@ public final class PeerHandle implements Parcelable { public int hashCode() { return peerId; } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(peerId); - } - - public static final Creator<PeerHandle> CREATOR = new Creator<PeerHandle>() { - @Override - public PeerHandle[] newArray(int size) { - return new PeerHandle[size]; - } - - @Override - public PeerHandle createFromParcel(Parcel in) { - int peerHandle = in.readInt(); - - return new PeerHandle(peerHandle); - } - }; - } diff --git a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java index 29f10e932e48..b3b5b2903471 100644 --- a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java +++ b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java @@ -61,6 +61,7 @@ public class TlvBufferUtils { public static class TlvConstructor { private int mTypeSize; private int mLengthSize; + private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN; private byte[] mArray; private int mArrayLength; @@ -84,6 +85,20 @@ public class TlvBufferUtils { } mTypeSize = typeSize; mLengthSize = lengthSize; + mPosition = 0; + } + + /** + * Configure the TLV constructor to use a particular byte order. Should be + * {@link ByteOrder#BIG_ENDIAN} (the default at construction) or + * {@link ByteOrder#LITTLE_ENDIAN}. + * + * @return The constructor to facilitate chaining + * {@code ctr.putXXX(..).putXXX(..)}. + */ + public TlvConstructor setByteOrder(ByteOrder byteOrder) { + mByteOrder = byteOrder; + return this; } /** @@ -96,6 +111,7 @@ public class TlvBufferUtils { public TlvConstructor wrap(@Nullable byte[] array) { mArray = array; mArrayLength = (array == null) ? 0 : array.length; + mPosition = 0; return this; } @@ -109,6 +125,7 @@ public class TlvBufferUtils { public TlvConstructor allocate(int capacity) { mArray = new byte[capacity]; mArrayLength = capacity; + mPosition = 0; return this; } @@ -155,6 +172,18 @@ public class TlvBufferUtils { } /** + * Copies a raw byte into the TLV buffer - without a type or a length. + * + * @param b The byte to be inserted into the structure. + * @return The constructor to facilitate chaining {@code cts.putXXX(..).putXXX(..)}. + */ + public TlvConstructor putRawByte(byte b) { + checkRawLength(1); + mArray[mPosition++] = b; + return this; + } + + /** * Copies a byte array into the TLV with the indicated type. For an LV * formatted structure (i.e. typeLength=0 in {@link TlvConstructor * TlvConstructor(int, int)} ) the type field is ignored. @@ -193,6 +222,22 @@ public class TlvBufferUtils { } /** + * Copies a byte array into the TLV - without a type or a length. + * + * @param array The array to be copied (in full) into the TLV structure. + * @return The constructor to facilitate chaining + * {@code ctr.putXXX(..).putXXX(..)}. + */ + public TlvConstructor putRawByteArray(@Nullable byte[] array) { + if (array == null) return this; + + checkRawLength(array.length); + System.arraycopy(array, 0, mArray, mPosition, array.length); + mPosition += array.length; + return this; + } + + /** * Places a zero length element (i.e. Length field = 0) into the TLV. * For an LV formatted structure (i.e. typeLength=0 in * {@link TlvConstructor TlvConstructor(int, int)} ) the type field is @@ -221,7 +266,7 @@ public class TlvBufferUtils { public TlvConstructor putShort(int type, short data) { checkLength(2); addHeader(type, 2); - Memory.pokeShort(mArray, mPosition, data, ByteOrder.BIG_ENDIAN); + Memory.pokeShort(mArray, mPosition, data, mByteOrder); mPosition += 2; return this; } @@ -239,7 +284,7 @@ public class TlvBufferUtils { public TlvConstructor putInt(int type, int data) { checkLength(4); addHeader(type, 4); - Memory.pokeInt(mArray, mPosition, data, ByteOrder.BIG_ENDIAN); + Memory.pokeInt(mArray, mPosition, data, mByteOrder); mPosition += 4; return this; } @@ -294,18 +339,24 @@ public class TlvBufferUtils { } } + private void checkRawLength(int dataLength) { + if (mPosition + dataLength > mArrayLength) { + throw new BufferOverflowException(); + } + } + private void addHeader(int type, int length) { if (mTypeSize == 1) { mArray[mPosition] = (byte) type; } else if (mTypeSize == 2) { - Memory.pokeShort(mArray, mPosition, (short) type, ByteOrder.BIG_ENDIAN); + Memory.pokeShort(mArray, mPosition, (short) type, mByteOrder); } mPosition += mTypeSize; if (mLengthSize == 1) { mArray[mPosition] = (byte) length; } else if (mLengthSize == 2) { - Memory.pokeShort(mArray, mPosition, (short) length, ByteOrder.BIG_ENDIAN); + Memory.pokeShort(mArray, mPosition, (short) length, mByteOrder); } mPosition += mLengthSize; } @@ -330,13 +381,19 @@ public class TlvBufferUtils { public int length; /** + * Control of the endianess of the TLV element - true for big-endian, false for little- + * endian. + */ + public ByteOrder byteOrder = ByteOrder.BIG_ENDIAN; + + /** * The Value (V) field - a raw byte array representing the current TLV * element where the entry starts at {@link TlvElement#offset}. */ - public byte[] refArray; + private byte[] mRefArray; /** - * The offset to be used into {@link TlvElement#refArray} to access the + * The offset to be used into {@link TlvElement#mRefArray} to access the * raw data representing the current TLV element. */ public int offset; @@ -344,7 +401,7 @@ public class TlvBufferUtils { private TlvElement(int type, int length, @Nullable byte[] refArray, int offset) { this.type = type; this.length = length; - this.refArray = refArray; + mRefArray = refArray; this.offset = offset; if (offset + length > refArray.length) { @@ -353,6 +410,15 @@ public class TlvBufferUtils { } /** + * Return the raw byte array of the Value (V) field. + * + * @return The Value (V) field as a byte array. + */ + public byte[] getRawData() { + return Arrays.copyOfRange(mRefArray, offset, offset + length); + } + + /** * Utility function to return a byte representation of a TLV element of * length 1. Note: an attempt to call this function on a TLV item whose * {@link TlvElement#length} is != 1 will result in an exception. @@ -364,7 +430,7 @@ public class TlvBufferUtils { throw new IllegalArgumentException( "Accesing a byte from a TLV element of length " + length); } - return refArray[offset]; + return mRefArray[offset]; } /** @@ -379,7 +445,7 @@ public class TlvBufferUtils { throw new IllegalArgumentException( "Accesing a short from a TLV element of length " + length); } - return Memory.peekShort(refArray, offset, ByteOrder.BIG_ENDIAN); + return Memory.peekShort(mRefArray, offset, byteOrder); } /** @@ -394,7 +460,7 @@ public class TlvBufferUtils { throw new IllegalArgumentException( "Accesing an int from a TLV element of length " + length); } - return Memory.peekInt(refArray, offset, ByteOrder.BIG_ENDIAN); + return Memory.peekInt(mRefArray, offset, byteOrder); } /** @@ -403,7 +469,7 @@ public class TlvBufferUtils { * @return String repersentation of the current TLV element. */ public String getString() { - return new String(refArray, offset, length); + return new String(mRefArray, offset, length); } } @@ -413,6 +479,7 @@ public class TlvBufferUtils { public static class TlvIterable implements Iterable<TlvElement> { private int mTypeSize; private int mLengthSize; + private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN; private byte[] mArray; private int mArrayLength; @@ -440,6 +507,13 @@ public class TlvBufferUtils { } /** + * Configure the TLV iterator to use little-endian byte ordering. + */ + public void setByteOrder(ByteOrder byteOrder) { + mByteOrder = byteOrder; + } + + /** * Prints out a parsed representation of the TLV-formatted byte array. * Whenever possible bytes, shorts, and integer are printed out (for * fields whose length is 1, 2, or 4 respectively). @@ -486,7 +560,7 @@ public class TlvBufferUtils { public List<byte[]> toList() { List<byte[]> list = new ArrayList<>(); for (TlvElement tlv : this) { - list.add(Arrays.copyOfRange(tlv.refArray, tlv.offset, tlv.offset + tlv.length)); + list.add(Arrays.copyOfRange(tlv.mRefArray, tlv.offset, tlv.offset + tlv.length)); } return list; @@ -516,7 +590,7 @@ public class TlvBufferUtils { if (mTypeSize == 1) { type = mArray[mOffset]; } else if (mTypeSize == 2) { - type = Memory.peekShort(mArray, mOffset, ByteOrder.BIG_ENDIAN); + type = Memory.peekShort(mArray, mOffset, mByteOrder); } mOffset += mTypeSize; @@ -524,11 +598,12 @@ public class TlvBufferUtils { if (mLengthSize == 1) { length = mArray[mOffset]; } else if (mLengthSize == 2) { - length = Memory.peekShort(mArray, mOffset, ByteOrder.BIG_ENDIAN); + length = Memory.peekShort(mArray, mOffset, mByteOrder); } mOffset += mLengthSize; TlvElement tlv = new TlvElement(type, length, mArray, mOffset); + tlv.byteOrder = mByteOrder; mOffset += length; return tlv; } @@ -543,7 +618,8 @@ public class TlvBufferUtils { /** * Validates that a (T)LV array is constructed correctly. I.e. that its specified Length - * fields correctly fill the specified length (and do not overshoot). + * fields correctly fill the specified length (and do not overshoot). Uses big-endian + * byte ordering. * * @param array The (T)LV array to verify. * @param typeSize The size (in bytes) of the type field. Valid values are 0, 1, or 2. @@ -551,6 +627,22 @@ public class TlvBufferUtils { * @return A boolean indicating whether the array is valid (true) or invalid (false). */ public static boolean isValid(@Nullable byte[] array, int typeSize, int lengthSize) { + return isValidEndian(array, typeSize, lengthSize, ByteOrder.BIG_ENDIAN); + } + + /** + * Validates that a (T)LV array is constructed correctly. I.e. that its specified Length + * fields correctly fill the specified length (and do not overshoot). + * + * @param array The (T)LV array to verify. + * @param typeSize The size (in bytes) of the type field. Valid values are 0, 1, or 2. + * @param lengthSize The size (in bytes) of the length field. Valid values are 1 or 2. + * @param byteOrder The endianness of the byte array: {@link ByteOrder#BIG_ENDIAN} or + * {@link ByteOrder#LITTLE_ENDIAN}. + * @return A boolean indicating whether the array is valid (true) or invalid (false). + */ + public static boolean isValidEndian(@Nullable byte[] array, int typeSize, int lengthSize, + ByteOrder byteOrder) { if (typeSize < 0 || typeSize > 2) { throw new IllegalArgumentException( "Invalid arguments - typeSize must be 0, 1, or 2: typeSize=" + typeSize); @@ -569,8 +661,7 @@ public class TlvBufferUtils { if (lengthSize == 1) { nextTlvIndex += lengthSize + array[nextTlvIndex]; } else { - nextTlvIndex += lengthSize + Memory.peekShort(array, nextTlvIndex, - ByteOrder.BIG_ENDIAN); + nextTlvIndex += lengthSize + Memory.peekShort(array, nextTlvIndex, byteOrder); } } diff --git a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java index 83affed0b4e0..971aa8e05df2 100644 --- a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java +++ b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java @@ -28,6 +28,7 @@ import java.nio.BufferOverflowException; import java.util.ArrayList; import java.util.List; + /** * Unit test harness for TlvBufferUtils class. */ @@ -69,6 +70,24 @@ public class TlvBufferUtilsTest { } /** + * Validate that re-using a TLV by any of the reallocation method resets it completely. + */ + @Test + public void testTlvReuse() { + TlvBufferUtils.TlvConstructor tlv = new TlvBufferUtils.TlvConstructor(1, 1); + + tlv.allocate(10); + tlv.putByte(0, (byte) 2); + tlv.putByte(1, (byte) 104); + + collector.checkThat("initial", tlv.getArray(), equalTo(new byte[]{0, 1, 2, 1, 1, 104})); + + tlv.allocate(8); + tlv.putByte(5, (byte) 7); + collector.checkThat("re-alloc", tlv.getArray(), equalTo(new byte[]{5, 1, 7})); + } + + /** * Verify that can build a valid TLV from a List of byte[]. */ @Test @@ -121,6 +140,23 @@ public class TlvBufferUtilsTest { List<byte[]> data = new TlvBufferUtils.TlvIterable(0, 1, invalidTlv01).toList(); } + /** + * Validate the API which places raw bytes into the TLV (without a TL structure). + */ + @Test + public void testRawPuts() { + TlvBufferUtils.TlvConstructor tlv = new TlvBufferUtils.TlvConstructor(1, 1); + + tlv.allocate(10); + tlv.putByte(0, (byte) 2); + tlv.putRawByte((byte) 55); + tlv.putByte(1, (byte) 104); + tlv.putRawByteArray(new byte[]{66, 77}); + + collector.checkThat("data", tlv.getArray(), + equalTo(new byte[]{0, 1, 2, 55, 1, 1, 104, 66, 77})); + } + @Test public void testTlvIterate() { final String ascii = "ABC"; @@ -163,6 +199,7 @@ public class TlvBufferUtilsTest { tlv02.putByte(0, (byte) 2); tlv02.putString(0, ascii); tlv02.putString(0, nonAscii); + tlv02.putByteArray(0, new byte[]{5, 4, 3, 2, 1}); TlvBufferUtils.TlvIterable tlv02It = new TlvBufferUtils.TlvIterable(0, 2, tlv02.getArray()); count = 0; @@ -181,6 +218,11 @@ public class TlvBufferUtilsTest { equalTo(nonAscii.getBytes().length)); collector.checkThat("tlv02-correct-iteration-DATA", tlv.getString().equals(nonAscii), equalTo(true)); + } else if (count == 3) { + collector.checkThat("tlv02-correct-iteration-mLength", tlv.length, + equalTo(5)); + collector.checkThat("tlv02-correct-iteration-DATA", tlv.getRawData(), + equalTo(new byte[]{5, 4, 3, 2, 1})); } else { collector.checkThat("Invalid number of iterations in loop - tlv02", true, equalTo(false)); @@ -188,7 +230,7 @@ public class TlvBufferUtilsTest { ++count; } collector.checkThat("Invalid number of iterations outside loop - tlv02", count, - equalTo(3)); + equalTo(4)); collector.checkThat("tlv22-valid", TlvBufferUtils.isValid(tlv22.getArray(), 2, 2), diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java index 6da6d4adeb62..3cc96bf2c795 100644 --- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java +++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java @@ -1614,23 +1614,31 @@ public class WifiAwareManagerTest { assertEquals(cap.hashCode(), rereadCap.hashCode()); } - // PeerHandle tests + // ParcelablePeerHandle tests + /** + * Verify parceling of ParcelablePeerHandle and interoperability with PeerHandle. + */ @Test - public void testPeerHandleParcel() { + public void testParcelablePeerHandleParcel() { final PeerHandle peerHandle = new PeerHandle(5); + final ParcelablePeerHandle parcelablePeerHandle = new ParcelablePeerHandle(peerHandle); Parcel parcelW = Parcel.obtain(); - peerHandle.writeToParcel(parcelW, 0); + parcelablePeerHandle.writeToParcel(parcelW, 0); byte[] bytes = parcelW.marshall(); parcelW.recycle(); Parcel parcelR = Parcel.obtain(); parcelR.unmarshall(bytes, 0, bytes.length); parcelR.setDataPosition(0); - PeerHandle rereadPeerHandle = PeerHandle.CREATOR.createFromParcel(parcelR); + ParcelablePeerHandle rereadParcelablePeerHandle = + ParcelablePeerHandle.CREATOR.createFromParcel(parcelR); + + assertEquals(peerHandle, rereadParcelablePeerHandle); + assertEquals(peerHandle.hashCode(), rereadParcelablePeerHandle.hashCode()); + assertEquals(parcelablePeerHandle, rereadParcelablePeerHandle); + assertEquals(parcelablePeerHandle.hashCode(), rereadParcelablePeerHandle.hashCode()); - assertEquals(peerHandle, rereadPeerHandle); - assertEquals(peerHandle.hashCode(), rereadPeerHandle.hashCode()); } } |