diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2019-02-12 04:11:52 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2019-02-12 04:11:52 +0000 |
commit | 13327cc461d8f54550866bc404a99205f95ab92f (patch) | |
tree | 3bbca8b95f5be9a8b82ad5a6fe31282a01cb376f | |
parent | 295083e9e621c9b9e790b304c087858c329e5074 (diff) | |
parent | 9f6f2e7990dd14b89f03a4ce8dd8c648c9ff2855 (diff) |
Snap for 5301221 from 9f6f2e7990dd14b89f03a4ce8dd8c648c9ff2855 to qt-release
Change-Id: Ib7179b6a319109199da3b3d01a987451dd9e3f74
207 files changed, 3510 insertions, 876 deletions
diff --git a/api/current.txt b/api/current.txt index c0d10a6bc20a..c5cd57378a9d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -30111,10 +30111,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 { @@ -45593,6 +45597,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 { @@ -48997,6 +49478,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); @@ -52612,7 +53094,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; @@ -52637,7 +53118,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); @@ -55870,11 +56350,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); @@ -56375,6 +56860,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(); @@ -56672,13 +57158,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); } @@ -61199,9 +61690,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/system-current.txt b/api/system-current.txt index 3a5023992074..bb34f6859887 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -205,6 +205,7 @@ package android { } 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 @@ -239,6 +240,8 @@ package android { 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 @@ -1148,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); @@ -5784,6 +5787,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"; @@ -7016,6 +7024,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 @@ -7831,6 +7840,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 9e266d86299d..1a7e4cb83c52 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1785,12 +1785,19 @@ 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 { field public static final String NAMESPACE = "privacy"; field public static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "location_access_check_enabled"; @@ -1813,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"; @@ -2156,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); } @@ -2168,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 { @@ -2680,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 } 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/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 7ddb783d71e1..da7e4daaf22b 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -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. @@ -2176,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; } @@ -5503,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/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h index 2999b649a509..ea3f3b32b0c4 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -511,6 +511,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/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp index 6069516e9666..92aa998d9720 100644 --- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp +++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp @@ -278,6 +278,39 @@ TEST(StatsdStatsTest, TestPullAtomStats) { EXPECT_EQ(3335L, report.pulled_atom_stats(0).max_pull_delay_nanos()); } +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) { StatsdStats stats; stats.noteRegisteredAnomalyAlarmChanged(); 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/role/RoleManager.java b/core/java/android/app/role/RoleManager.java index 04d5c5aaa1d5..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. @@ -173,15 +182,6 @@ public final class RoleManager { public static final String ROLE_CALL_COMPANION = "android.app.role.CALL_COMPANION"; /** - * The name of the assistant app role. - * - * @hide - */ - @SystemApi - @TestApi - public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT"; - - /** * @hide */ @IntDef(flag = true, value = { MANAGE_HOLDERS_FLAG_DONT_KILL_APP }) 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/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/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 96b6eb527002..0abd5eaaf2aa 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -3747,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/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/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/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 41d3cbb88f5c..ec4f397ff70b 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -69,6 +69,7 @@ public final class DeviceConfig { * @hide */ @SystemApi + @TestApi public static final String NAMESPACE_AUTOFILL = "autofill"; /** @@ -308,6 +309,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 = @@ -399,6 +419,7 @@ public final class DeviceConfig { * @see #removeOnPropertyChangedListener(OnPropertyChangedListener) */ @SystemApi + @TestApi @RequiresPermission(READ_DEVICE_CONFIG) public static void addOnPropertyChangedListener( @NonNull String namespace, @@ -432,6 +453,7 @@ public final class DeviceConfig { * @see #addOnPropertyChangedListener(String, Executor, OnPropertyChangedListener) */ @SystemApi + @TestApi public static void removeOnPropertyChangedListener( OnPropertyChangedListener onPropertyChangedListener) { synchronized (sLock) { @@ -528,6 +550,7 @@ public final class DeviceConfig { * @hide */ @SystemApi + @TestApi public interface OnPropertyChangedListener { /** * Called when a property has changed. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index de84e713a6f7..3747ec6f4003 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -13285,17 +13285,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 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/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/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index 3f18d8b46e2a..39b6876d86c7 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -95,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; 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/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/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/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/textclassifier/TEST_MAPPING b/core/java/android/view/textclassifier/TEST_MAPPING new file mode 100644 index 000000000000..0d3c3465f2d6 --- /dev/null +++ b/core/java/android/view/textclassifier/TEST_MAPPING @@ -0,0 +1,23 @@ +{ + "presubmit": [ + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "android.view.textclassifier" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "CtsViewTestCases", + "options": [ + { + "include-filter": "android.view.textclassifier.cts" + } + ] + } + ] +} diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 9d7a482aa611..4b7c393b1b96 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -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; @@ -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) { 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/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 7ed7aa293f21..904a86261e6c 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -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; } 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 800b19cdd77e..9ae62ef8ab7a 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -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/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..89bb2738b899 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -639,6 +639,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); 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 c3609038b08f..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. @@ -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/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/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/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_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/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/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 a501ae2661c6..130f6291b516 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1951,6 +1951,10 @@ <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 --> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index d5cefc4e4818..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"> @@ -2979,6 +2981,10 @@ <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"> 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 410a8c168b5d..8e251fd4ea6f 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3643,4 +3643,6 @@ <java-symbol type="array" name="config_displayWhiteBalanceDecreaseThresholds" /> <java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientBrightnessThreshold" /> <java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientColorTemperature" /> + + <java-symbol type="drawable" name="ic_action_open" /> </resources> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index ec57f793f15f..206682a1955b 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, 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/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java index bdd03707c1f1..d2d03e565522 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java @@ -382,7 +382,6 @@ public class TextClassifierTest { assertThat(textLanguage, isTextLanguage("ja")); } - /* DISABLED: b/122467291 @Test public void testSuggestConversationActions_textReplyOnly_maxThree() { if (isTextClassifierDisabled()) return; @@ -410,7 +409,7 @@ public class TextClassifierTest { assertThat(conversationAction, isConversationAction(ConversationAction.TYPE_TEXT_REPLY)); } - }*/ + } @Test public void testSuggestConversationActions_textReplyOnly_noMax() { 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/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/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/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/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/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/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/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/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/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/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..db92ed258064 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1573,12 +1573,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 +2307,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/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index fc1843ba982a..822920e63460 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -187,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; 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/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 f6f3fa646232..2b344f6cf195 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -773,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(); } @@ -784,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(); @@ -800,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/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/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/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/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/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/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java index 5d03f19f4655..b0d1106ecb24 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java @@ -35,7 +35,6 @@ 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; @@ -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/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/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/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/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/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/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java index eaf790bb05c4..8ccb6e20a614 100644 --- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java +++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java @@ -328,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); } @@ -360,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; } 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/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/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/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/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index 18e292feba30..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, diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 6c3e1f4ce1c2..00105be87cd4 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -188,6 +188,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; @@ -843,7 +844,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); @@ -967,7 +968,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); @@ -5765,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)"); 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/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/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index e27dd94b1a2c..21a4e8417bab 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -72,8 +72,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 +90,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 +111,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(); @@ -657,12 +669,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 +681,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/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/TestSystemServices.java b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java index b151fb7a613c..1c1fe29bd7cc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java @@ -88,6 +88,7 @@ class TestSystemServices { sPolicy = null; sMockitoSession.finishMocking(); + sMockitoSession = null; } private static void setUpTestWindowService() { 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/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java index b6b9a861a282..2970c211e29c 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; @@ -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/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/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/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/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/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/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index f5d452e9721d..2a03924fd58c 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -10309,11 +10309,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/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/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()); } } |