diff options
311 files changed, 5212 insertions, 1433 deletions
diff --git a/Android.bp b/Android.bp index 7bdedc79943d..0848d2b7668e 100644 --- a/Android.bp +++ b/Android.bp @@ -804,6 +804,7 @@ filegroup { srcs: [ "core/java/android/os/IStatsCompanionService.aidl", "core/java/android/os/IStatsManager.aidl", + "core/java/android/os/IStatsPullerCallback.aidl", ], } diff --git a/Android.mk b/Android.mk index 9c65948f4838..9a91dd1c491a 100644 --- a/Android.mk +++ b/Android.mk @@ -72,6 +72,9 @@ $(OUT_DOCS)/offline-sdk-timestamp: $(OUT_DOCS)/offline-sdk-docs-docs.zip $(hide) mkdir -p $(OUT_DOCS)/offline-sdk ( unzip -qo $< -d $(OUT_DOCS)/offline-sdk && touch -f $@ ) || exit 1 +.PHONY: docs offline-sdk-docs +docs offline-sdk-docs: $(OUT_DOCS)/offline-sdk-timestamp + # Run this for checkbuild checkbuild: doc-comment-check-docs # Check comment when you are updating the API diff --git a/api/current.txt b/api/current.txt index 91f5cef85e56..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); @@ -56015,6 +56500,7 @@ package android.widget { method @Nullable public android.view.View getAnchorView(); method @StyleRes public int getAnimationStyle(); method @Nullable public android.graphics.drawable.Drawable getBackground(); + method @Nullable public android.graphics.Rect getEpicenterBounds(); method public int getHeight(); method public int getHorizontalOffset(); method public int getInputMethodMode(); @@ -56041,6 +56527,7 @@ package android.widget { method public void setBackgroundDrawable(@Nullable android.graphics.drawable.Drawable); method public void setContentWidth(int); method public void setDropDownGravity(int); + method public void setEpicenterBounds(@Nullable android.graphics.Rect); method public void setHeight(int); method public void setHorizontalOffset(int); method public void setInputMethodMode(int); @@ -56373,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(); @@ -56670,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); } @@ -61197,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..f673827a8633 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); @@ -5776,6 +5779,11 @@ package android.provider { field public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled"; } + public static interface DeviceConfig.Runtime { + field public static final String NAMESPACE = "runtime"; + field public static final String USE_PRECOMPILED_LAYOUT = "view.precompiled_layout_enabled"; + } + public static interface DeviceConfig.RuntimeNative { field public static final String NAMESPACE = "runtime_native"; } @@ -5784,6 +5792,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 +7029,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 +7845,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/Android.bp b/cmds/statsd/Android.bp index d6f045ea43fd..faf2053835fa 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -71,6 +71,7 @@ cc_defaults { "src/external/Perfetto.cpp", "src/external/Perfprofd.cpp", "src/external/StatsPuller.cpp", + "src/external/StatsCallbackPuller.cpp", "src/external/StatsCompanionServicePuller.cpp", "src/external/SubsystemSleepStatePuller.cpp", "src/external/PowerStatsPuller.cpp", diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 86bf3eca3ee6..bd21a955729d 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -1057,6 +1057,24 @@ Status StatsService::sendAppBreadcrumbAtom(int32_t label, int32_t state) { return Status::ok(); } +Status StatsService::registerPullerCallback(int32_t atomTag, + const sp<android::os::IStatsPullerCallback>& pullerCallback, + const String16& packageName) { + ENFORCE_DUMP_AND_USAGE_STATS(packageName); + + VLOG("StatsService::registerPullerCallback called."); + mPullerManager->RegisterPullerCallback(atomTag, pullerCallback); + return Status::ok(); +} + +Status StatsService::unregisterPullerCallback(int32_t atomTag, const String16& packageName) { + ENFORCE_DUMP_AND_USAGE_STATS(packageName); + + VLOG("StatsService::unregisterPullerCallback called."); + mPullerManager->UnregisterPullerCallback(atomTag); + return Status::ok(); +} + hardware::Return<void> StatsService::reportSpeakerImpedance( const SpeakerImpedance& speakerImpedance) { LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), speakerImpedance); diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index cdff50fcb62e..941ed462b303 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -173,6 +173,19 @@ public: virtual Status sendAppBreadcrumbAtom(int32_t label, int32_t state) override; /** + * Binder call to register a callback function for a vendor pulled atom. + * Note: this atom must NOT have uid as a field. + */ + virtual Status registerPullerCallback(int32_t atomTag, + const sp<android::os::IStatsPullerCallback>& pullerCallback, + const String16& packageName) override; + + /** + * Binder call to unregister any existing callback function for a vendor pulled atom. + */ + virtual Status unregisterPullerCallback(int32_t atomTag, const String16& packageName) override; + + /** * Binder call to get SpeakerImpedance atom. */ virtual Return<void> reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) override; diff --git a/cmds/statsd/src/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/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp new file mode 100644 index 000000000000..d718273e9b85 --- /dev/null +++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define DEBUG false // STOPSHIP if true +#include "Log.h" + +#include <android/os/IStatsPullerCallback.h> + +#include "StatsCallbackPuller.h" +#include "logd/LogEvent.h" +#include "stats_log_util.h" + +using namespace android::binder; + +namespace android { +namespace os { +namespace statsd { + +StatsCallbackPuller::StatsCallbackPuller(int tagId, const sp<IStatsPullerCallback>& callback) : + StatsPuller(tagId), mCallback(callback) { + VLOG("StatsCallbackPuller created for tag %d", tagId); +} + +bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) { + VLOG("StatsCallbackPuller called for tag %d", mTagId) + if(mCallback == nullptr) { + ALOGW("No callback registered"); + return false; + } + int64_t wallClockTimeNs = getWallClockNs(); + int64_t elapsedTimeNs = getElapsedRealtimeNs(); + vector<StatsLogEventWrapper> returned_value; + Status status = mCallback->pullData(mTagId, elapsedTimeNs, wallClockTimeNs, &returned_value); + if (!status.isOk()) { + ALOGW("StatsCallbackPuller::pull failed for %d", mTagId); + return false; + } + data->clear(); + for (const StatsLogEventWrapper& it: returned_value) { + LogEvent::createLogEvents(it, *data); + } + VLOG("StatsCallbackPuller::pull succeeded for %d", mTagId); + return true; +} + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/media/java/android/media/session/MediaSessionProviderService.java b/cmds/statsd/src/external/StatsCallbackPuller.h index 9a346ff4a12e..c4bfa89ba9a7 100644 --- a/media/java/android/media/session/MediaSessionProviderService.java +++ b/cmds/statsd/src/external/StatsCallbackPuller.h @@ -14,22 +14,25 @@ * limitations under the License. */ -package android.media.session; +#pragma once -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; +#include <android/os/IStatsPullerCallback.h> +#include <utils/String16.h> +#include "StatsPuller.h" -/** - * Abstract class for mainline module services. - * - * @hide // TODO: Make it as a @SystemApi - */ -public abstract class MediaSessionProviderService extends Service { +namespace android { +namespace os { +namespace statsd { + +class StatsCallbackPuller : public StatsPuller { +public: + explicit StatsCallbackPuller(int tagId, const sp<IStatsPullerCallback>& callback); + +private: + bool PullInternal(vector<std::shared_ptr<LogEvent> >* data) override; + const sp<IStatsPullerCallback> mCallback; +}; - @Override - public IBinder onBind(Intent intent) { - // TODO: Return IMediaSessionProviderService.Stub() - return null; - } -} +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp index c7c22ee85f0f..9552c0a5e35e 100644 --- a/cmds/statsd/src/external/StatsPuller.cpp +++ b/cmds/statsd/src/external/StatsPuller.cpp @@ -33,7 +33,7 @@ sp<UidMap> StatsPuller::mUidMap = nullptr; void StatsPuller::SetUidMap(const sp<UidMap>& uidMap) { mUidMap = uidMap; } StatsPuller::StatsPuller(const int tagId) - : mTagId(tagId) { + : mTagId(tagId), mLastPullTimeNs(0) { } bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) { diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index ecdcd21d44dd..ed72b2914a34 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -18,6 +18,7 @@ #include "Log.h" #include <android/os/IStatsCompanionService.h> +#include <android/os/IStatsPullerCallback.h> #include <cutils/log.h> #include <math.h> #include <stdint.h> @@ -29,6 +30,7 @@ #include "PowerStatsPuller.h" #include "ResourceHealthManagerPuller.h" #include "StatsCompanionServicePuller.h" +#include "StatsCallbackPuller.h" #include "StatsPullerManager.h" #include "SubsystemSleepStatePuller.h" #include "statslog.h" @@ -49,7 +51,7 @@ namespace statsd { // Values smaller than this may require to update the alarm. const int64_t NO_ALARM_UPDATE = INT64_MAX; -const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { +std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // wifi_bytes_transfer {android::util::WIFI_BYTES_TRANSFER, {.additiveFields = {2, 3, 4, 5}, @@ -420,6 +422,30 @@ int StatsPullerManager::ClearPullerCacheIfNecessary(int64_t timestampNs) { return totalCleared; } +void StatsPullerManager::RegisterPullerCallback(int32_t atomTag, + const sp<IStatsPullerCallback>& callback) { + AutoMutex _l(mLock); + // Platform pullers cannot be changed. + if (atomTag < StatsdStats::kMaxPlatformAtomTag) { + VLOG("RegisterPullerCallback: atom tag %d is less than min tag %d", + atomTag, StatsdStats::kMaxPlatformAtomTag); + return; + } + VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag); + StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true); + kAllPullAtomInfo[atomTag] = {.puller = new StatsCallbackPuller(atomTag, callback)}; +} + +void StatsPullerManager::UnregisterPullerCallback(int32_t atomTag) { + AutoMutex _l(mLock); + // Platform pullers cannot be changed. + if (atomTag < StatsdStats::kMaxPlatformAtomTag) { + return; + } + StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/false); + kAllPullAtomInfo.erase(atomTag); +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h index 807e4af03dae..45f6b3568143 100644 --- a/cmds/statsd/src/external/StatsPullerManager.h +++ b/cmds/statsd/src/external/StatsPullerManager.h @@ -17,6 +17,7 @@ #pragma once #include <android/os/IStatsCompanionService.h> +#include <android/os/IStatsPullerCallback.h> #include <binder/IServiceManager.h> #include <utils/RefBase.h> #include <utils/threads.h> @@ -91,7 +92,12 @@ public: void SetStatsCompanionService(sp<IStatsCompanionService> statsCompanionService); - const static std::map<int, PullAtomInfo> kAllPullAtomInfo; + void RegisterPullerCallback(int32_t atomTag, + const sp<IStatsPullerCallback>& callback); + + void UnregisterPullerCallback(int32_t atomTag); + + static std::map<int, PullAtomInfo> kAllPullAtomInfo; private: sp<IStatsCompanionService> mStatsCompanionService = nullptr; diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp index c4034ffeee22..40329b7c86ab 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.cpp +++ b/cmds/statsd/src/guardrail/StatsdStats.cpp @@ -423,6 +423,15 @@ void StatsdStats::noteEmptyData(int atomId) { mPulledAtomStats[atomId].emptyData++; } +void StatsdStats::notePullerCallbackRegistrationChanged(int atomId, bool registered) { + lock_guard<std::mutex> lock(mLock); + if (registered) { + mPulledAtomStats[atomId].registeredCount++; + } else { + mPulledAtomStats[atomId].unregisteredCount++; + } +} + void StatsdStats::noteHardDimensionLimitReached(int64_t metricId) { lock_guard<std::mutex> lock(mLock); getAtomMetricStats(metricId).hardDimensionLimitReached++; @@ -514,6 +523,8 @@ void StatsdStats::resetInternalLocked() { pullStats.second.dataError = 0; pullStats.second.pullTimeout = 0; pullStats.second.pullExceedMaxDelay = 0; + pullStats.second.registeredCount = 0; + pullStats.second.unregisteredCount = 0; } mAtomMetricStats.clear(); } @@ -625,12 +636,14 @@ void StatsdStats::dumpStats(int out) const { " (average pull time nanos)%lld, (max pull time nanos)%lld, (average pull delay " "nanos)%lld, " " (max pull delay nanos)%lld, (data error)%ld\n" - " (pull timeout)%ld, (pull exceed max delay)%ld\n", + " (pull timeout)%ld, (pull exceed max delay)%ld\n" + " (registered count) %ld, (unregistered count) %ld\n", (int)pair.first, (long)pair.second.totalPull, (long)pair.second.totalPullFromCache, (long)pair.second.minPullIntervalSec, (long long)pair.second.avgPullTimeNs, (long long)pair.second.maxPullTimeNs, (long long)pair.second.avgPullDelayNs, (long long)pair.second.maxPullDelayNs, pair.second.dataError, - pair.second.pullTimeout, pair.second.pullExceedMaxDelay); + pair.second.pullTimeout, pair.second.pullExceedMaxDelay, + pair.second.registeredCount, pair.second.unregisteredCount); } if (mAnomalyAlarmRegisteredStats > 0) { diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h index 2999b649a509..65e8a324d7d3 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -146,6 +146,10 @@ public: // Max time to do a pull. static const int64_t kPullMaxDelayNs = 10 * NS_PER_SEC; + + // Max platform atom tag number. + static const int32_t kMaxPlatformAtomTag = 100000; + /** * Report a new config has been received and report the static stats about the config. * @@ -340,6 +344,13 @@ public: void noteEmptyData(int atomId); /** + * Records that a puller callback for the given atomId was registered or unregistered. + * + * @param registered True if the callback was registered, false if was unregistered. + */ + void notePullerCallbackRegistrationChanged(int atomId, bool registered); + + /** * Hard limit was reached in the cardinality of an atom */ void noteHardDimensionLimitReached(int64_t metricId); @@ -416,6 +427,8 @@ public: long statsCompanionPullFailed = 0; long statsCompanionPullBinderTransactionFailed = 0; long emptyData = 0; + long registeredCount = 0; + long unregisteredCount = 0; } PulledAtomStats; typedef struct { @@ -511,6 +524,7 @@ private: FRIEND_TEST(StatsdStatsTest, TestAnomalyMonitor); FRIEND_TEST(StatsdStatsTest, TestSystemServerCrash); FRIEND_TEST(StatsdStatsTest, TestPullAtomStats); + FRIEND_TEST(StatsdStatsTest, TestAtomMetricsStats); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index ac6c27adceaa..851ae9962d09 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -450,6 +450,17 @@ void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<Log } mMatchedMetricDimensionKeys.clear(); mHasGlobalBase = true; + + // If we reach the guardrail, we might have dropped some data which means the bucket is + // incomplete. + // + // The base also needs to be reset. If we do not have the full data, we might + // incorrectly compute the diff when mUseZeroDefaultBase is true since an existing key + // might be missing from mCurrentSlicedBucket. + if (hasReachedGuardRailLimit()) { + invalidateCurrentBucket(); + mCurrentSlicedBucket.clear(); + } } void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { @@ -471,6 +482,10 @@ void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { } } +bool ValueMetricProducer::hasReachedGuardRailLimit() const { + return mCurrentSlicedBucket.size() >= mDimensionHardLimit; +} + bool ValueMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) { // ===========GuardRail============== // 1. Report the tuple count if the tuple count > soft limit @@ -481,7 +496,7 @@ bool ValueMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) { size_t newTupleCount = mCurrentSlicedBucket.size() + 1; StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount); // 2. Don't add more tuples, we are above the allowed threshold. Drop the data. - if (newTupleCount > mDimensionHardLimit) { + if (hasReachedGuardRailLimit()) { ALOGE("ValueMetric %lld dropping data for dimension key %s", (long long)mMetricId, newKey.toString().c_str()); StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId); diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index d1c2315b28be..f26ad85acf05 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -158,6 +158,7 @@ private: // Util function to check whether the specified dimension hits the guardrail. bool hitGuardRailLocked(const MetricDimensionKey& newKey); + bool hasReachedGuardRailLimit() const; bool hitFullBucketGuardRailLocked(const MetricDimensionKey& newKey); @@ -244,6 +245,7 @@ private: FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket); FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate); FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed); + FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit); FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed); FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed); FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded); diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index 6a07a3f169e0..863261ae1626 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -407,6 +407,8 @@ message StatsdStatsReport { optional int64 stats_companion_pull_failed = 13; optional int64 stats_companion_pull_binder_transaction_failed = 14; optional int64 empty_data = 15; + optional int64 registered_count = 16; + optional int64 unregistered_count = 17; } repeated PulledAtomStats pulled_atom_stats = 10; diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp index aa8cfc508861..0ebf2ca4e035 100644 --- a/cmds/statsd/src/stats_log_util.cpp +++ b/cmds/statsd/src/stats_log_util.cpp @@ -70,6 +70,8 @@ const int FIELD_ID_PULL_FAILED = 12; const int FIELD_ID_STATS_COMPANION_FAILED = 13; const int FIELD_ID_STATS_COMPANION_BINDER_TRANSACTION_FAILED = 14; const int FIELD_ID_EMPTY_DATA = 15; +const int FIELD_ID_PULL_REGISTERED_COUNT = 16; +const int FIELD_ID_PULL_UNREGISTERED_COUNT = 17; // for AtomMetricStats proto const int FIELD_ID_ATOM_METRIC_STATS = 17; const int FIELD_ID_METRIC_ID = 1; @@ -480,6 +482,10 @@ void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats> (long long)pair.second.statsCompanionPullBinderTransactionFailed); protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_EMPTY_DATA, (long long)pair.second.emptyData); + protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_REGISTERED_COUNT, + (long long) pair.second.registeredCount); + protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_UNREGISTERED_COUNT, + (long long) pair.second.unregisteredCount); protoOutput->end(token); } diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp index 6069516e9666..44a88f049443 100644 --- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp +++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp @@ -259,6 +259,10 @@ TEST(StatsdStatsTest, TestPullAtomStats) { stats.notePullDelay(android::util::DISK_SPACE, 3335L); stats.notePull(android::util::DISK_SPACE); stats.notePullFromCache(android::util::DISK_SPACE); + stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, true); + stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, false); + stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, true); + vector<uint8_t> output; stats.dumpStats(&output, false); @@ -276,6 +280,41 @@ TEST(StatsdStatsTest, TestPullAtomStats) { EXPECT_EQ(3333L, report.pulled_atom_stats(0).max_pull_time_nanos()); EXPECT_EQ(2223L, report.pulled_atom_stats(0).average_pull_delay_nanos()); EXPECT_EQ(3335L, report.pulled_atom_stats(0).max_pull_delay_nanos()); + EXPECT_EQ(2L, report.pulled_atom_stats(0).registered_count()); + EXPECT_EQ(1L, report.pulled_atom_stats(0).unregistered_count()); +} + +TEST(StatsdStatsTest, TestAtomMetricsStats) { + StatsdStats stats; + time_t now = time(nullptr); + // old event, we get it from the stats buffer. should be ignored. + stats.noteBucketDropped(1000L); + + stats.noteBucketBoundaryDelayNs(1000L, -1L); + stats.noteBucketBoundaryDelayNs(1000L, -10L); + stats.noteBucketBoundaryDelayNs(1000L, 2L); + + stats.noteBucketBoundaryDelayNs(1001L, 1L); + + vector<uint8_t> output; + stats.dumpStats(&output, false); + StatsdStatsReport report; + bool good = report.ParseFromArray(&output[0], output.size()); + EXPECT_TRUE(good); + + EXPECT_EQ(2, report.atom_metric_stats().size()); + + auto atomStats = report.atom_metric_stats(0); + EXPECT_EQ(1000L, atomStats.metric_id()); + EXPECT_EQ(1L, atomStats.bucket_dropped()); + EXPECT_EQ(-10L, atomStats.min_bucket_boundary_delay_ns()); + EXPECT_EQ(2L, atomStats.max_bucket_boundary_delay_ns()); + + auto atomStats2 = report.atom_metric_stats(1); + EXPECT_EQ(1001L, atomStats2.metric_id()); + EXPECT_EQ(0L, atomStats2.bucket_dropped()); + EXPECT_EQ(0L, atomStats2.min_bucket_boundary_delay_ns()); + EXPECT_EQ(1L, atomStats2.max_bucket_boundary_delay_ns()); } TEST(StatsdStatsTest, TestAnomalyMonitor) { diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index ae3cdbcb5eb4..572b1991f426 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -2390,6 +2390,51 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed) { EXPECT_EQ(true, valueProducer.mHasGlobalBase); } +TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit) { + ValueMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.mutable_value_field()->set_field(tagId); + metric.mutable_value_field()->add_child()->set_field(2); + metric.mutable_dimensions_in_what()->set_field(tagId); + metric.mutable_dimensions_in_what()->add_child()->set_field(1); + metric.set_condition(StringToId("SCREEN_ON")); + metric.set_max_pull_delay_sec(INT_MAX); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); + + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + // First onConditionChanged + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + for (int i = 0; i < 2000; i++) { + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); + event->write(i); + event->write(i); + event->init(); + data->push_back(event); + } + return true; + })); + + ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex, + eventMatcherWizard, tagId, bucketStartTimeNs, + bucketStartTimeNs, pullerManager); + + valueProducer.mCondition = false; + valueProducer.onConditionChanged(true, bucket2StartTimeNs + 2); + EXPECT_EQ(true, valueProducer.mCurrentBucketIsInvalid); + EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size()); +} + TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed) { ValueMetric metric; metric.set_id(metricId); 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/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index db6ad3df17b0..2b765b2284e7 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -247,8 +247,20 @@ interface IActivityTaskManager { boolean preserveWindows, boolean animate, int animationDuration); boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop, boolean animate, in Rect initialBounds, boolean showRecents); - - + /** + * Use the offset to adjust the stack boundary with animation. + * + * @param stackId Id of the stack to adjust. + * @param compareBounds Offset is only applied if the current pinned stack bounds is equal to + * the compareBounds. + * @param xOffset The horizontal offset. + * @param yOffset The vertical offset. + * @param animationDuration The duration of the resize animation in milliseconds or -1 if the + * default animation duration should be used. + * @throws RemoteException + */ + void offsetPinnedStackBounds(int stackId, in Rect compareBounds, int xOffset, int yOffset, + int animationDuration); /** * Removes stacks in the input windowing modes from the system if they are of activity type * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java index 3119b37a686e..7746148d325a 100644 --- a/core/java/android/app/StatsManager.java +++ b/core/java/android/app/StatsManager.java @@ -24,6 +24,7 @@ import android.annotation.SystemApi; import android.content.Context; import android.os.IBinder; import android.os.IStatsManager; +import android.os.IStatsPullerCallback; import android.os.RemoteException; import android.os.ServiceManager; import android.util.AndroidException; @@ -408,6 +409,39 @@ public final class StatsManager { } } + /** + * Registers a callback for an atom when that atom is to be pulled. The stats service will + * invoke pullData in the callback when the stats service determines that this atom needs to be + * pulled. Currently, this only works for atoms with tags above 100,000 that do not have a uid. + * + * @param atomTag The tag of the atom for this puller callback. Must be at least 100000. + * @param callback The callback to be invoked when the stats service pulls the atom. + * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service + * + * @hide + */ + @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS }) + public void setPullerCallback(int atomTag, IStatsPullerCallback callback) + throws StatsUnavailableException { + synchronized (this) { + try { + IStatsManager service = getIStatsManagerLocked(); + if (callback == null) { + service.unregisterPullerCallback(atomTag, mContext.getOpPackageName()); + } else { + service.registerPullerCallback(atomTag, callback, + mContext.getOpPackageName()); + } + + } catch (RemoteException e) { + Slog.e(TAG, "Failed to connect to statsd when registering data listener."); + throw new StatsUnavailableException("could not connect", e); + } catch (SecurityException e) { + throw new StatsUnavailableException(e.getMessage(), e); + } + } + } + private class StatsdDeathRecipient implements IBinder.DeathRecipient { @Override public void binderDied() { diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index 077b177be930..dd00e5a74382 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -97,6 +97,12 @@ public class TaskInfo { public long lastActiveTime; /** + * The id of the display this task is associated with. + * @hide + */ + public int displayId; + + /** * The recent activity values for the highest activity in the stack to have set the values. * {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}. */ @@ -152,6 +158,7 @@ public class TaskInfo { userId = source.readInt(); stackId = source.readInt(); taskId = source.readInt(); + displayId = source.readInt(); isRunning = source.readBoolean(); baseIntent = source.readInt() != 0 ? Intent.CREATOR.createFromParcel(source) @@ -179,6 +186,7 @@ public class TaskInfo { dest.writeInt(userId); dest.writeInt(stackId); dest.writeInt(taskId); + dest.writeInt(displayId); dest.writeBoolean(isRunning); if (baseIntent != null) { @@ -209,6 +217,7 @@ public class TaskInfo { @Override public String toString() { return "TaskInfo{userId=" + userId + " stackId=" + stackId + " taskId=" + taskId + + " displayId=" + displayId + " isRunning=" + isRunning + " baseIntent=" + baseIntent + " baseActivity=" + baseActivity + " topActivity=" + topActivity + " origActivity=" + origActivity diff --git a/core/java/android/app/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/net/INetworkMonitorCallbacks.aidl b/core/java/android/net/INetworkMonitorCallbacks.aidl index a8682f9ddd3b..514658549651 100644 --- a/core/java/android/net/INetworkMonitorCallbacks.aidl +++ b/core/java/android/net/INetworkMonitorCallbacks.aidl @@ -24,7 +24,7 @@ oneway interface INetworkMonitorCallbacks { void onNetworkMonitorCreated(in INetworkMonitor networkMonitor); void notifyNetworkTested(int testResult, @nullable String redirectUrl); void notifyPrivateDnsConfigResolved(in PrivateDnsConfigParcel config); - void showProvisioningNotification(String action); + void showProvisioningNotification(String action, String packageName); void hideProvisioningNotification(); void logCaptivePortalLoginEvent(int eventId, String packageName); }
\ No newline at end of file diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java index b6cd6359384a..7a4c9bc16ac7 100644 --- a/core/java/android/net/NetworkStack.java +++ b/core/java/android/net/NetworkStack.java @@ -63,9 +63,6 @@ public class NetworkStack { public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK"; - /** @hide */ - public static final String NETWORKSTACK_PACKAGE_NAME = "com.android.mainline.networkstack"; - private static final int NETWORKSTACK_TIMEOUT_MS = 10_000; @NonNull diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 629289bb7a45..0384faa88be5 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -1093,6 +1093,12 @@ public class FileUtils { return buildUniqueFileWithExtension(parent, parts[0], parts[1]); } + /** {@hide} */ + public static File buildNonUniqueFile(File parent, String mimeType, String displayName) { + final String[] parts = splitFileName(mimeType, displayName); + return buildFile(parent, parts[0], parts[1]); + } + /** * Generates a unique file name under the given parent directory, keeping * any extension intact. diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl index 93d6f4c12128..f1bba1ab2977 100644 --- a/core/java/android/os/IStatsManager.aidl +++ b/core/java/android/os/IStatsManager.aidl @@ -16,6 +16,8 @@ package android.os; +import android.os.IStatsPullerCallback; + /** * Binder interface to communicate with the statistics management service. * {@hide} @@ -178,4 +180,20 @@ interface IStatsManager { * this label. This allows building custom metrics and predicates. */ void sendAppBreadcrumbAtom(int label, int state); + + /** + * Registers a puller callback function that, when invoked, pulls the data + * for the specified vendor atom tag. + * + * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS + */ + oneway void registerPullerCallback(int atomTag, IStatsPullerCallback pullerCallback, + String packageName); + + /** + * Unregisters a puller callback function for the given vendor atom. + * + * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS + */ + oneway void unregisterPullerCallback(int atomTag, String packageName); } diff --git a/core/java/android/os/IStatsPullerCallback.aidl b/core/java/android/os/IStatsPullerCallback.aidl new file mode 100644 index 000000000000..1684aeb0d666 --- /dev/null +++ b/core/java/android/os/IStatsPullerCallback.aidl @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.os.StatsLogEventWrapper; + +/** + * Binder interface to pull atoms for the stats service. + * {@hide} + */ +interface IStatsPullerCallback { + /** + * Pull data for the specified atom tag. Returns an array of StatsLogEventWrapper containing + * the data. + * + * Note: These pulled atoms should not have uid/attribution chain. Additionally, the event + * timestamps will be truncated to the nearest 5 minutes. + */ + StatsLogEventWrapper[] pullData(int atomTag, long elapsedNanos, long wallClocknanos); + +} diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java index acb9eac3572c..23342426693a 100644 --- a/core/java/android/os/StatsLogEventWrapper.java +++ b/core/java/android/os/StatsLogEventWrapper.java @@ -57,20 +57,18 @@ public final class StatsLogEventWrapper implements Parcelable { public static final Parcelable.Creator<StatsLogEventWrapper> CREATOR = new Parcelable.Creator<StatsLogEventWrapper>() { public StatsLogEventWrapper createFromParcel(Parcel in) { - android.util.EventLog.writeEvent(0x534e4554, "112550251", - android.os.Binder.getCallingUid(), ""); - // Purposefully leaving this method not implemented. - throw new RuntimeException("Not implemented"); + return new StatsLogEventWrapper(in); } public StatsLogEventWrapper[] newArray(int size) { - android.util.EventLog.writeEvent(0x534e4554, "112550251", - android.os.Binder.getCallingUid(), ""); - // Purposefully leaving this method not implemented. - throw new RuntimeException("Not implemented"); + return new StatsLogEventWrapper[size]; } }; + private StatsLogEventWrapper(Parcel in) { + readFromParcel(in); + } + /** * Set work source if any. */ @@ -197,6 +195,70 @@ public final class StatsLogEventWrapper implements Parcelable { } /** + * Reads from parcel and appropriately fills member fields. + */ + public void readFromParcel(Parcel in) { + mTypes = new ArrayList<>(); + mValues = new ArrayList<>(); + mWorkSource = null; + + mTag = in.readInt(); + mElapsedTimeNs = in.readLong(); + mWallClockTimeNs = in.readLong(); + + // Clear any data. + if (DEBUG) { + Slog.d(TAG, "Reading " + mTag + " " + mElapsedTimeNs + " " + mWallClockTimeNs); + } + // Set up worksource if present. + int numWorkChains = in.readInt(); + if (numWorkChains > 0) { + mWorkSource = new WorkSource(); + for (int i = 0; i < numWorkChains; i++) { + android.os.WorkSource.WorkChain workChain = mWorkSource.createWorkChain(); + int workChainSize = in.readInt(); + for (int j = 0; j < workChainSize; j++) { + int uid = in.readInt(); + String tag = in.readString(); + workChain.addNode(uid, tag); + } + } + } + + // Do the rest of the types. + int numTypes = in.readInt(); + if (DEBUG) { + Slog.d(TAG, "Reading " + numTypes + " elements"); + } + for (int i = 0; i < numTypes; i++) { + int type = in.readInt(); + mTypes.add(type); + switch (type) { + case EVENT_TYPE_INT: + mValues.add(in.readInt()); + break; + case EVENT_TYPE_LONG: + mValues.add(in.readLong()); + break; + case EVENT_TYPE_FLOAT: + mValues.add(in.readFloat()); + break; + case EVENT_TYPE_DOUBLE: + mValues.add(in.readDouble()); + break; + case EVENT_TYPE_STRING: + mValues.add(in.readString()); + break; + case EVENT_TYPE_STORAGE: + mValues.add(in.createByteArray()); + break; + default: + break; + } + } + } + + /** * Boilerplate for Parcel. */ public int describeContents() { diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 41d3cbb88f5c..18e1f5902a31 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"; /** @@ -122,6 +123,21 @@ public final class DeviceConfig { } /** + * Namespace for all runtime related features. + * + * @hide + */ + @SystemApi + public interface Runtime { + String NAMESPACE = "runtime"; + + /** + * Whether or not we use the precompiled layout. + */ + String USE_PRECOMPILED_LAYOUT = "view.precompiled_layout_enabled"; + } + + /** * Namespace for all runtime native related features. * * @hide @@ -308,6 +324,25 @@ public final class DeviceConfig { String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled"; } + /** + * Namespace for system scheduler related features. These features will be applied + * immediately upon change. + * + * @hide + */ + @SystemApi + public interface Scheduler { + String NAMESPACE = "scheduler"; + + /** + * Flag for enabling fast metrics collection in system scheduler. + * A flag value of '' or '0' means the fast metrics collection is not + * enabled. Otherwise fast metrics collection is enabled and flag value + * is the order id. + */ + String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection"; + } + private static final Object sLock = new Object(); @GuardedBy("sLock") private static Map<OnPropertyChangedListener, Pair<String, Executor>> sListeners = @@ -399,6 +434,7 @@ public final class DeviceConfig { * @see #removeOnPropertyChangedListener(OnPropertyChangedListener) */ @SystemApi + @TestApi @RequiresPermission(READ_DEVICE_CONFIG) public static void addOnPropertyChangedListener( @NonNull String namespace, @@ -432,6 +468,7 @@ public final class DeviceConfig { * @see #addOnPropertyChangedListener(String, Executor, OnPropertyChangedListener) */ @SystemApi + @TestApi public static void removeOnPropertyChangedListener( OnPropertyChangedListener onPropertyChangedListener) { synchronized (sLock) { @@ -528,6 +565,7 @@ public final class DeviceConfig { * @hide */ @SystemApi + @TestApi public interface OnPropertyChangedListener { /** * Called when a property has changed. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index de84e713a6f7..22329baa5109 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 @@ -13354,6 +13343,14 @@ public final class Settings { public static final String ISOLATED_STORAGE_REMOTE = "isolated_storage_remote"; /** + * Indicates whether aware is available in the current location. + * @hide + */ + public static final String AWARE_ALLOWED = "aware_allowed"; + + private static final Validator AWARE_ALLOWED_VALIDATOR = BOOLEAN_VALIDATOR; + + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. * @@ -13399,6 +13396,7 @@ public final class Settings { SOFT_AP_TIMEOUT_ENABLED, ZEN_DURATION, CHARGING_VIBRATION_ENABLED, + AWARE_ALLOWED, }; /** @@ -13459,6 +13457,7 @@ public final class Settings { VALIDATORS.put(WIFI_PNO_RECENCY_SORTING_ENABLED, WIFI_PNO_RECENCY_SORTING_ENABLED_VALIDATOR); VALIDATORS.put(WIFI_LINK_PROBING_ENABLED, WIFI_LINK_PROBING_ENABLED_VALIDATOR); + VALIDATORS.put(AWARE_ALLOWED, AWARE_ALLOWED_VALIDATOR); } /** diff --git a/core/java/android/service/textclassifier/TEST_MAPPING b/core/java/android/service/textclassifier/TEST_MAPPING new file mode 100644 index 000000000000..ccf26315852d --- /dev/null +++ b/core/java/android/service/textclassifier/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "imports": [ + { + "path": "frameworks/base/core/java/android/view/textclassifier" + } + ] +} diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index e3a6bd7a6949..49bae280321e 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -32,6 +32,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerGlobal; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.Process; @@ -495,7 +496,7 @@ public final class Display { * @return True if the display is still valid. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public boolean getDisplayInfo(DisplayInfo outDisplayInfo) { synchronized (this) { updateDisplayInfoLocked(); diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index ff4ee9ce7ded..ad8fee978c9a 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -158,8 +158,9 @@ public final class DisplayInfo implements Parcelable { * * @hide */ + // Remark on @UnsupportedAppUsage: Display.getCutout should be used instead @Nullable - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public DisplayCutout displayCutout; /** diff --git a/core/java/android/view/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..b28ac4714e90 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -33,6 +33,8 @@ import android.os.Handler; import android.os.Message; import android.os.SystemProperties; import android.os.Trace; +import android.provider.DeviceConfig; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; @@ -80,8 +82,6 @@ public abstract class LayoutInflater { private static final String TAG = LayoutInflater.class.getSimpleName(); private static final boolean DEBUG = false; - private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY - = "view.precompiled_layout_enabled"; private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex"; /** Empty stack trace used to avoid log spam in re-throw exceptions. */ @@ -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; @@ -407,8 +412,24 @@ public abstract class LayoutInflater { } private void initPrecompiledViews() { - initPrecompiledViews( - SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false)); + // Use the device config if enabled, otherwise default to the system property. + String usePrecompiledLayout = null; + try { + usePrecompiledLayout = DeviceConfig.getProperty( + DeviceConfig.Runtime.NAMESPACE, + DeviceConfig.Runtime.USE_PRECOMPILED_LAYOUT); + } catch (Exception e) { + // May be caused by permission errors reading the property (i.e. instant apps). + } + boolean enabled = false; + if (TextUtils.isEmpty(usePrecompiledLayout)) { + enabled = SystemProperties.getBoolean( + DeviceConfig.Runtime.USE_PRECOMPILED_LAYOUT, + false); + } else { + enabled = Boolean.parseBoolean(usePrecompiledLayout); + } + initPrecompiledViews(enabled); } private void initPrecompiledViews(boolean enablePrecompiledViews) { 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/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 46aea80efe7a..e3833c01eeaf 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -520,7 +520,7 @@ public final class WindowManagerGlobal { return false; } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public void trimMemory(int level) { if (ThreadedRenderer.isAvailable()) { if (shouldDestroyEglContext(level)) { diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS new file mode 100644 index 000000000000..265674a74b7e --- /dev/null +++ b/core/java/android/view/accessibility/OWNERS @@ -0,0 +1,3 @@ +svetoslavganov@google.com +pweaver@google.com +rhedjao@google.com diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java index dfd9a2e95cb7..e0950948afb8 100644 --- a/core/java/android/view/animation/Animation.java +++ b/core/java/android/view/animation/Animation.java @@ -23,6 +23,7 @@ import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.RectF; +import android.os.Build; import android.os.Handler; import android.os.SystemProperties; import android.util.AttributeSet; @@ -30,9 +31,6 @@ import android.util.TypedValue; import dalvik.system.CloseGuard; -import java.util.ArrayList; -import java.util.List; - /** * Abstraction for an Animation that can be applied to Views, Surfaces, or * other objects. See the {@link android.view.animation animation package @@ -187,15 +185,12 @@ public abstract class Animation implements Cloneable { /** * An animation listener to be notified when the animation starts, ends or repeats. */ - @UnsupportedAppUsage + // If you need to chain the AnimationListener, wrap the existing Animation into an AnimationSet + // and add your new listener to that set + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 117519981) private AnimationListener mListener; /** - * A list of animation listeners to be notified when the animation starts, ends or repeats. - */ - private List<AnimationListener> mListeners; - - /** * Desired Z order mode during animation. */ private int mZAdjustment; @@ -833,7 +828,7 @@ public abstract class Animation implements Cloneable { } private boolean hasAnimationListener() { - return mListener != null || (mListeners != null && !mListeners.isEmpty()); + return mListener != null; } /** @@ -848,32 +843,6 @@ public abstract class Animation implements Cloneable { } /** - * <p>Adds an animation listener to this animation. The animation listener - * is notified of animation events such as the end of the animation or the - * repetition of the animation.</p> - * - * @param listener the animation listener to be notified - */ - public void addAnimationListener(AnimationListener listener) { - if (mListeners == null) { - mListeners = new ArrayList<>(1); - } - mListeners.add(listener); - } - - /** - * <p>Removes an animation listener that has been added with - * {@link #addAnimationListener(AnimationListener)}.</p> - * - * @param listener the animation listener to be removed - */ - public void removeAnimationListener(AnimationListener listener) { - if (mListeners != null) { - mListeners.remove(listener); - } - } - - /** * Gurantees that this animation has an interpolator. Will use * a AccelerateDecelerateInterpolator is nothing else was specified. */ @@ -1003,33 +972,18 @@ public abstract class Animation implements Cloneable { if (mListener != null) { mListener.onAnimationStart(this); } - if (mListeners != null && !mListeners.isEmpty()) { - for (AnimationListener listener : mListeners) { - listener.onAnimationStart(this); - } - } } void dispatchAnimationRepeat() { if (mListener != null) { mListener.onAnimationRepeat(this); } - if (mListeners != null && !mListeners.isEmpty()) { - for (AnimationListener listener : mListeners) { - listener.onAnimationRepeat(this); - } - } } void dispatchAnimationEnd() { if (mListener != null) { mListener.onAnimationEnd(this); } - if (mListeners != null && !mListeners.isEmpty()) { - for (AnimationListener listener : mListeners) { - listener.onAnimationEnd(this); - } - } } /** diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 83fc017373a6..5e5c8265f782 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -17,7 +17,6 @@ package android.view.autofill; import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST; -import static android.util.DebugUtils.flagsToString; import static android.view.autofill.Helper.sDebug; import static android.view.autofill.Helper.sVerbose; @@ -338,6 +337,14 @@ public final class AutofillManager { public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes /** + * Disables Augmented Autofill. + * + * @hide + */ + @TestApi + public static final int FLAG_SMART_SUGGESTION_OFF = 0x0; + + /** * Displays the Augment Autofill window using the same mechanism (such as a popup-window * attached to the focused view) as the standard autofill. * @@ -347,13 +354,21 @@ public final class AutofillManager { public static final int FLAG_SMART_SUGGESTION_SYSTEM = 0x1; /** @hide */ - @IntDef(flag = true, prefix = { "FLAG_SMART_SUGGESTION_" }, value = { - FLAG_SMART_SUGGESTION_SYSTEM - }) + @IntDef(flag = false, value = { FLAG_SMART_SUGGESTION_OFF, FLAG_SMART_SUGGESTION_SYSTEM }) @Retention(RetentionPolicy.SOURCE) public @interface SmartSuggestionMode {} /** + * {@code DeviceConfig} property used to set which Smart Suggestion modes for Augmented Autofill + * are available. + * + * @hide + */ + @TestApi + public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = + "smart_suggestion_supported_modes"; + + /** * Makes an authentication id from a request id and a dataset id. * * @param requestId The request id. @@ -2347,7 +2362,14 @@ public final class AutofillManager { /** @hide */ public static String getSmartSuggestionModeToString(@SmartSuggestionMode int flags) { - return flagsToString(AutofillManager.class, "FLAG_SMART_SUGGESTION_", flags); + switch (flags) { + case FLAG_SMART_SUGGESTION_OFF: + return "OFF"; + case FLAG_SMART_SUGGESTION_SYSTEM: + return "SYSTEM"; + default: + return "INVALID:" + flags; + } } @GuardedBy("mLock") diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 8a097883dd5c..e63a406411d8 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1373,7 +1373,7 @@ public final class InputMethodManager { * @hide */ @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499) public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) { try { Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be removed " diff --git a/core/java/android/view/textclassifier/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/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index f9564b44e825..25e5dd32c6b2 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -471,11 +471,24 @@ public class ListPopupWindow implements ShowableListMenu { * Specifies the anchor-relative bounds of the popup's transition * epicenter. * - * @param bounds anchor-relative bounds - * @hide + * @param bounds anchor-relative bounds, or {@code null} to use default epicenter + * + * @see #getEpicenterBounds() + */ + public void setEpicenterBounds(@Nullable Rect bounds) { + mEpicenterBounds = bounds != null ? new Rect(bounds) : null; + } + + /** + * Returns bounds which are used as a popup's epicenter + * of the enter and exit transitions. + * + * @return bounds relative to anchor view, or {@code null} if not set + * @see #setEpicenterBounds(Rect) */ - public void setEpicenterBounds(Rect bounds) { - mEpicenterBounds = bounds; + @Nullable + public Rect getEpicenterBounds() { + return mEpicenterBounds != null ? new Rect(mEpicenterBounds) : null; } /** diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 311f8968150c..2aa019b5d0f4 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -236,6 +236,8 @@ public class ListView extends AbsListView { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.ListView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.ListView, + attrs, a, defStyleAttr, defStyleRes); final CharSequence[] entries = a.getTextArray(R.styleable.ListView_entries); if (entries != null) { diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index 157992a98a4a..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/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 88d938082b05..279829672c57 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -490,7 +490,7 @@ public class PopupWindow { */ @Nullable public Rect getEpicenterBounds() { - return mEpicenterBounds; + return mEpicenterBounds != null ? new Rect(mEpicenterBounds) : null; } /** @@ -509,7 +509,7 @@ public class PopupWindow { * @see #getEpicenterBounds() */ public void setEpicenterBounds(@Nullable Rect bounds) { - mEpicenterBounds = bounds; + mEpicenterBounds = bounds != null ? new Rect(bounds) : null; } private Transition getTransition(int resId) { 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/colorextraction/ColorExtractor.java b/core/java/com/android/internal/colorextraction/ColorExtractor.java index c171fa6b25fd..258d081c6ad8 100644 --- a/core/java/com/android/internal/colorextraction/ColorExtractor.java +++ b/core/java/com/android/internal/colorextraction/ColorExtractor.java @@ -22,7 +22,6 @@ import android.app.WallpaperColors; import android.app.WallpaperManager; import android.content.Context; import android.os.Trace; -import android.os.UserHandle; import android.util.Log; import android.util.SparseArray; @@ -32,7 +31,6 @@ import com.android.internal.colorextraction.types.Tonal; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Iterator; /** * Class to process wallpaper colors and generate a tonal palette based on them. @@ -222,6 +220,7 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener public static class GradientColors { private int mMainColor; private int mSecondaryColor; + private int[] mColorPalette; private boolean mSupportsDarkText; public void setMainColor(int mainColor) { @@ -232,6 +231,10 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener mSecondaryColor = secondaryColor; } + public void setColorPalette(int[] colorPalette) { + mColorPalette = colorPalette; + } + public void setSupportsDarkText(boolean supportsDarkText) { mSupportsDarkText = supportsDarkText; } @@ -239,6 +242,7 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener public void set(GradientColors other) { mMainColor = other.mMainColor; mSecondaryColor = other.mSecondaryColor; + mColorPalette = other.mColorPalette; mSupportsDarkText = other.mSupportsDarkText; } @@ -250,6 +254,10 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener return mSecondaryColor; } + public int[] getColorPalette() { + return mColorPalette; + } + public boolean supportsDarkText() { return mSupportsDarkText; } @@ -283,4 +291,4 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener public interface OnColorsChangedListener { void onColorsChanged(ColorExtractor colorExtractor, int which); } -}
\ No newline at end of file +} diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java index 3fd88dbb8704..d6a8934566b2 100644 --- a/core/java/com/android/internal/colorextraction/types/Tonal.java +++ b/core/java/com/android/internal/colorextraction/types/Tonal.java @@ -173,6 +173,7 @@ public class Tonal implements ExtractionType { Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY); float[] s = fit(palette.s, hsl[1], fitIndex, 0.0f, 1.0f); float[] l = fit(palette.l, hsl[2], fitIndex, 0.0f, 1.0f); + int[] colorPalette = getColorPalette(h, s, l); if (DEBUG) { StringBuilder builder = new StringBuilder("Tonal Palette - index: " + fitIndex + @@ -209,6 +210,7 @@ public class Tonal implements ExtractionType { // Normal colors: outColorsNormal.setMainColor(mainColor); outColorsNormal.setSecondaryColor(mainColor); + outColorsNormal.setColorPalette(colorPalette); // Dark colors: // Stops at 4th color, only lighter if dark text is supported @@ -222,6 +224,7 @@ public class Tonal implements ExtractionType { mainColor = getColorInt(primaryIndex, h, s, l); outColorsDark.setMainColor(mainColor); outColorsDark.setSecondaryColor(mainColor); + outColorsDark.setColorPalette(colorPalette); // Extra Dark: // Stay close to dark colors until dark text is supported @@ -235,6 +238,7 @@ public class Tonal implements ExtractionType { mainColor = getColorInt(primaryIndex, h, s, l); outColorsExtraDark.setMainColor(mainColor); outColorsExtraDark.setSecondaryColor(mainColor); + outColorsExtraDark.setColorPalette(colorPalette); outColorsNormal.setSupportsDarkText(supportsDarkText); outColorsDark.setSupportsDarkText(supportsDarkText); @@ -262,16 +266,19 @@ public class Tonal implements ExtractionType { * @param inWallpaperColors Colors to read. * @param outGradientColors Destination. */ - public static void applyFallback(@Nullable WallpaperColors inWallpaperColors, + public void applyFallback(@Nullable WallpaperColors inWallpaperColors, @NonNull GradientColors outGradientColors) { boolean light = inWallpaperColors != null && (inWallpaperColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0; final int color = light ? MAIN_COLOR_LIGHT : MAIN_COLOR_DARK; + final float[] hsl = new float[3]; + ColorUtils.colorToHSL(color, hsl); outGradientColors.setMainColor(color); outGradientColors.setSecondaryColor(color); outGradientColors.setSupportsDarkText(light); + outGradientColors.setColorPalette(getColorPalette(findTonalPalette(hsl[0], hsl[1]))); } private int getColorInt(int fitIndex, float[] h, float[] s, float[] l) { @@ -281,6 +288,19 @@ public class Tonal implements ExtractionType { return ColorUtils.HSLToColor(mTmpHSL); } + private int[] getColorPalette(float[] h, float[] s, float[] l) { + int[] colorPalette = new int[h.length]; + for (int i = 0; i < colorPalette.length; i++) { + colorPalette[i] = getColorInt(i, h, s, l); + } + return colorPalette; + } + + private int[] getColorPalette(TonalPalette palette) { + return getColorPalette(palette.h, palette.s, palette.l); + } + + /** * Checks if a given color exists in the blacklist * @param hsl float array with 3 components (H 0..360, S 0..1 and L 0..1) @@ -598,4 +618,4 @@ public class Tonal implements ExtractionType { return numbers; } } -}
\ No newline at end of file +} diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java index 2c272dea073b..7f4d8a2d0587 100644 --- a/core/java/com/android/internal/os/BinderCallsStats.java +++ b/core/java/com/android/internal/os/BinderCallsStats.java @@ -52,6 +52,8 @@ public class BinderCallsStats implements BinderInternal.Observer { public static final boolean ENABLED_DEFAULT = true; public static final boolean DETAILED_TRACKING_DEFAULT = true; public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 100; + public static final boolean DEFAULT_TRACK_SCREEN_INTERACTIVE = false; + public static final boolean DEFAULT_TRACK_DIRECT_CALLING_UID = true; public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 5000; private static final String DEBUG_ENTRY_PREFIX = "__DEBUG_"; @@ -85,6 +87,8 @@ public class BinderCallsStats implements BinderInternal.Observer { private long mStartElapsedTime = SystemClock.elapsedRealtime(); private long mCallStatsCount = 0; private boolean mAddDebugEntries = false; + private boolean mTrackDirectCallingUid = DEFAULT_TRACK_DIRECT_CALLING_UID; + private boolean mTrackScreenInteractive = DEFAULT_TRACK_SCREEN_INTERACTIVE; private CachedDeviceState.Readonly mDeviceState; private CachedDeviceState.TimeInStateStopwatch mBatteryStopwatch; @@ -160,7 +164,12 @@ public class BinderCallsStats implements BinderInternal.Observer { duration = 0; latencyDuration = 0; } - final int callingUid = getCallingUid(); + final boolean screenInteractive = mTrackScreenInteractive + ? mDeviceState.isScreenInteractive() + : OVERFLOW_SCREEN_INTERACTIVE; + final int callingUid = mTrackDirectCallingUid + ? getCallingUid() + : OVERFLOW_DIRECT_CALLING_UID; synchronized (mLock) { // This was already checked in #callStart but check again while synchronized. @@ -177,7 +186,7 @@ public class BinderCallsStats implements BinderInternal.Observer { final CallStat callStat = uidEntry.getOrCreate( callingUid, s.binderClass, s.transactionCode, - mDeviceState.isScreenInteractive(), + screenInteractive, mCallStatsCount >= mMaxBinderCallStatsCount); final boolean isNewCallStat = callStat.callCount == 0; if (isNewCallStat) { @@ -484,6 +493,30 @@ public class BinderCallsStats implements BinderInternal.Observer { } } + /** + * Whether to track the screen state. + */ + public void setTrackScreenInteractive(boolean enabled) { + synchronized (mLock) { + if (enabled != mTrackScreenInteractive) { + mTrackScreenInteractive = enabled; + reset(); + } + } + } + + /** + * Whether to track direct caller uid. + */ + public void setTrackDirectCallerUid(boolean enabled) { + synchronized (mLock) { + if (enabled != mTrackDirectCallingUid) { + mTrackDirectCallingUid = enabled; + reset(); + } + } + } + public void setAddDebugEntries(boolean addDebugEntries) { mAddDebugEntries = addDebugEntries; } diff --git a/core/java/com/android/internal/os/ChildZygoteInit.java b/core/java/com/android/internal/os/ChildZygoteInit.java index cc74863632dd..1f816c18f886 100644 --- a/core/java/com/android/internal/os/ChildZygoteInit.java +++ b/core/java/com/android/internal/os/ChildZygoteInit.java @@ -102,7 +102,7 @@ public class ChildZygoteInit { // are just isolated UIDs in the range, because for the webview zygote, there is no // single range that captures all possible isolated UIDs. // TODO(b/123615476) narrow this down - if (uidGidMin < Process.FIRST_ISOLATED_UID) { + if (uidGidMin < Process.FIRST_APP_ZYGOTE_ISOLATED_UID) { throw new RuntimeException("Passed in UID range does not map to isolated processes."); } diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java index b3d9ca7670b5..c059721eb2d3 100644 --- a/core/java/com/android/internal/os/LooperStats.java +++ b/core/java/com/android/internal/os/LooperStats.java @@ -39,6 +39,7 @@ import java.util.concurrent.ThreadLocalRandom; public class LooperStats implements Looper.Observer { public static final String DEBUG_ENTRY_PREFIX = "__DEBUG_"; private static final int SESSION_POOL_SIZE = 50; + private static final boolean DISABLED_SCREEN_STATE_TRACKING_VALUE = false; @GuardedBy("mLock") private final SparseArray<Entry> mEntries = new SparseArray<>(512); @@ -54,6 +55,7 @@ public class LooperStats implements Looper.Observer { private long mStartCurrentTime = System.currentTimeMillis(); private long mStartElapsedTime = SystemClock.elapsedRealtime(); private boolean mAddDebugEntries = false; + private boolean mTrackScreenInteractive = false; public LooperStats(int samplingInterval, int entriesSizeCap) { this.mSamplingInterval = samplingInterval; @@ -218,9 +220,15 @@ public class LooperStats implements Looper.Observer { mSamplingInterval = samplingInterval; } + public void setTrackScreenInteractive(boolean enabled) { + mTrackScreenInteractive = enabled; + } + @Nullable private Entry findEntry(Message msg, boolean allowCreateNew) { - final boolean isInteractive = mDeviceState.isScreenInteractive(); + final boolean isInteractive = mTrackScreenInteractive + ? mDeviceState.isScreenInteractive() + : DISABLED_SCREEN_STATE_TRACKING_VALUE; final int id = Entry.idFor(msg, isInteractive); Entry entry; synchronized (mLock) { diff --git a/core/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/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 6770ae19ce3d..738221340aba 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -209,21 +209,14 @@ applications that come with the platform <privapp-permissions package="com.android.mainline.networkstack"> <permission name="android.permission.ACCESS_NETWORK_CONDITIONS"/> - <permission name="android.permission.CHANGE_BACKGROUND_DATA_SETTING"/> <permission name="android.permission.CONNECTIVITY_INTERNAL"/> <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/> <permission name="android.permission.CONTROL_VPN"/> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.LOCAL_MAC_ADDRESS"/> - <permission name="android.permission.MANAGE_IPSEC_TUNNELS"/> - <permission name="android.permission.MANAGE_NETWORK_POLICY"/> <permission name="android.permission.MANAGE_SUBSCRIPTION_PLANS"/> <permission name="android.permission.MANAGE_USB"/> - <permission name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"/> - <permission name="android.permission.NETWORK_SETTINGS"/> - <permission name="android.permission.NETWORK_STACK" /> - <permission name="android.permission.NET_TUNNELING"/> <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD"/> - <permission name="android.permission.PEERS_MAC_ADDRESS"/> <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/> <permission name="android.permission.READ_PRECISE_PHONE_STATE"/> <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> @@ -261,6 +254,7 @@ applications that come with the platform <permission name="android.permission.CHANGE_LOWPAN_STATE"/> <permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/> <permission name="android.permission.CLEAR_APP_CACHE"/> + <permission name="android.permission.ACCESS_INSTANT_APPS" /> <permission name="android.permission.CONNECTIVITY_INTERNAL"/> <permission name="android.permission.DELETE_CACHE_FILES"/> <permission name="android.permission.DELETE_PACKAGES"/> diff --git a/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/media/packages/MediaCore/Android.bp.bak b/media/packages/MediaCore/Android.bp.bak deleted file mode 100644 index c7fd58bf933a..000000000000 --- a/media/packages/MediaCore/Android.bp.bak +++ /dev/null @@ -1,21 +0,0 @@ -android_app { - name: "MediaCore", - - srcs: [ - "src/**/*.java", - ], - - static_libs: [ - // TODO: Temporarily statically linked. Should go into "libs" - "media1", - ], - - // System app - platform_apis: true, - - // Privileged app - privileged: true, - - // Make sure that the implementation only relies on SDK or system APIs. - sdk_version: "system_current", -} diff --git a/media/packages/MediaCore/AndroidManifest.xml b/media/packages/MediaCore/AndroidManifest.xml deleted file mode 100644 index 4e2b274511e8..000000000000 --- a/media/packages/MediaCore/AndroidManifest.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* //device/apps/common/AndroidManifest.xml -** -** Copyright 2019, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.media" coreApp="true" android:sharedUserId="android.uid.system" - android:sharedUserLabel="@string/android_system_label"> - <application android:process="system" - android:persistent="true" - android:directBootAware="true"> - <service android:name="AmlMediaSessionProviderService" android:singleUser="true"> - <intent-filter> - <action android:name="android.media.session.MediaSessionProviderService"/> - </intent-filter> - </service> - </application> -</manifest> diff --git a/media/packages/MediaCore/res/values/strings.xml b/media/packages/MediaCore/res/values/strings.xml deleted file mode 100644 index 59fd635b905f..000000000000 --- a/media/packages/MediaCore/res/values/strings.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2019 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<resources> - <!-- Label for the Android system components when they are shown to the user. --> - <string name="android_system_label" translatable="false">Android System</string> -</resources> - diff --git a/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java b/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java deleted file mode 100644 index 43b95ab7ebdb..000000000000 --- a/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.media; - -import android.content.Context; -import android.media.session.MediaSessionProviderService; -import android.os.PowerManager; -import android.util.Log; - -/** - * System implementation of MediaSessionProviderService - */ -public class AmlMediaSessionProviderService extends MediaSessionProviderService { - private static final String TAG = "AmlMediaSessionProviderS"; - static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private Context mContext; - - public AmlMediaSessionProviderService(Context context) { - mContext = context; - PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - } -} diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index 51afbc7d91b0..730c409a91fb 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -230,6 +230,7 @@ LIBANDROID { ASurfaceTransaction_reparent; # introduced=29 ASurfaceTransaction_setBuffer; # introduced=29 ASurfaceTransaction_setBufferAlpha; # introduced=29 + ASurfaceTransaction_setBufferDataSpace; # introduced=29 ASurfaceTransaction_setBufferTransparency; # introduced=29 ASurfaceTransaction_setColor; # introduced=29 ASurfaceTransaction_setDamageRegion; # introduced=29 diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index 7d2934b8554e..d07052bb3b3f 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -440,6 +440,20 @@ void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* aSurfaceTransaction transaction->setAlpha(surfaceControl, alpha); } +void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* aSurfaceTransaction, + ASurfaceControl* aSurfaceControl, + ADataSpace aDataSpace) { + CHECK_NOT_NULL(aSurfaceTransaction); + CHECK_NOT_NULL(aSurfaceControl); + + sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); + LOG_ALWAYS_FATAL_IF(!isDataSpaceValid(surfaceControl, aDataSpace), "invalid dataspace"); + + Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); + + transaction->setDataspace(surfaceControl, static_cast<ui::Dataspace>(aDataSpace)); +} + void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl, struct AHdrMetadata_smpte2086* metadata) { diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java index b6b229c770b2..c5e598d8ce46 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java @@ -230,6 +230,10 @@ public class Assistant extends NotificationAssistantService { NotificationEntry entry = new NotificationEntry(mPackageManager, sbn, channel, mSmsHelper); SmartActionsHelper.SmartSuggestions suggestions = mSmartActionsHelper.suggest(entry); + if (DEBUG) { + Log.d(TAG, String.format("Creating Adjustment for %s, with %d actions, and %d replies.", + sbn.getKey(), suggestions.actions.size(), suggestions.replies.size())); + } return createEnqueuedNotificationAdjustment( entry, suggestions.actions, suggestions.replies); } diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java index 08cc39fc4935..f372fe55dfb0 100644 --- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java +++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java @@ -21,6 +21,7 @@ import android.app.Notification; import android.app.Person; import android.app.RemoteAction; import android.content.Context; +import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.Parcelable; import android.os.Process; @@ -42,6 +43,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Deque; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; public class SmartActionsHelper { @@ -120,6 +122,12 @@ public class SmartActionsHelper { if (messages.isEmpty()) { return Collections.emptyList(); } + // Do not generate smart actions if the last message is from the local user. + ConversationActions.Message lastMessage = messages.get(messages.size() - 1); + if (arePersonsEqual( + ConversationActions.Message.PERSON_USER_SELF, lastMessage.getAuthor())) { + return Collections.emptyList(); + } TextClassifier.EntityConfig.Builder typeConfigBuilder = new TextClassifier.EntityConfig.Builder(); @@ -230,8 +238,11 @@ public class SmartActionsHelper { private Notification.Action createNotificationAction( RemoteAction remoteAction, String actionType) { + Icon icon = remoteAction.shouldShowIcon() + ? remoteAction.getIcon() + : Icon.createWithResource(mContext, com.android.internal.R.drawable.ic_action_open); return new Notification.Action.Builder( - remoteAction.getIcon(), + icon, remoteAction.getTitle(), remoteAction.getActionIntent()) .setContextual(true) @@ -312,13 +323,12 @@ public class SmartActionsHelper { if (message == null) { continue; } + // As per the javadoc of Notification.addMessage, null means local user. Person senderPerson = message.getSenderPerson(); - // Skip encoding once the sender is missing as it is important to distinguish - // local user and remote user when generating replies. if (senderPerson == null) { - break; + senderPerson = localUser; } - Person author = localUser != null && localUser.equals(senderPerson) + Person author = localUser != null && arePersonsEqual(localUser, senderPerson) ? ConversationActions.Message.PERSON_USER_SELF : senderPerson; extractMessages.push(new ConversationActions.Message.Builder(author) .setText(message.getText()) @@ -333,6 +343,12 @@ public class SmartActionsHelper { return new ArrayList<>(extractMessages); } + private static boolean arePersonsEqual(@NonNull Person left, @NonNull Person right) { + return Objects.equals(left.getKey(), right.getKey()) + && Objects.equals(left.getName(), right.getName()) + && Objects.equals(left.getUri(), right.getUri()); + } + static class SmartSuggestions { public final ArrayList<CharSequence> replies; public final ArrayList<Notification.Action> actions; diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java index ebbd961b6f23..74c20fc09df2 100644 --- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java +++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java @@ -222,22 +222,29 @@ public class SmartActionsHelperTest { List<ConversationActions.Message> messages = runSuggestAndCaptureRequest().getConversation(); - assertThat(messages).hasSize(3); + assertThat(messages).hasSize(4); - ConversationActions.Message secondMessage = messages.get(0); + ConversationActions.Message firstMessage = messages.get(0); + MessageSubject.assertThat(firstMessage).hasText("firstMessage"); + MessageSubject.assertThat(firstMessage) + .hasPerson(ConversationActions.Message.PERSON_USER_SELF); + MessageSubject.assertThat(firstMessage) + .hasReferenceTime(createZonedDateTimeFromMsUtc(1000)); + + ConversationActions.Message secondMessage = messages.get(1); MessageSubject.assertThat(secondMessage).hasText("secondMessage"); MessageSubject.assertThat(secondMessage) .hasPerson(ConversationActions.Message.PERSON_USER_SELF); MessageSubject.assertThat(secondMessage) .hasReferenceTime(createZonedDateTimeFromMsUtc(2000)); - ConversationActions.Message thirdMessage = messages.get(1); + ConversationActions.Message thirdMessage = messages.get(2); MessageSubject.assertThat(thirdMessage).hasText("thirdMessage"); MessageSubject.assertThat(thirdMessage).hasPerson(userA); MessageSubject.assertThat(thirdMessage) .hasReferenceTime(createZonedDateTimeFromMsUtc(3000)); - ConversationActions.Message fourthMessage = messages.get(2); + ConversationActions.Message fourthMessage = messages.get(3); MessageSubject.assertThat(fourthMessage).hasText("fourthMessage"); MessageSubject.assertThat(fourthMessage).hasPerson(userB); MessageSubject.assertThat(fourthMessage) @@ -245,6 +252,28 @@ public class SmartActionsHelperTest { } @Test + public void testSuggest_lastMessageLocalUser() { + Person me = new Person.Builder().setName("Me").build(); + Person userA = new Person.Builder().setName("A").build(); + Notification.MessagingStyle style = + new Notification.MessagingStyle(me) + .addMessage("firstMessage", 1000, userA) + .addMessage("secondMessage", 2000, me); + Notification notification = + mNotificationBuilder + .setContentText("You have two new messages") + .setStyle(style) + .setActions(createReplyAction()) + .build(); + when(mStatusBarNotification.getNotification()).thenReturn(notification); + + mSmartActionsHelper.suggest(createNotificationEntry()); + + verify(mTextClassifier, never()) + .suggestConversationActions(any(ConversationActions.Request.class)); + } + + @Test public void testSuggest_messageStyle_noPerson() { Person me = new Person.Builder().setName("Me").build(); Notification.MessagingStyle style = diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml index ac55bfa1aed7..e4d35915c77c 100644 --- a/packages/NetworkStack/AndroidManifest.xml +++ b/packages/NetworkStack/AndroidManifest.xml @@ -27,8 +27,8 @@ <uses-permission android:name="android.permission.NETWORK_SETTINGS" /> <!-- Signature permission defined in NetworkStackStub --> <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" /> - <!-- Launch captive portal app as specific user --> - <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> + <!-- Send latency broadcast as current user --> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <uses-permission android:name="android.permission.NETWORK_STACK" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <application diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java index 0d6d080b6dc2..2e72d8296a37 100644 --- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java @@ -500,7 +500,7 @@ public class NetworkMonitor extends StateMachine { private void showProvisioningNotification(String action) { try { - mCallback.showProvisioningNotification(action); + mCallback.showProvisioningNotification(action, mContext.getPackageName()); } catch (RemoteException e) { Log.e(TAG, "Error showing provisioning notification", e); } diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java index d11bb64213c3..b98b0f798fe3 100644 --- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java +++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java @@ -482,7 +482,7 @@ public class NetworkMonitorTest { nm.notifyNetworkConnected(); verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)) - .showProvisioningNotification(any()); + .showProvisioningNotification(any(), any()); // Check that startCaptivePortalApp sends the expected intent. nm.launchCaptivePortalApp(); diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index e28c894ff8f3..ab95910a77b5 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -167,7 +167,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> // This is to ensure all the profiles are disconnected as some CK/Hs do not // disconnect PBAP connection when HF connection is brought down PbapServerProfile PbapProfile = mProfileManager.getPbapProfile(); - if (PbapProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED) + if (PbapProfile != null && isConnectedProfile(PbapProfile)) { PbapProfile.disconnect(mDevice); } diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java index 88adcdb16edc..5c9a06f91e6a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java @@ -20,6 +20,7 @@ import android.os.Looper; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; public class ThreadUtils { @@ -59,12 +60,14 @@ public class ThreadUtils { /** * Posts runnable in background using shared background thread pool. + * + * @Return A future of the task that can be monitored for updates or cancelled. */ - public static void postOnBackgroundThread(Runnable runnable) { + public static Future postOnBackgroundThread(Runnable runnable) { if (sSingleThreadExecutor == null) { sSingleThreadExecutor = Executors.newSingleThreadExecutor(); } - sSingleThreadExecutor.execute(runnable); + return sSingleThreadExecutor.submit(runnable); } /** diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index e8c728d358ea..0da3b10778e9 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -82,6 +82,7 @@ <uses-permission android:name="android.permission.MOVE_PACKAGE" /> <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" /> <uses-permission android:name="android.permission.CLEAR_APP_CACHE" /> + <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS" /> <uses-permission android:name="android.permission.DELETE_CACHE_FILES" /> <uses-permission android:name="android.permission.DELETE_PACKAGES" /> <uses-permission android:name="android.permission.MANAGE_ROLLBACKS" /> diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java index ac6904300f71..38bf77d5eb0e 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java @@ -55,9 +55,16 @@ public interface ClockPlugin extends Plugin { void setTextColor(int color); /** + * Sets the color palette for the clock face. + * @param supportsDarkText Whether dark text can be displayed. + * @param colors Colors that should be used on the clock face, ordered from darker to lighter. + */ + default void setColorPalette(boolean supportsDarkText, int[] colors) {} + + /** * Notifies that time tick alarm from doze service fired. */ - default void dozeTimeTick() { } + default void dozeTimeTick() {} /** * Set the amount (ratio) that the device has transitioned to doze. diff --git a/packages/SystemUI/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 6c970c0cc814..822920e63460 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -1,5 +1,6 @@ package com.android.keyguard; +import android.app.WallpaperManager; import android.content.Context; import android.graphics.Paint; import android.graphics.Paint.Style; @@ -12,8 +13,10 @@ import android.widget.TextClock; import androidx.annotation.VisibleForTesting; +import com.android.internal.colorextraction.ColorExtractor; import com.android.keyguard.clock.ClockManager; import com.android.systemui.Dependency; +import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; @@ -50,6 +53,8 @@ public class KeyguardClockSwitch extends RelativeLayout { * Maintain state so that a newly connected plugin can be initialized. */ private float mDarkAmount; + private boolean mSupportsDarkText; + private int[] mColorPalette; private final StatusBarStateController.StateListener mStateListener = new StatusBarStateController.StateListener() { @@ -72,6 +77,21 @@ public class KeyguardClockSwitch extends RelativeLayout { private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin; + /** + * Listener for changes to the color palette. + * + * The color palette changes when the wallpaper is changed. + */ + private SysuiColorExtractor.OnColorsChangedListener mColorsListener = (extractor, which) -> { + if ((which & WallpaperManager.FLAG_LOCK) != 0) { + if (extractor instanceof SysuiColorExtractor) { + updateColors((SysuiColorExtractor) extractor); + } else { + updateColors(Dependency.get(SysuiColorExtractor.class)); + } + } + }; + public KeyguardClockSwitch(Context context) { this(context, null); } @@ -100,6 +120,9 @@ public class KeyguardClockSwitch extends RelativeLayout { super.onAttachedToWindow(); Dependency.get(ClockManager.class).addOnClockChangedListener(mClockChangedListener); Dependency.get(StatusBarStateController.class).addCallback(mStateListener); + SysuiColorExtractor colorExtractor = Dependency.get(SysuiColorExtractor.class); + colorExtractor.addOnColorsChangedListener(mColorsListener); + updateColors(colorExtractor); } @Override @@ -107,6 +130,8 @@ public class KeyguardClockSwitch extends RelativeLayout { super.onDetachedFromWindow(); Dependency.get(ClockManager.class).removeOnClockChangedListener(mClockChangedListener); Dependency.get(StatusBarStateController.class).removeCallback(mStateListener); + Dependency.get(SysuiColorExtractor.class) + .removeOnColorsChangedListener(mColorsListener); } private void setClockPlugin(ClockPlugin plugin) { @@ -149,6 +174,9 @@ public class KeyguardClockSwitch extends RelativeLayout { mClockPlugin.setStyle(getPaint().getStyle()); mClockPlugin.setTextColor(getCurrentTextColor()); mClockPlugin.setDarkAmount(mDarkAmount); + if (mColorPalette != null) { + mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette); + } } /** @@ -159,7 +187,9 @@ public class KeyguardClockSwitch extends RelativeLayout { View bigClockView = mClockPlugin.getBigClockView(); if (bigClockView != null) { container.addView(bigClockView); - container.setVisibility(View.VISIBLE); + if (container.getVisibility() == View.GONE) { + container.setVisibility(View.VISIBLE); + } } } mBigClockContainer = container; @@ -246,6 +276,16 @@ public class KeyguardClockSwitch extends RelativeLayout { } } + private void updateColors(SysuiColorExtractor colorExtractor) { + ColorExtractor.GradientColors colors = colorExtractor.getColors(WallpaperManager.FLAG_LOCK, + true); + mSupportsDarkText = colors.supportsDarkText(); + mColorPalette = colors.getColorPalette(); + if (mClockPlugin != null) { + mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette); + } + } + @VisibleForTesting (otherwise = VisibleForTesting.NONE) ClockManager.ClockChangedListener getClockChangedListener() { return mClockChangedListener; diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java index db6127f1d573..3114708de038 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java @@ -89,7 +89,17 @@ public class BubbleClockController implements ClockPlugin { @Override public void setTextColor(int color) { mLockClock.setTextColor(color); - mDigitalClock.setTextColor(color); + } + + @Override + public void setColorPalette(boolean supportsDarkText, int[] colorPalette) { + if (colorPalette == null || colorPalette.length == 0) { + return; + } + final int length = colorPalette.length; + mDigitalClock.setTextColor(colorPalette[Math.max(0, length - 6)]); + mAnalogClock.setClockColors(colorPalette[Math.max(0, length - 6)], + colorPalette[Math.max(0, length - 3)]); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java index 3591dc82c8ec..4d8cf963ff50 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java @@ -22,6 +22,7 @@ import android.content.res.Resources; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; +import android.widget.FrameLayout.LayoutParams; import com.android.keyguard.R; @@ -80,8 +81,9 @@ public class ClockLayout extends FrameLayout { // Put digital clock in two left corner of the screen. if (mDigitalClock != null) { - mDigitalClock.setX(0.1f * getWidth() + offsetX); - mDigitalClock.setY(0.1f * getHeight() + offsetY); + LayoutParams params = (LayoutParams) mDigitalClock.getLayoutParams(); + mDigitalClock.setX(offsetX + params.leftMargin); + mDigitalClock.setY(offsetY + params.topMargin); } // Put the analog clock in the middle of the screen. diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java index 2c709e0393bd..e35cf113c111 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java @@ -78,6 +78,16 @@ public class ImageClock extends FrameLayout { mTime.setTimeZone(timeZone); } + /** + * Sets the colors to use on the clock face. + * @param dark Darker color obtained from color palette. + * @param light Lighter color obtained from color palette. + */ + public void setClockColors(int dark, int light) { + mHourHand.setColorFilter(dark); + mMinuteHand.setColorFilter(light); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java index 8734754541a6..3c9a4f821c62 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java @@ -76,10 +76,12 @@ public class StretchAnalogClock extends View { } /** - * Set the color of the minute hand. + * Set the colors to use on the clock face. + * @param dark Darker color obtained from color palette. + * @param light Lighter color obtained from color palette. */ - public void setMinuteHandColor(int color) { - mMinutePaint.setColor(color); + public void setClockColor(int dark, int light) { + mHourPaint.setColor(dark); invalidate(); } diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java index 0a39158cd4be..c4651149521c 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java @@ -89,8 +89,17 @@ public class StretchAnalogClockController implements ClockPlugin { @Override public void setTextColor(int color) { mLockClock.setTextColor(color); - mDigitalClock.setTextColor(color); - mAnalogClock.setMinuteHandColor(color); + } + + @Override + public void setColorPalette(boolean supportsDarkText, int[] colorPalette) { + if (colorPalette == null || colorPalette.length == 0) { + return; + } + final int length = colorPalette.length; + mDigitalClock.setTextColor(colorPalette[Math.max(0, length - 5)]); + mAnalogClock.setClockColor(colorPalette[Math.max(0, length - 5)], + colorPalette[Math.max(0, length - 2)]); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java index 17d929dc8a3b..2ea39c40bee2 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java @@ -87,6 +87,15 @@ public class TypeClockController implements ClockPlugin { } @Override + public void setColorPalette(boolean supportsDarkText, int[] colorPalette) { + if (colorPalette == null || colorPalette.length == 0) { + return; + } + final int length = colorPalette.length; + mTypeClock.setClockColor(colorPalette[Math.max(0, length - 5)]); + } + + @Override public void dozeTimeTick() { mTypeClock.onTimeChanged(); } diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java index 8feae53159ac..6f1b59c69865 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java @@ -43,7 +43,7 @@ public class TypographicClock extends TextView { private final Resources mResources; private final String[] mHours; private final String[] mMinutes; - private final int mAccentColor; + private int mAccentColor; private Calendar mTime; private String mDescFormat; private TimeZone mTimeZone; @@ -106,6 +106,13 @@ public class TypographicClock extends TextView { mTime.setTimeZone(timeZone); } + /** + * Sets the accent color used on the clock face. + */ + public void setClockColor(int color) { + mAccentColor = color; + } + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); diff --git a/packages/SystemUI/src/com/android/systemui/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/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java index fdf18ce24f50..900ea72d856c 100644 --- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java +++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java @@ -48,6 +48,7 @@ import javax.inject.Singleton; @Singleton public class SysuiColorExtractor extends ColorExtractor implements Dumpable { private static final String TAG = "SysuiColorExtractor"; + private final Tonal mTonal; private boolean mWallpaperVisible; private boolean mHasBackdrop; // Colors to return when the wallpaper isn't visible @@ -61,6 +62,7 @@ public class SysuiColorExtractor extends ColorExtractor implements Dumpable { @VisibleForTesting public SysuiColorExtractor(Context context, ExtractionType type, boolean registerVisibility) { super(context, type); + mTonal = type instanceof Tonal ? (Tonal) type : new Tonal(context); mWpHiddenColors = new GradientColors(); WallpaperColors systemColors = getWallpaperColors(WallpaperManager.FLAG_SYSTEM); @@ -94,7 +96,7 @@ public class SysuiColorExtractor extends ColorExtractor implements Dumpable { } private void updateDefaultGradients(WallpaperColors colors) { - Tonal.applyFallback(colors, mWpHiddenColors); + mTonal.applyFallback(colors, mWpHiddenColors); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java index ddd9cbf209d6..aebadf936e0c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java +++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java @@ -16,6 +16,7 @@ package com.android.systemui.media; +import android.annotation.Nullable; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; @@ -24,6 +25,7 @@ import android.media.AudioAttributes; import android.media.IAudioService; import android.media.IRingtonePlayer; import android.media.Ringtone; +import android.media.VolumeShaper; import android.net.Uri; import android.os.Binder; import android.os.IBinder; @@ -78,11 +80,16 @@ public class RingtonePlayer extends SystemUI { private final Ringtone mRingtone; public Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa) { + this(token, uri, user, aa, null); + } + + Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa, + @Nullable VolumeShaper.Configuration volumeShaperConfig) { mToken = token; mRingtone = new Ringtone(getContextForUser(user), false); mRingtone.setAudioAttributes(aa); - mRingtone.setUri(uri); + mRingtone.setUri(uri, volumeShaperConfig); } @Override @@ -99,6 +106,12 @@ public class RingtonePlayer extends SystemUI { @Override public void play(IBinder token, Uri uri, AudioAttributes aa, float volume, boolean looping) throws RemoteException { + playWithVolumeShaping(token, uri, aa, volume, looping, null); + } + @Override + public void playWithVolumeShaping(IBinder token, Uri uri, AudioAttributes aa, float volume, + boolean looping, @Nullable VolumeShaper.Configuration volumeShaperConfig) + throws RemoteException { if (LOGD) { Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid=" + Binder.getCallingUid() + ")"); @@ -108,7 +121,7 @@ public class RingtonePlayer extends SystemUI { client = mClients.get(token); if (client == null) { final UserHandle user = Binder.getCallingUserHandle(); - client = new Client(token, uri, user, aa); + client = new Client(token, uri, user, aa, volumeShaperConfig); token.linkToDeath(client, 0); mClients.put(token, client); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index 82aa4737af99..9c65994425ed 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -79,6 +79,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call private static final int MSG_RESIZE_IMMEDIATE = 1; private static final int MSG_RESIZE_ANIMATE = 2; + private static final int MSG_OFFSET_ANIMATE = 3; private Context mContext; private IActivityManager mActivityManager; @@ -360,9 +361,20 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call /** * Animates the PiP to offset it from the IME or shelf. */ - void animateToOffset(Rect toBounds) { + void animateToOffset(Rect originalBounds, int offset) { cancelAnimations(); - resizeAndAnimatePipUnchecked(toBounds, SHIFT_DURATION); + adjustAndAnimatePipOffset(originalBounds, offset, SHIFT_DURATION); + } + + private void adjustAndAnimatePipOffset(Rect originalBounds, int offset, int duration) { + if (offset == 0) { + return; + } + SomeArgs args = SomeArgs.obtain(); + args.arg1 = originalBounds; + args.argi1 = offset; + args.argi2 = duration; + mHandler.sendMessage(mHandler.obtainMessage(MSG_OFFSET_ANIMATE, args)); } /** @@ -549,6 +561,31 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call return true; } + case MSG_OFFSET_ANIMATE: { + SomeArgs args = (SomeArgs) msg.obj; + Rect originalBounds = (Rect) args.arg1; + final int offset = args.argi1; + final int duration = args.argi2; + try { + StackInfo stackInfo = mActivityTaskManager.getStackInfo( + WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED); + if (stackInfo == null) { + // In the case where we've already re-expanded or dismissed the PiP, then + // just skip the resize + return true; + } + + mActivityTaskManager.offsetPinnedStackBounds(stackInfo.stackId, originalBounds, + 0/* xOffset */, offset, duration); + Rect toBounds = new Rect(originalBounds); + toBounds.offset(0, offset); + mBounds.set(toBounds); + } catch (RemoteException e) { + Log.e(TAG, "Could not animate offset pinned stack with offset: " + offset, e); + } + return true; + } + default: return false; } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 6a9f24c619fe..cef1b6b1d93b 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -346,12 +346,11 @@ public class PipTouchHandler { } private void animateToOffset(Rect animatingBounds, Rect toAdjustedBounds) { - final Rect bounds = new Rect(animatingBounds); - bounds.offset(0, toAdjustedBounds.bottom - bounds.top); + int offset = toAdjustedBounds.bottom - animatingBounds.top; // In landscape mode, PIP window can go offset while launching IME. We want to align the // the top of the PIP window with the top of the movement bounds in that case. - bounds.offset(0, Math.max(0, mMovementBounds.top - bounds.top)); - mMotionHelper.animateToOffset(bounds); + offset += Math.max(0, mMovementBounds.top - animatingBounds.top); + mMotionHelper.animateToOffset(animatingBounds, offset); } private void onRegistrationChanged(boolean isRegistered) { diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index f0543454073d..c43f5728aaa2 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -54,6 +54,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.time.Duration; import java.util.Arrays; +import java.util.concurrent.Future; public class PowerUI extends SystemUI { static final String TAG = "PowerUI"; @@ -80,6 +81,7 @@ public class PowerUI extends SystemUI { private Estimate mLastEstimate; private boolean mLowWarningShownThisChargeCycle; private boolean mSevereWarningShownThisChargeCycle; + private Future mLastShowWarningTask; private int mLowBatteryAlertCloseLevel; private final int[] mLowBatteryReminderLevels = new int[2]; @@ -247,7 +249,10 @@ public class PowerUI extends SystemUI { } // Show the correct version of low battery warning if needed - ThreadUtils.postOnBackgroundThread(() -> { + if (mLastShowWarningTask != null) { + mLastShowWarningTask.cancel(true); + } + mLastShowWarningTask = ThreadUtils.postOnBackgroundThread(() -> { maybeShowBatteryWarning( oldBatteryLevel, plugged, oldPlugged, oldBucket, bucket); }); @@ -276,7 +281,7 @@ public class PowerUI extends SystemUI { estimate = mEnhancedEstimates.getEstimate(); mLastEstimate = estimate; } - // Turbo is not always booted once SysUI is running so we have ot make sure we actually + // Turbo is not always booted once SysUI is running so we have to make sure we actually // get data back if (estimate != null) { mTimeRemaining = estimate.estimateMillis; @@ -355,13 +360,26 @@ public class PowerUI extends SystemUI { // Only show the low warning once per charge cycle & no battery saver final boolean canShowWarning = !mLowWarningShownThisChargeCycle && !isPowerSaver && (timeRemaining < mEnhancedEstimates.getLowWarningThreshold() - || mBatteryLevel <= warnLevel); + || mBatteryLevel <= warnLevel); // Only show the severe warning once per charge cycle final boolean canShowSevereWarning = !mSevereWarningShownThisChargeCycle && (timeRemaining < mEnhancedEstimates.getSevereWarningThreshold() - || mBatteryLevel <= critLevel); - + || mBatteryLevel <= critLevel); + + final boolean canShow = canShowWarning || canShowSevereWarning; + if (DEBUG) { + Slog.d(TAG, "Enhanced trigger is: " + canShow + "\nwith values: " + + " mLowWarningShownThisChargeCycle: " + mLowWarningShownThisChargeCycle + + " mSevereWarningShownThisChargeCycle: " + mSevereWarningShownThisChargeCycle + + " mEnhancedEstimates.timeremaining: " + timeRemaining + + " mBatteryLevel: " + mBatteryLevel + + " canShowWarning: " + canShowWarning + + " canShowSevereWarning: " + canShowSevereWarning + + " plugged: " + plugged + + " batteryStatus: " + batteryStatus + + " isPowerSaver: " + isPowerSaver); + } return canShowWarning || canShowSevereWarning; } diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt index 65ed889f34e1..ecbf0246a8ba 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt @@ -16,6 +16,7 @@ package com.android.systemui.privacy import android.content.Context import android.util.AttributeSet +import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.LinearLayout @@ -29,14 +30,25 @@ class OngoingPrivacyChip @JvmOverloads constructor( defStyleRes: Int = 0 ) : LinearLayout(context, attrs, defStyleAttrs, defStyleRes) { - private val iconMargin = - context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_margin) + private val iconMarginExpanded = context.resources.getDimensionPixelSize( + R.dimen.ongoing_appops_chip_icon_margin_expanded) + private val iconMarginCollapsed = context.resources.getDimensionPixelSize( + R.dimen.ongoing_appops_chip_icon_margin_collapsed) private val iconSize = context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_size) - val iconColor = context.resources.getColor( + private val iconColor = context.resources.getColor( R.color.status_bar_clock_color, context.theme) + private val backgroundDrawable = context.getDrawable(R.drawable.privacy_chip_bg) private lateinit var text: TextView private lateinit var iconsContainer: LinearLayout + private lateinit var inUseText: TextView + var expanded = false + set(value) { + if (value != field) { + field = value + updateView() + } + } var builder = PrivacyDialogBuilder(context, emptyList<PrivacyItem>()) var privacyList = emptyList<PrivacyItem>() set(value) { @@ -48,15 +60,18 @@ class OngoingPrivacyChip @JvmOverloads constructor( override fun onFinishInflate() { super.onFinishInflate() + inUseText = findViewById(R.id.in_use_text) text = findViewById(R.id.text_container) iconsContainer = findViewById(R.id.icons_container) } // Should only be called if the builder icons or app changed private fun updateView() { + inUseText.visibility = if (expanded) View.GONE else View.VISIBLE + background = if (expanded) backgroundDrawable else null fun setIcons(dialogBuilder: PrivacyDialogBuilder, iconsContainer: ViewGroup) { iconsContainer.removeAllViews() - dialogBuilder.generateIcons().forEach { + dialogBuilder.generateIcons().forEachIndexed { i, it -> it.mutate() it.setTint(iconColor) val image = ImageView(context).apply { @@ -64,17 +79,19 @@ class OngoingPrivacyChip @JvmOverloads constructor( scaleType = ImageView.ScaleType.CENTER_INSIDE } iconsContainer.addView(image, iconSize, iconSize) - val lp = image.layoutParams as MarginLayoutParams - lp.marginStart = iconMargin - image.layoutParams = lp + if (i != 0) { + val lp = image.layoutParams as MarginLayoutParams + lp.marginStart = if (expanded) iconMarginExpanded else iconMarginCollapsed + image.layoutParams = lp + } } } if (!privacyList.isEmpty()) { generateContentDescription() setIcons(builder, iconsContainer) - text.visibility = if (builder.types.size == 1) VISIBLE else GONE - if (builder.types.size == 1) { + text.visibility = if (builder.types.size == 1 && expanded) VISIBLE else GONE + if (builder.types.size == 1 && expanded) { if (builder.app != null) { text.setText(builder.app?.applicationName) } else { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java index b865ce8d261a..f91c9d944439 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java @@ -189,6 +189,7 @@ public class QSFooterImpl extends FrameLayout implements QSFooter, addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> updateAnimator(right - left)); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + updateEverything(); } private void updateAnimator(int width) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 74e82b270aa0..ee9255c54a62 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -124,6 +124,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements private TintedIconManager mIconManager; private TouchAnimator mStatusIconsAlphaAnimator; private TouchAnimator mHeaderTextContainerAlphaAnimator; + private TouchAnimator mPrivacyChipAlphaAnimator; private View mSystemIconsView; private View mQuickQsStatusIcons; @@ -212,6 +213,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements mNextAlarmTextView = findViewById(R.id.next_alarm_text); mRingerModeIcon = findViewById(R.id.ringer_mode_icon); mRingerModeTextView = findViewById(R.id.ringer_mode_text); + mPrivacyChip = findViewById(R.id.privacy_chip); + mPrivacyChip.setOnClickListener(this); updateResources(); @@ -230,8 +233,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements mClockView = findViewById(R.id.clock); mClockView.setOnClickListener(this); mDateView = findViewById(R.id.date); - mPrivacyChip = findViewById(R.id.privacy_chip); - mPrivacyChip.setOnClickListener(this); mSpace = findViewById(R.id.space); // Tint for the battery icons are handled in setupHost() @@ -383,6 +384,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements updateStatusIconAlphaAnimator(); updateHeaderTextContainerAlphaAnimator(); + updatePrivacyChipAlphaAnimator(); } private void updateStatusIconAlphaAnimator() { @@ -398,6 +400,12 @@ public class QuickStatusBarHeader extends RelativeLayout implements .build(); } + private void updatePrivacyChipAlphaAnimator() { + mPrivacyChipAlphaAnimator = new TouchAnimator.Builder() + .addFloat(mPrivacyChip, "alpha", 1, 0, 1) + .build(); + } + public void setExpanded(boolean expanded) { if (mExpanded == expanded) return; mExpanded = expanded; @@ -431,6 +439,10 @@ public class QuickStatusBarHeader extends RelativeLayout implements if (mHeaderTextContainerAlphaAnimator != null) { mHeaderTextContainerAlphaAnimator.setPosition(keyguardExpansionFraction); } + if (mPrivacyChipAlphaAnimator != null) { + mPrivacyChip.setExpanded(expansionFraction > 0.5); + mPrivacyChipAlphaAnimator.setPosition(keyguardExpansionFraction); + } // Check the original expansion fraction - we don't want to show the tooltip until the // panel is pulled all the way out. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java index 54ed0d9cd8ce..8b522a2033f8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java @@ -16,8 +16,10 @@ package com.android.systemui.statusbar.notification.collection; +import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; +import android.app.Person; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.SnoozeCriterion; @@ -235,8 +237,11 @@ public class NotificationData { if (mRankingMap != null) { getRanking(statusBarNotification.getKey(), mTmpRanking); if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT - || statusBarNotification.getNotification().isForegroundService() - || statusBarNotification.getNotification().hasMediaSession()) { + || isImportantOngoing(statusBarNotification.getNotification()) + || statusBarNotification.getNotification().hasMediaSession() + || hasPerson(statusBarNotification.getNotification()) + || hasStyle(statusBarNotification.getNotification(), + Notification.MessagingStyle.class)) { return true; } if (mGroupManager.isSummaryOfGroup(statusBarNotification)) { @@ -252,6 +257,24 @@ public class NotificationData { return false; } + private boolean isImportantOngoing(Notification notification) { + return notification.isForegroundService() + && mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_LOW; + } + + private boolean hasStyle(Notification notification, Class targetStyle) { + Class<? extends Notification.Style> style = notification.getNotificationStyle(); + return targetStyle.equals(style); + } + + private boolean hasPerson(Notification notification) { + // TODO: cache favorite and recent contacts to check contact affinity + ArrayList<Person> people = notification.extras != null + ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST) + : new ArrayList<>(); + return people != null && !people.isEmpty(); + } + public boolean isAmbient(String key) { if (mRankingMap != null) { getRanking(key, mTmpRanking); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java index 43b5503682cc..a1fcbebecea1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java @@ -30,6 +30,9 @@ public class NotificationCounters { /** Counter tag for when the user hits 'stop notifications' in the blocking helper. */ public static final String BLOCKING_HELPER_STOP_NOTIFICATIONS = "blocking_helper_stop_notifications"; + /** Counter tag for when the user hits 'deliver silently' in the blocking helper. */ + public static final String BLOCKING_HELPER_DELIVER_SILENTLY = + "blocking_helper_deliver_silently"; /** Counter tag for when the user hits 'show silently' in the blocking helper. */ public static final String BLOCKING_HELPER_TOGGLE_SILENT = "blocking_helper_toggle_silent"; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/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/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java index ba2aec0dd3e1..9f36a1eb9943 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java @@ -23,12 +23,19 @@ import static android.app.Notification.CATEGORY_CALL; import static android.app.Notification.CATEGORY_EVENT; import static android.app.Notification.CATEGORY_MESSAGE; import static android.app.Notification.CATEGORY_REMINDER; +import static android.app.NotificationManager.IMPORTANCE_LOW; +import static android.app.NotificationManager.IMPORTANCE_MIN; + +import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_CHANNEL; +import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_IMPORTANCE; +import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_VIS_EFFECTS; import static junit.framework.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -36,6 +43,7 @@ import static org.mockito.Mockito.when; import android.Manifest; import android.app.Notification; import android.app.NotificationChannel; +import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Person; import android.content.Intent; @@ -84,8 +92,6 @@ public class NotificationDataTest extends SysuiTestCase { private static final int UID_NORMAL = 123; private static final int UID_ALLOW_DURING_SETUP = 456; - private static final String TEST_HIDDEN_NOTIFICATION_KEY = "testHiddenNotificationKey"; - private static final String TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY = "exempt"; private static final NotificationChannel NOTIFICATION_CHANNEL = new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE); @@ -97,7 +103,7 @@ public class NotificationDataTest extends SysuiTestCase { NotificationData.KeyguardEnvironment mEnvironment; private final IPackageManager mMockPackageManager = mock(IPackageManager.class); - private NotificationData mNotificationData; + private TestableNotificationData mNotificationData; private ExpandableNotificationRow mRow; @Before @@ -131,6 +137,7 @@ public class NotificationDataTest extends SysuiTestCase { @Test public void testChannelSetWhenAdded() { + mNotificationData.rankingOverrides.putParcelable(OVERRIDE_CHANNEL, NOTIFICATION_CHANNEL); mNotificationData.add(mRow.getEntry()); assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().channel); } @@ -217,12 +224,12 @@ public class NotificationDataTest extends SysuiTestCase { @Test public void testIsExemptFromDndVisualSuppression_foreground() { initStatusBarNotification(false); - when(mMockStatusBarNotification.getKey()).thenReturn( - TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); + Notification n = mMockStatusBarNotification.getNotification(); n.flags = Notification.FLAG_FOREGROUND_SERVICE; NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification); mNotificationData.add(entry); + mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS, 255); assertTrue(entry.isExemptFromDndVisualSuppression()); assertFalse(entry.shouldSuppressAmbient()); @@ -231,8 +238,6 @@ public class NotificationDataTest extends SysuiTestCase { @Test public void testIsExemptFromDndVisualSuppression_media() { initStatusBarNotification(false); - when(mMockStatusBarNotification.getKey()).thenReturn( - TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); Notification n = mMockStatusBarNotification.getNotification(); Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n); nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class))); @@ -240,6 +245,7 @@ public class NotificationDataTest extends SysuiTestCase { when(mMockStatusBarNotification.getNotification()).thenReturn(n); NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification); mNotificationData.add(entry); + mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS, 255); assertTrue(entry.isExemptFromDndVisualSuppression()); assertFalse(entry.shouldSuppressAmbient()); @@ -248,11 +254,10 @@ public class NotificationDataTest extends SysuiTestCase { @Test public void testIsExemptFromDndVisualSuppression_system() { initStatusBarNotification(false); - when(mMockStatusBarNotification.getKey()).thenReturn( - TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification); entry.mIsSystemNotification = true; mNotificationData.add(entry); + mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS, 255); assertTrue(entry.isExemptFromDndVisualSuppression()); assertFalse(entry.shouldSuppressAmbient()); @@ -261,10 +266,10 @@ public class NotificationDataTest extends SysuiTestCase { @Test public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() { initStatusBarNotification(false); - when(mMockStatusBarNotification.getKey()).thenReturn( - TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification); entry.mIsSystemNotification = true; + mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS, + NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT); mNotificationData.add(entry); when(mMockStatusBarNotification.getNotification()).thenReturn( @@ -353,6 +358,64 @@ public class NotificationDataTest extends SysuiTestCase { assertTrue(entry.isLastMessageFromReply()); } + @Test + public void personHighPriority() { + Person person = new Person.Builder() + .setName("name") + .setKey("abc") + .setUri("uri") + .setBot(true) + .build(); + + Notification notification = new Notification.Builder(mContext, "test") + .addPerson(person) + .build(); + + StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, + notification, mContext.getUser(), "", 0); + + assertTrue(mNotificationData.isHighPriority(sbn)); + } + + @Test + public void messagingStyleHighPriority() { + + Notification notification = new Notification.Builder(mContext, "test") + .setStyle(new Notification.MessagingStyle("")) + .build(); + + StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, + notification, mContext.getUser(), "", 0); + + assertTrue(mNotificationData.isHighPriority(sbn)); + } + + @Test + public void minForegroundNotHighPriority() { + Notification notification = mock(Notification.class); + when(notification.isForegroundService()).thenReturn(true); + + mNotificationData.rankingOverrides.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_MIN); + + StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, + notification, mContext.getUser(), "", 0); + + assertFalse(mNotificationData.isHighPriority(sbn)); + } + + @Test + public void lowForegroundHighPriority() { + Notification notification = mock(Notification.class); + when(notification.isForegroundService()).thenReturn(true); + + mNotificationData.rankingOverrides.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW); + + StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, + notification, mContext.getUser(), "", 0); + + assertTrue(mNotificationData.isHighPriority(sbn)); + } + private void initStatusBarNotification(boolean allowDuringSetup) { Bundle bundle = new Bundle(); bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup); @@ -362,39 +425,90 @@ public class NotificationDataTest extends SysuiTestCase { when(mMockStatusBarNotification.getNotification()).thenReturn(notification); } - private class TestableNotificationData extends NotificationData { + public static class TestableNotificationData extends NotificationData { public TestableNotificationData() { super(); } + public static final String OVERRIDE_RANK = "r"; + public static final String OVERRIDE_DND = "dnd"; + public static final String OVERRIDE_VIS_OVERRIDE = "vo"; + public static final String OVERRIDE_VIS_EFFECTS = "ve"; + public static final String OVERRIDE_IMPORTANCE = "i"; + public static final String OVERRIDE_IMP_EXP = "ie"; + public static final String OVERRIDE_GROUP = "g"; + public static final String OVERRIDE_CHANNEL = "c"; + public static final String OVERRIDE_PEOPLE = "p"; + public static final String OVERRIDE_SNOOZE_CRITERIA = "sc"; + public static final String OVERRIDE_BADGE = "b"; + public static final String OVERRIDE_USER_SENTIMENT = "us"; + public static final String OVERRIDE_HIDDEN = "h"; + public static final String OVERRIDE_LAST_ALERTED = "la"; + public static final String OVERRIDE_NOISY = "n"; + public static final String OVERRIDE_SMART_ACTIONS = "sa"; + public static final String OVERRIDE_SMART_REPLIES = "sr"; + public static final String OVERRIDE_BUBBLE = "cb"; + + public Bundle rankingOverrides = new Bundle(); + @Override protected boolean getRanking(String key, Ranking outRanking) { super.getRanking(key, outRanking); - if (key.equals(TEST_HIDDEN_NOTIFICATION_KEY)) { - outRanking.populate(key, outRanking.getRank(), - outRanking.matchesInterruptionFilter(), - outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(), - outRanking.getImportance(), outRanking.getImportanceExplanation(), - outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null, - outRanking.canShowBadge(), outRanking.getUserSentiment(), true, - -1, false, null, null, outRanking.canBubble()); - } else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) { - outRanking.populate(key, outRanking.getRank(), - outRanking.matchesInterruptionFilter(), - outRanking.getVisibilityOverride(), 255, - outRanking.getImportance(), outRanking.getImportanceExplanation(), - outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null, - outRanking.canShowBadge(), outRanking.getUserSentiment(), true, -1, - false, null, null, outRanking.canBubble()); - } else { - outRanking.populate(key, outRanking.getRank(), - outRanking.matchesInterruptionFilter(), - outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(), - outRanking.getImportance(), outRanking.getImportanceExplanation(), - outRanking.getOverrideGroupKey(), NOTIFICATION_CHANNEL, null, null, - outRanking.canShowBadge(), outRanking.getUserSentiment(), false, -1, - false, null, null, outRanking.canBubble()); + + ArrayList<String> currentAdditionalPeople = new ArrayList<>(); + if (outRanking.getAdditionalPeople() != null) { + currentAdditionalPeople.addAll(outRanking.getAdditionalPeople()); + } + + ArrayList<SnoozeCriterion> currentSnooze = new ArrayList<>(); + if (outRanking.getSnoozeCriteria() != null) { + currentSnooze.addAll(outRanking.getSnoozeCriteria()); + } + + ArrayList<Notification.Action> currentActions = new ArrayList<>(); + if (outRanking.getSmartActions() != null) { + currentActions.addAll(outRanking.getSmartActions()); } + + ArrayList<CharSequence> currentReplies = new ArrayList<>(); + if (outRanking.getSmartReplies() != null) { + currentReplies.addAll(outRanking.getSmartReplies()); + } + + outRanking.populate(key, + rankingOverrides.getInt(OVERRIDE_RANK, outRanking.getRank()), + rankingOverrides.getBoolean(OVERRIDE_DND, + outRanking.matchesInterruptionFilter()), + rankingOverrides.getInt(OVERRIDE_VIS_OVERRIDE, + outRanking.getVisibilityOverride()), + rankingOverrides.getInt(OVERRIDE_VIS_EFFECTS, + outRanking.getSuppressedVisualEffects()), + rankingOverrides.getInt(OVERRIDE_IMPORTANCE, outRanking.getImportance()), + rankingOverrides.getCharSequence(OVERRIDE_IMP_EXP, + outRanking.getImportanceExplanation()), + rankingOverrides.getString(OVERRIDE_GROUP, outRanking.getOverrideGroupKey()), + rankingOverrides.containsKey(OVERRIDE_CHANNEL) + ? (NotificationChannel) rankingOverrides.getParcelable(OVERRIDE_CHANNEL) + : outRanking.getChannel(), + rankingOverrides.containsKey(OVERRIDE_PEOPLE) + ? rankingOverrides.getStringArrayList(OVERRIDE_PEOPLE) + : currentAdditionalPeople, + rankingOverrides.containsKey(OVERRIDE_SNOOZE_CRITERIA) + ? rankingOverrides.getParcelableArrayList(OVERRIDE_SNOOZE_CRITERIA) + : currentSnooze, + rankingOverrides.getBoolean(OVERRIDE_BADGE, outRanking.canShowBadge()), + rankingOverrides.getInt(OVERRIDE_USER_SENTIMENT, outRanking.getUserSentiment()), + rankingOverrides.getBoolean(OVERRIDE_HIDDEN, outRanking.isSuspended()), + rankingOverrides.getLong(OVERRIDE_LAST_ALERTED, + outRanking.getLastAudiblyAlertedMillis()), + rankingOverrides.getBoolean(OVERRIDE_NOISY, outRanking.isNoisy()), + rankingOverrides.containsKey(OVERRIDE_SMART_ACTIONS) + ? rankingOverrides.getParcelableArrayList(OVERRIDE_SMART_ACTIONS) + : currentActions, + rankingOverrides.containsKey(OVERRIDE_SMART_REPLIES) + ? rankingOverrides.getCharSequenceArrayList(OVERRIDE_SMART_REPLIES) + : currentReplies, + rankingOverrides.getBoolean(OVERRIDE_BUBBLE, outRanking.canBubble())); return true; } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/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/proto/src/wifi.proto b/proto/src/wifi.proto index fb7585b74118..82359c547a88 100644 --- a/proto/src/wifi.proto +++ b/proto/src/wifi.proto @@ -671,6 +671,9 @@ message ConnectionEvent { // Has bug report been taken. optional bool automatic_bug_report_taken = 9; + + // Connection is using locally generated random MAC address. + optional bool use_randomized_mac = 10 [default = false]; } // Number of occurrences of a specific RSSI poll rssi value diff --git a/sax/tests/saxtests/Android.bp b/sax/tests/saxtests/Android.bp new file mode 100644 index 000000000000..5889f769a645 --- /dev/null +++ b/sax/tests/saxtests/Android.bp @@ -0,0 +1,11 @@ +android_test { + name: "FrameworksSaxTests", + // Include all test java files. + srcs: ["src/**/*.java"], + libs: [ + "android.test.runner", + "android.test.base", + ], + static_libs: ["junit"], + platform_apis: true, +} diff --git a/sax/tests/saxtests/Android.mk b/sax/tests/saxtests/Android.mk deleted file mode 100644 index c4517a9a954a..000000000000 --- a/sax/tests/saxtests/Android.mk +++ /dev/null @@ -1,16 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -# We only want this apk build for tests. -LOCAL_MODULE_TAGS := tests - -# Include all test java files. -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base -LOCAL_STATIC_JAVA_LIBRARIES := junit -LOCAL_PACKAGE_NAME := FrameworksSaxTests -LOCAL_PRIVATE_PLATFORM_APIS := true - -include $(BUILD_PACKAGE) - diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS new file mode 100644 index 000000000000..265674a74b7e --- /dev/null +++ b/services/accessibility/OWNERS @@ -0,0 +1,3 @@ +svetoslavganov@google.com +pweaver@google.com +rhedjao@google.com diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 2e45fa72eaac..4a3f12674eb7 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -49,6 +49,7 @@ import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.UserHandle; import android.os.UserManager; +import android.provider.DeviceConfig; import android.provider.Settings; import android.service.autofill.FillEventHistory; import android.service.autofill.UserData; @@ -167,10 +168,14 @@ public final class AutofillManagerService mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext()); mAm = LocalServices.getService(ActivityManagerInternal.class); + DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_AUTOFILL, + ActivityThread.currentApplication().getMainExecutor(), + (namespace, name, value) -> setSmartSuggestionModesFromDeviceConfig(value)); + setLogLevelFromSettings(); setMaxPartitionsFromSettings(); setMaxVisibleDatasetsFromSettings(); - setSmartSuggestionEmulationFromSettings(); + setSmartSuggestionModesFromDeviceConfig(); final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); @@ -197,9 +202,6 @@ public final class AutofillManagerService resolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS), false, observer, UserHandle.USER_ALL); - resolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS), false, observer, - UserHandle.USER_ALL); } @Override // from AbstractMasterSystemService @@ -214,9 +216,6 @@ public final class AutofillManagerService case Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS: setMaxVisibleDatasetsFromSettings(); break; - case Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS: - setSmartSuggestionEmulationFromSettings(); - break; default: Slog.w(TAG, "Unexpected property (" + property + "); updating cache instead"); // fall through @@ -457,14 +456,25 @@ public final class AutofillManagerService } } - private void setSmartSuggestionEmulationFromSettings() { - final int flags = Settings.Global.getInt(getContext().getContentResolver(), - Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS, 0); - if (sDebug) { - Slog.d(TAG, "setSmartSuggestionEmulationFromSettings(): " - + getSmartSuggestionModeToString(flags)); - } + private void setSmartSuggestionModesFromDeviceConfig() { + final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_AUTOFILL, + AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES); + setSmartSuggestionModesFromDeviceConfig(value); + } + private void setSmartSuggestionModesFromDeviceConfig(@Nullable String value) { + if (sDebug) Slog.d(TAG, "setSmartSuggestionEmulationFromDeviceConfig(): value=" + value); + final int flags; + if (value == null) { + flags = AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM; + } else { + try { + flags = Integer.parseInt(value); + } catch (Exception e) { + Slog.w(TAG, "setSmartSuggestionEmulationFromDeviceConfig(): NAN:" + value); + return; + } + } synchronized (mLock) { mSupportedSmartSuggestionModes = flags; } diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListingMap.java index 2d2e88afccf1..a44890118717 100644 --- a/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java +++ b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListingMap.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,13 +11,14 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ package com.android.server.backup.encryption.chunk; import android.annotation.Nullable; import android.util.proto.ProtoInputStream; + import java.io.IOException; import java.util.Collections; import java.util.HashMap; @@ -30,16 +31,16 @@ import java.util.Map; * It can then tell the server to use that chunk, through telling it the position and length of the * chunk in the previous backup's blob. */ -public class ChunkListing { +public class ChunkListingMap { /** - * Reads a ChunkListing from a {@link ProtoInputStream}. Expects the message to be of format + * Reads a ChunkListingMap from a {@link ProtoInputStream}. Expects the message to be of format * {@link ChunksMetadataProto.ChunkListing}. * * @param inputStream Currently at a {@link ChunksMetadataProto.ChunkListing} message. * @throws IOException when the message is not structured as expected or a field can not be * read. */ - public static ChunkListing readFromProto(ProtoInputStream inputStream) throws IOException { + public static ChunkListingMap readFromProto(ProtoInputStream inputStream) throws IOException { Map<ChunkHash, Entry> entries = new HashMap(); long start = 0; @@ -54,12 +55,12 @@ public class ChunkListing { } } - return new ChunkListing(entries); + return new ChunkListingMap(entries); } private final Map<ChunkHash, Entry> mChunksByHash; - private ChunkListing(Map<ChunkHash, Entry> chunksByHash) { + private ChunkListingMap(Map<ChunkHash, Entry> chunksByHash) { mChunksByHash = Collections.unmodifiableMap(new HashMap<>(chunksByHash)); } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java index 39d5c9d0b777..86ad52d9a42b 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java @@ -77,15 +77,12 @@ public final class ContentCaptureManagerServiceShellCommand extends ShellCommand pw.println(" Temporarily (for DURATION ms) changes the service implemtation."); pw.println(" To reset, call with just the USER_ID argument."); pw.println(""); - pw.println(""); pw.println(" set default-service-enabled USER_ID [true|false]"); pw.println(" Enable / disable the default service for the user."); pw.println(""); - pw.println(""); pw.println(" get default-service-enabled USER_ID"); pw.println(" Checks whether the default service is enabled for the user."); pw.println(""); - pw.println(""); pw.println(" list sessions [--user USER_ID]"); pw.println(" Lists all pending sessions."); pw.println(""); diff --git a/services/core/java/com/android/server/AlarmManagerInternal.java b/services/core/java/com/android/server/AlarmManagerInternal.java index 275661084aa3..5b0de5e2aae0 100644 --- a/services/core/java/com/android/server/AlarmManagerInternal.java +++ b/services/core/java/com/android/server/AlarmManagerInternal.java @@ -26,6 +26,8 @@ public interface AlarmManagerInternal { void broadcastAlarmComplete(int recipientUid); } + /** Returns true if AlarmManager is delaying alarms due to device idle. */ + boolean isIdling(); public void removeAlarmsForUid(int uid); public void registerInFlightListener(InFlightListener callback); } diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 10b532700d1b..a400cc384a58 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -1991,6 +1991,11 @@ class AlarmManagerService extends SystemService { */ private final class LocalService implements AlarmManagerInternal { @Override + public boolean isIdling() { + return isIdlingImpl(); + } + + @Override public void removeAlarmsForUid(int uid) { synchronized (mLock) { removeLocked(uid); @@ -2823,6 +2828,12 @@ class AlarmManagerService extends SystemService { } } + private boolean isIdlingImpl() { + synchronized (mLock) { + return mPendingIdleUntil != null; + } + } + AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) { synchronized (mLock) { return mNextAlarmClockForUser.get(userId); diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java index eafa0e2a6786..e51025943df4 100644 --- a/services/core/java/com/android/server/BinderCallsStatsService.java +++ b/services/core/java/com/android/server/BinderCallsStatsService.java @@ -121,6 +121,8 @@ public class BinderCallsStatsService extends Binder { private static final String SETTINGS_DETAILED_TRACKING_KEY = "detailed_tracking"; private static final String SETTINGS_UPLOAD_DATA_KEY = "upload_data"; private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; + private static final String SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY = "track_screen_state"; + private static final String SETTINGS_TRACK_DIRECT_CALLING_UID_KEY = "track_calling_uid"; private static final String SETTINGS_MAX_CALL_STATS_KEY = "max_call_stats_count"; private boolean mEnabled; @@ -169,6 +171,12 @@ public class BinderCallsStatsService extends Binder { mBinderCallsStats.setMaxBinderCallStats(mParser.getInt( SETTINGS_MAX_CALL_STATS_KEY, BinderCallsStats.MAX_BINDER_CALL_STATS_COUNT_DEFAULT)); + mBinderCallsStats.setTrackScreenInteractive( + mParser.getBoolean(SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY, + BinderCallsStats.DEFAULT_TRACK_SCREEN_INTERACTIVE)); + mBinderCallsStats.setTrackDirectCallerUid( + mParser.getBoolean(SETTINGS_TRACK_DIRECT_CALLING_UID_KEY, + BinderCallsStats.DEFAULT_TRACK_DIRECT_CALLING_UID)); final boolean enabled = diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index fe4411c1dbb5..d1cd072ee215 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -38,7 +38,6 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.uidRulesToString; -import static android.net.NetworkStack.NETWORKSTACK_PACKAGE_NAME; import static android.net.shared.NetworkMonitorUtils.isValidationRequired; import static android.net.shared.NetworkParcelableUtil.toStableParcelable; import static android.os.Process.INVALID_UID; @@ -2667,9 +2666,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public void showProvisioningNotification(String action) { + public void showProvisioningNotification(String action, String packageName) { final Intent intent = new Intent(action); - intent.setPackage(NETWORKSTACK_PACKAGE_NAME); + intent.setPackage(packageName); final PendingIntent pendingIntent; // Only the system server can register notifications with package "android" diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 39030aaf3eb4..6b663941f8fb 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -271,6 +271,7 @@ public class DeviceIdleController extends SystemService private static final int EVENT_BUFFER_SIZE = 100; private AlarmManager mAlarmManager; + private AlarmManagerInternal mLocalAlarmManager; private IBatteryStats mBatteryStats; private ActivityManagerInternal mLocalActivityManager; private ActivityTaskManagerInternal mLocalActivityTaskManager; @@ -616,7 +617,8 @@ public class DeviceIdleController extends SystemService } }; - private final AlarmManager.OnAlarmListener mDeepAlarmListener + @VisibleForTesting + final AlarmManager.OnAlarmListener mDeepAlarmListener = new AlarmManager.OnAlarmListener() { @Override public void onAlarm() { @@ -1874,6 +1876,7 @@ public class DeviceIdleController extends SystemService if (phase == PHASE_SYSTEM_SERVICES_READY) { synchronized (this) { mAlarmManager = mInjector.getAlarmManager(); + mLocalAlarmManager = getLocalService(AlarmManagerInternal.class); mBatteryStats = BatteryStatsService.getService(); mLocalActivityManager = getLocalService(ActivityManagerInternal.class); mLocalActivityTaskManager = getLocalService(ActivityTaskManagerInternal.class); @@ -2605,6 +2608,16 @@ public class DeviceIdleController extends SystemService // next natural time to come out of it. } + + /** Returns true if the screen is locked. */ + @VisibleForTesting + boolean isKeyguardShowing() { + synchronized (this) { + return mScreenLocked; + } + } + + @VisibleForTesting void keyguardShowingLocked(boolean showing) { if (DEBUG) Slog.i(TAG, "keyguardShowing=" + showing); if (mScreenLocked != showing) { @@ -2616,25 +2629,38 @@ public class DeviceIdleController extends SystemService } } + @VisibleForTesting void scheduleReportActiveLocked(String activeReason, int activeUid) { Message msg = mHandler.obtainMessage(MSG_REPORT_ACTIVE, activeUid, 0, activeReason); mHandler.sendMessage(msg); } void becomeActiveLocked(String activeReason, int activeUid) { - if (DEBUG) Slog.i(TAG, "becomeActiveLocked, reason = " + activeReason); + becomeActiveLocked(activeReason, activeUid, mConstants.INACTIVE_TIMEOUT, true); + } + + private void becomeActiveLocked(String activeReason, int activeUid, + long newInactiveTimeout, boolean changeLightIdle) { + if (DEBUG) { + Slog.i(TAG, "becomeActiveLocked, reason=" + activeReason + + ", changeLightIdle=" + changeLightIdle); + } if (mState != STATE_ACTIVE || mLightState != STATE_ACTIVE) { EventLogTags.writeDeviceIdle(STATE_ACTIVE, activeReason); - EventLogTags.writeDeviceIdleLight(LIGHT_STATE_ACTIVE, activeReason); - scheduleReportActiveLocked(activeReason, activeUid); mState = STATE_ACTIVE; - mLightState = LIGHT_STATE_ACTIVE; - mInactiveTimeout = mConstants.INACTIVE_TIMEOUT; + mInactiveTimeout = newInactiveTimeout; mCurIdleBudget = 0; mMaintenanceStartTime = 0; resetIdleManagementLocked(); - resetLightIdleManagementLocked(); - addEvent(EVENT_NORMAL, activeReason); + + if (changeLightIdle) { + EventLogTags.writeDeviceIdleLight(LIGHT_STATE_ACTIVE, activeReason); + mLightState = LIGHT_STATE_ACTIVE; + resetLightIdleManagementLocked(); + // Only report active if light is also ACTIVE. + scheduleReportActiveLocked(activeReason, activeUid); + addEvent(EVENT_NORMAL, activeReason); + } } } @@ -2654,50 +2680,82 @@ public class DeviceIdleController extends SystemService } } + /** Sanity check to make sure DeviceIdleController and AlarmManager are on the same page. */ + private void verifyAlarmStateLocked() { + if (mState == STATE_ACTIVE && mNextAlarmTime != 0) { + Slog.wtf(TAG, "mState=ACTIVE but mNextAlarmTime=" + mNextAlarmTime); + } + if (mState != STATE_IDLE && mLocalAlarmManager.isIdling()) { + Slog.wtf(TAG, "mState=" + stateToString(mState) + " but AlarmManager is idling"); + } + if (mState == STATE_IDLE && !mLocalAlarmManager.isIdling()) { + Slog.wtf(TAG, "mState=IDLE but AlarmManager is not idling"); + } + if (mLightState == LIGHT_STATE_ACTIVE && mNextLightAlarmTime != 0) { + Slog.wtf(TAG, "mLightState=ACTIVE but mNextLightAlarmTime is " + + TimeUtils.formatDuration(mNextLightAlarmTime - SystemClock.elapsedRealtime()) + + " from now"); + } + } + void becomeInactiveIfAppropriateLocked() { - if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()"); - if ((!mScreenOn && !mCharging) || mForceIdle) { - // Become inactive and determine if we will ultimately go idle. - if (mDeepEnabled) { - if (mQuickDozeActivated) { - if (mState == STATE_QUICK_DOZE_DELAY || mState == STATE_IDLE - || mState == STATE_IDLE_MAINTENANCE) { - // Already "idling". Don't want to restart the process. - // mLightState can't be LIGHT_STATE_ACTIVE if mState is any of these 3 - // values, so returning here is safe. - return; - } - if (DEBUG) { - Slog.d(TAG, "Moved from " - + stateToString(mState) + " to STATE_QUICK_DOZE_DELAY"); - } - mState = STATE_QUICK_DOZE_DELAY; - // Make sure any motion sensing or locating is stopped. - resetIdleManagementLocked(); - // Wait a small amount of time in case something (eg: background service from - // recently closed app) needs to finish running. - scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false); - EventLogTags.writeDeviceIdle(mState, "no activity"); - } else if (mState == STATE_ACTIVE) { - mState = STATE_INACTIVE; - if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE"); - resetIdleManagementLocked(); - long delay = mInactiveTimeout; - if (shouldUseIdleTimeoutFactorLocked()) { - delay = (long) (mPreIdleFactor * delay); - } - scheduleAlarmLocked(delay, false); - EventLogTags.writeDeviceIdle(mState, "no activity"); + verifyAlarmStateLocked(); + + final boolean isScreenBlockingInactive = + mScreenOn && (!mConstants.WAIT_FOR_UNLOCK || !mScreenLocked); + if (DEBUG) { + Slog.d(TAG, "becomeInactiveIfAppropriateLocked():" + + " isScreenBlockingInactive=" + isScreenBlockingInactive + + " (mScreenOn=" + mScreenOn + + ", WAIT_FOR_UNLOCK=" + mConstants.WAIT_FOR_UNLOCK + + ", mScreenLocked=" + mScreenLocked + ")" + + " mCharging=" + mCharging + + " mForceIdle=" + mForceIdle + ); + } + if (!mForceIdle && (mCharging || isScreenBlockingInactive)) { + return; + } + // Become inactive and determine if we will ultimately go idle. + if (mDeepEnabled) { + if (mQuickDozeActivated) { + if (mState == STATE_QUICK_DOZE_DELAY || mState == STATE_IDLE + || mState == STATE_IDLE_MAINTENANCE) { + // Already "idling". Don't want to restart the process. + // mLightState can't be LIGHT_STATE_ACTIVE if mState is any of these 3 + // values, so returning here is safe. + return; } - } - if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) { - mLightState = LIGHT_STATE_INACTIVE; - if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE"); - resetLightIdleManagementLocked(); - scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT); - EventLogTags.writeDeviceIdleLight(mLightState, "no activity"); + if (DEBUG) { + Slog.d(TAG, "Moved from " + + stateToString(mState) + " to STATE_QUICK_DOZE_DELAY"); + } + mState = STATE_QUICK_DOZE_DELAY; + // Make sure any motion sensing or locating is stopped. + resetIdleManagementLocked(); + // Wait a small amount of time in case something (eg: background service from + // recently closed app) needs to finish running. + scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false); + EventLogTags.writeDeviceIdle(mState, "no activity"); + } else if (mState == STATE_ACTIVE) { + mState = STATE_INACTIVE; + if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE"); + resetIdleManagementLocked(); + long delay = mInactiveTimeout; + if (shouldUseIdleTimeoutFactorLocked()) { + delay = (long) (mPreIdleFactor * delay); + } + scheduleAlarmLocked(delay, false); + EventLogTags.writeDeviceIdle(mState, "no activity"); } } + if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) { + mLightState = LIGHT_STATE_INACTIVE; + if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE"); + resetLightIdleManagementLocked(); + scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT); + EventLogTags.writeDeviceIdleLight(mLightState, "no activity"); + } } private void resetIdleManagementLocked() { @@ -3216,33 +3274,10 @@ public class DeviceIdleController extends SystemService // The device is not yet active, so we want to go back to the pending idle // state to wait again for no motion. Note that we only monitor for motion // after moving out of the inactive state, so no need to worry about that. - boolean becomeInactive = false; - if (mState != STATE_ACTIVE) { - // Motion shouldn't affect light state, if it's already in doze-light or maintenance - boolean lightIdle = mLightState == LIGHT_STATE_IDLE - || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK - || mLightState == LIGHT_STATE_IDLE_MAINTENANCE; - if (!lightIdle) { - // Only switch to active state if we're not in either idle state - scheduleReportActiveLocked(type, Process.myUid()); - addEvent(EVENT_NORMAL, type); - } - mActiveReason = ACTIVE_REASON_MOTION; - mState = STATE_ACTIVE; - mInactiveTimeout = timeout; - mCurIdleBudget = 0; - mMaintenanceStartTime = 0; - EventLogTags.writeDeviceIdle(mState, type); - becomeInactive = true; - updateActiveConstraintsLocked(); - } - if (mLightState == LIGHT_STATE_OVERRIDE) { - // We went out of light idle mode because we had started deep idle mode... let's - // now go back and reset things so we resume light idling if appropriate. - mLightState = LIGHT_STATE_ACTIVE; - EventLogTags.writeDeviceIdleLight(mLightState, type); - becomeInactive = true; - } + final boolean becomeInactive = mState != STATE_ACTIVE + || mLightState == LIGHT_STATE_OVERRIDE; + // We only want to change the IDLE state if it's OVERRIDE. + becomeActiveLocked(type, Process.myUid(), timeout, mLightState == LIGHT_STATE_OVERRIDE); if (becomeInactive) { becomeInactiveIfAppropriateLocked(); } diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java index 9184128d466f..c334540f48cc 100644 --- a/services/core/java/com/android/server/LooperStatsService.java +++ b/services/core/java/com/android/server/LooperStatsService.java @@ -51,16 +51,19 @@ public class LooperStatsService extends Binder { private static final String LOOPER_STATS_SERVICE_NAME = "looper_stats"; private static final String SETTINGS_ENABLED_KEY = "enabled"; private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; + private static final String SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY = "track_screen_state"; private static final String DEBUG_SYS_LOOPER_STATS_ENABLED = "debug.sys.looper_stats_enabled"; private static final int DEFAULT_SAMPLING_INTERVAL = 100; private static final int DEFAULT_ENTRIES_SIZE_CAP = 2000; private static final boolean DEFAULT_ENABLED = true; + private static final boolean DEFAULT_TRACK_SCREEN_INTERACTIVE = false; private final Context mContext; private final LooperStats mStats; // Default should be false so that the first call to #setEnabled installed the looper observer. private boolean mEnabled = false; + private boolean mTrackScreenInteractive = false; private LooperStatsService(Context context, LooperStats stats) { this.mContext = context; @@ -79,6 +82,9 @@ public class LooperStatsService extends Binder { setSamplingInterval( parser.getInt(SETTINGS_SAMPLING_INTERVAL_KEY, DEFAULT_SAMPLING_INTERVAL)); + setTrackScreenInteractive( + parser.getBoolean(SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY, + DEFAULT_TRACK_SCREEN_INTERACTIVE)); // Manually specified value takes precedence over Settings. setEnabled(SystemProperties.getBoolean( DEBUG_SYS_LOOPER_STATS_ENABLED, @@ -155,6 +161,13 @@ public class LooperStatsService extends Binder { } } + private void setTrackScreenInteractive(boolean enabled) { + if (mTrackScreenInteractive != enabled) { + mTrackScreenInteractive = enabled; + mStats.reset(); + } + } + private void setSamplingInterval(int samplingInterval) { if (samplingInterval > 0) { mStats.setSamplingInterval(samplingInterval); diff --git a/services/core/java/com/android/server/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/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index a14fd17209e8..19bdc0969e6d 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -96,6 +96,7 @@ import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; +import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; @@ -180,6 +181,7 @@ public class Tethering extends BaseNetworkObserver { // into a single coherent structure. private final HashSet<IpServer> mForwardedDownstreams; private final VersionedBroadcastListener mCarrierConfigChange; + private final VersionedBroadcastListener mDefaultSubscriptionChange; private final TetheringDependencies mDeps; private final EntitlementManager mEntitlementMgr; @@ -232,6 +234,15 @@ public class Tethering extends BaseNetworkObserver { mEntitlementMgr.reevaluateSimCardProvisioning(); }); + filter = new IntentFilter(); + filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); + mDefaultSubscriptionChange = new VersionedBroadcastListener( + "DefaultSubscriptionChangeListener", mContext, smHandler, filter, + (Intent ignored) -> { + mLog.log("OBSERVED default data subscription change"); + updateConfiguration(); + mEntitlementMgr.reevaluateSimCardProvisioning(); + }); mStateReceiver = new StateReceiver(); // Load tethering configuration. @@ -242,6 +253,7 @@ public class Tethering extends BaseNetworkObserver { private void startStateMachineUpdaters() { mCarrierConfigChange.startListening(); + mDefaultSubscriptionChange.startListening(); final Handler handler = mTetherMasterSM.getHandler(); IntentFilter filter = new IntentFilter(); @@ -270,7 +282,8 @@ public class Tethering extends BaseNetworkObserver { // NOTE: This is always invoked on the mLooper thread. private void updateConfiguration() { - mConfig = new TetheringConfiguration(mContext, mLog); + final int subId = mDeps.getDefaultDataSubscriptionId(); + mConfig = new TetheringConfiguration(mContext, mLog, subId); mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired); mEntitlementMgr.updateConfiguration(mConfig); } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java index 1e6bb04858a1..8a46ff18979f 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java @@ -26,8 +26,8 @@ import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; import static com.android.internal.R.array.config_mobile_hotspot_provision_app; import static com.android.internal.R.array.config_tether_bluetooth_regexs; import static com.android.internal.R.array.config_tether_dhcp_range; -import static com.android.internal.R.array.config_tether_usb_regexs; import static com.android.internal.R.array.config_tether_upstream_types; +import static com.android.internal.R.array.config_tether_usb_regexs; import static com.android.internal.R.array.config_tether_wifi_regexs; import static com.android.internal.R.bool.config_tether_upstream_automatic; import static com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui; @@ -38,6 +38,7 @@ import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.util.SharedLog; import android.provider.Settings; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -100,29 +101,34 @@ public class TetheringConfiguration { public final String[] provisioningApp; public final String provisioningAppNoUi; - public TetheringConfiguration(Context ctx, SharedLog log) { + public final int subId; + + public TetheringConfiguration(Context ctx, SharedLog log, int id) { final SharedLog configLog = log.forSubComponent("config"); - tetherableUsbRegexs = getResourceStringArray(ctx, config_tether_usb_regexs); + subId = id; + Resources res = getResources(ctx, subId); + + tetherableUsbRegexs = getResourceStringArray(res, config_tether_usb_regexs); // TODO: Evaluate deleting this altogether now that Wi-Fi always passes // us an interface name. Careful consideration needs to be given to // implications for Settings and for provisioning checks. - tetherableWifiRegexs = getResourceStringArray(ctx, config_tether_wifi_regexs); - tetherableBluetoothRegexs = getResourceStringArray(ctx, config_tether_bluetooth_regexs); + tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs); + tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs); dunCheck = checkDunRequired(ctx); configLog.log("DUN check returned: " + dunCheckString(dunCheck)); - chooseUpstreamAutomatically = getResourceBoolean(ctx, config_tether_upstream_automatic); - preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck); + chooseUpstreamAutomatically = getResourceBoolean(res, config_tether_upstream_automatic); + preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, dunCheck); isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN); - legacyDhcpRanges = getLegacyDhcpRanges(ctx); + legacyDhcpRanges = getLegacyDhcpRanges(res); defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); enableLegacyDhcpServer = getEnableLegacyDhcpServer(ctx); - provisioningApp = getResourceStringArray(ctx, config_mobile_hotspot_provision_app); - provisioningAppNoUi = getProvisioningAppNoUi(ctx); + provisioningApp = getResourceStringArray(res, config_mobile_hotspot_provision_app); + provisioningAppNoUi = getProvisioningAppNoUi(res); configLog.log(toString()); } @@ -144,6 +150,9 @@ public class TetheringConfiguration { } public void dump(PrintWriter pw) { + pw.print("subId: "); + pw.println(subId); + dumpStringArray(pw, "tetherableUsbRegexs", tetherableUsbRegexs); dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs); dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs); @@ -169,6 +178,7 @@ public class TetheringConfiguration { public String toString() { final StringJoiner sj = new StringJoiner(" "); + sj.add(String.format("subId:%d", subId)); sj.add(String.format("tetherableUsbRegexs:%s", makeString(tetherableUsbRegexs))); sj.add(String.format("tetherableWifiRegexs:%s", makeString(tetherableWifiRegexs))); sj.add(String.format("tetherableBluetoothRegexs:%s", @@ -235,8 +245,8 @@ public class TetheringConfiguration { } } - private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, int dunCheck) { - final int ifaceTypes[] = ctx.getResources().getIntArray(config_tether_upstream_types); + private static Collection<Integer> getUpstreamIfaceTypes(Resources res, int dunCheck) { + final int[] ifaceTypes = res.getIntArray(config_tether_upstream_types); final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); for (int i : ifaceTypes) { switch (i) { @@ -286,33 +296,33 @@ public class TetheringConfiguration { return false; } - private static String[] getLegacyDhcpRanges(Context ctx) { - final String[] fromResource = getResourceStringArray(ctx, config_tether_dhcp_range); + private static String[] getLegacyDhcpRanges(Resources res) { + final String[] fromResource = getResourceStringArray(res, config_tether_dhcp_range); if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) { return fromResource; } return copy(LEGACY_DHCP_DEFAULT_RANGE); } - private static String getProvisioningAppNoUi(Context ctx) { + private static String getProvisioningAppNoUi(Resources res) { try { - return ctx.getResources().getString(config_mobile_hotspot_provision_app_no_ui); + return res.getString(config_mobile_hotspot_provision_app_no_ui); } catch (Resources.NotFoundException e) { return ""; } } - private static boolean getResourceBoolean(Context ctx, int resId) { + private static boolean getResourceBoolean(Resources res, int resId) { try { - return ctx.getResources().getBoolean(resId); + return res.getBoolean(resId); } catch (Resources.NotFoundException e404) { return false; } } - private static String[] getResourceStringArray(Context ctx, int resId) { + private static String[] getResourceStringArray(Resources res, int resId) { try { - final String[] strArray = ctx.getResources().getStringArray(resId); + final String[] strArray = res.getStringArray(resId); return (strArray != null) ? strArray : EMPTY_STRING_ARRAY; } catch (Resources.NotFoundException e404) { return EMPTY_STRING_ARRAY; @@ -325,6 +335,19 @@ public class TetheringConfiguration { return intVal != 0; } + private Resources getResources(Context ctx, int subId) { + if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + return getResourcesForSubIdWrapper(ctx, subId); + } else { + return ctx.getResources(); + } + } + + @VisibleForTesting + protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) { + return SubscriptionManager.getResourcesForSubId(ctx, subId); + } + private static String[] copy(String[] strarray) { return Arrays.copyOf(strarray, strarray.length); } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java index 6d6f81eb98e6..3fddac111ec5 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java @@ -21,6 +21,7 @@ import android.net.NetworkRequest; import android.net.ip.IpServer; import android.net.util.SharedLog; import android.os.Handler; +import android.telephony.SubscriptionManager; import com.android.internal.util.StateMachine; import com.android.server.connectivity.MockableSystemProperties; @@ -85,4 +86,11 @@ public class TetheringDependencies { SharedLog log, MockableSystemProperties systemProperties) { return new EntitlementManager(ctx, target, log, systemProperties); } + + /** + * Get default data subscription id to build TetheringConfiguration. + */ + public int getDefaultDataSubscriptionId() { + return SubscriptionManager.getDefaultDataSubscriptionId(); + } } diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java index 9cb6eeec2126..45f169ca0b6f 100644 --- a/services/core/java/com/android/server/display/ColorDisplayService.java +++ b/services/core/java/com/android/server/display/ColorDisplayService.java @@ -387,8 +387,10 @@ public final class ColorDisplayService extends SystemService { Slog.d(TAG, "Setting saturation level: " + saturationLevel); if (saturationLevel == 100) { + setActivated(false); Matrix.setIdentityM(mMatrixGlobalSaturation, 0); } else { + setActivated(true); float saturation = saturationLevel * 0.1f; float desaturation = 1.0f - saturation; float[] luminance = {0.231f * desaturation, 0.715f * desaturation, @@ -556,14 +558,16 @@ public final class ColorDisplayService extends SystemService { if (setting != null) { switch (setting) { case Secure.NIGHT_DISPLAY_ACTIVATED: - final boolean activated = isNightDisplayActivatedSetting(); + final boolean activated = mNightDisplayTintController + .isActivatedSetting(); if (mNightDisplayTintController.isActivatedStateNotSet() || mNightDisplayTintController.isActivated() != activated) { - mNightDisplayTintController.onActivated(activated); + mNightDisplayTintController.setActivated(activated); } break; case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE: - final int temperature = getNightDisplayColorTemperatureSetting(); + final int temperature = mNightDisplayTintController + .getColorTemperatureSetting(); if (mNightDisplayTintController.getColorTemperature() != temperature) { mNightDisplayTintController @@ -639,14 +643,16 @@ public final class ColorDisplayService extends SystemService { // Prepare the night display color transformation matrix. mNightDisplayTintController .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix()); - mNightDisplayTintController.setMatrix(getNightDisplayColorTemperatureSetting()); + mNightDisplayTintController + .setMatrix(mNightDisplayTintController.getColorTemperatureSetting()); // Initialize the current auto mode. onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal()); // Force the initialization of the current saved activation state. if (mNightDisplayTintController.isActivatedStateNotSet()) { - mNightDisplayTintController.onActivated(isNightDisplayActivatedSetting()); + mNightDisplayTintController + .setActivated(mNightDisplayTintController.isActivatedSetting()); } } @@ -674,6 +680,10 @@ public final class ColorDisplayService extends SystemService { if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) { mDisplayWhiteBalanceTintController.endAnimator(); } + + if (mGlobalSaturationTintController.isAvailable(getContext())) { + mGlobalSaturationTintController.setActivated(null); + } } private void onNightDisplayAutoModeChanged(int autoMode) { @@ -722,7 +732,8 @@ public final class ColorDisplayService extends SystemService { if (mNightDisplayTintController.isAvailable(getContext())) { mNightDisplayTintController .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode)); - mNightDisplayTintController.setMatrix(getNightDisplayColorTemperatureSetting()); + mNightDisplayTintController + .setMatrix(mNightDisplayTintController.getColorTemperatureSetting()); } updateDisplayWhiteBalanceStatus(); @@ -1040,8 +1051,7 @@ public final class ColorDisplayService extends SystemService { * * See {@link com.android.server.display.DisplayTransformManager} */ - private @ColorMode - int getCurrentColorModeFromSystemProperties() { + private @ColorMode int getCurrentColorModeFromSystemProperties() { final int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0); if (displayColorSetting == 0) { return "1.0".equals(SystemProperties.get("persist.sys.sf.color_saturation")) @@ -1098,33 +1108,6 @@ public final class ColorDisplayService extends SystemService { pw.println("Color mode: " + getColorModeInternal()); } - private boolean isNightDisplayActivatedSetting() { - return Secure.getIntForUser(getContext().getContentResolver(), - Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1; - } - - private int getNightDisplayColorTemperatureSetting() { - return clampNightDisplayColorTemperature(Secure.getIntForUser( - getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, NOT_SET, - mCurrentUser)); - } - - private int clampNightDisplayColorTemperature(int colorTemperature) { - if (colorTemperature == NOT_SET) { - colorTemperature = getContext().getResources().getInteger( - R.integer.config_nightDisplayColorTemperatureDefault); - } - final int minimumTemperature = ColorDisplayManager.getMinimumColorTemperature(getContext()); - final int maximumTemperature = ColorDisplayManager.getMaximumColorTemperature(getContext()); - if (colorTemperature < minimumTemperature) { - colorTemperature = minimumTemperature; - } else if (colorTemperature > maximumTemperature) { - colorTemperature = maximumTemperature; - } - - return colorTemperature; - } - private abstract class NightDisplayAutoMode { public abstract void onActivated(boolean activated); @@ -1171,7 +1154,7 @@ public final class ColorDisplayService extends SystemService { // Maintain the existing activated state if within the current period. if (mLastActivatedTime.isBefore(now) && mLastActivatedTime.isAfter(start) && (mLastActivatedTime.isAfter(end) || now.isBefore(end))) { - activate = isNightDisplayActivatedSetting(); + activate = mNightDisplayTintController.isActivatedSetting(); } } @@ -1267,7 +1250,7 @@ public final class ColorDisplayService extends SystemService { // Maintain the existing activated state if within the current period. if (mLastActivatedTime.isBefore(now) && (mLastActivatedTime.isBefore(sunrise) ^ mLastActivatedTime.isBefore(sunset))) { - activate = isNightDisplayActivatedSetting(); + activate = mNightDisplayTintController.isActivatedSetting(); } } @@ -1466,9 +1449,11 @@ public final class ColorDisplayService extends SystemService { if (isActivatedStateNotSet() || activationStateChanged) { super.setActivated(activated); - Secure.putIntForUser(getContext().getContentResolver(), - Secure.NIGHT_DISPLAY_ACTIVATED, - activated ? 1 : 0, mCurrentUser); + if (isActivatedSetting() != activated) { + Secure.putIntForUser(getContext().getContentResolver(), + Secure.NIGHT_DISPLAY_ACTIVATED, + activated ? 1 : 0, mCurrentUser); + } onActivated(activated); } } @@ -1486,7 +1471,7 @@ public final class ColorDisplayService extends SystemService { return mIsAvailable; } - void onActivated(boolean activated) { + private void onActivated(boolean activated) { Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display"); if (mNightDisplayAutoMode != null) { mNightDisplayAutoMode.onActivated(activated); @@ -1501,7 +1486,7 @@ public final class ColorDisplayService extends SystemService { int getColorTemperature() { return mColorTemp != null ? clampNightDisplayColorTemperature(mColorTemp) - : getNightDisplayColorTemperatureSetting(); + : getColorTemperatureSetting(); } boolean setColorTemperature(int temperature) { @@ -1516,6 +1501,36 @@ public final class ColorDisplayService extends SystemService { setMatrix(temperature); mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE); } + + boolean isActivatedSetting() { + return Secure.getIntForUser(getContext().getContentResolver(), + Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1; + } + + int getColorTemperatureSetting() { + return clampNightDisplayColorTemperature(Secure.getIntForUser( + getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, + NOT_SET, + mCurrentUser)); + } + + private int clampNightDisplayColorTemperature(int colorTemperature) { + if (colorTemperature == NOT_SET) { + colorTemperature = getContext().getResources().getInteger( + R.integer.config_nightDisplayColorTemperatureDefault); + } + final int minimumTemperature = ColorDisplayManager + .getMinimumColorTemperature(getContext()); + final int maximumTemperature = ColorDisplayManager + .getMaximumColorTemperature(getContext()); + if (colorTemperature < minimumTemperature) { + colorTemperature = minimumTemperature; + } else if (colorTemperature > maximumTemperature) { + colorTemperature = maximumTemperature; + } + + return colorTemperature; + } } /** @@ -1671,6 +1686,20 @@ public final class ColorDisplayService extends SystemService { } @Override + public boolean isSaturationActivated() { + getContext().enforceCallingPermission( + Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, + "Permission required to get display saturation level"); + final long token = Binder.clearCallingIdentity(); + try { + return !mGlobalSaturationTintController.isActivatedStateNotSet() + && mGlobalSaturationTintController.isActivated(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override public boolean setAppSaturationLevel(String packageName, int level) { getContext().enforceCallingPermission( Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java index cf84e22e7dd1..1b237949a543 100644 --- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java +++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java @@ -187,7 +187,7 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR @Override public boolean isDefaultServiceEnabled(int userId) { synchronized (mLock) { - return mDefaultServicesDisabled.get(userId); + return !mDefaultServicesDisabled.get(userId); } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 144f2b6b143f..96ba0841855c 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -667,13 +667,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final int mSequenceNumber; final long mTimestamp; final long mWallTime; + @UserIdInt + final int mImeUserId; @NonNull final IBinder mImeToken; + final int mImeDisplayId; @NonNull final String mImeId; @StartInputReason final int mStartInputReason; final boolean mRestarting; + @UserIdInt + final int mTargetUserId; + final int mTargetDisplayId; @Nullable final IBinder mTargetWindow; @NonNull @@ -682,17 +688,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final int mTargetWindowSoftInputMode; final int mClientBindSequenceNumber; - StartInputInfo(@NonNull IBinder imeToken, @NonNull String imeId, - @StartInputReason int startInputReason, boolean restarting, - @Nullable IBinder targetWindow, @NonNull EditorInfo editorInfo, - @SoftInputModeFlags int targetWindowSoftInputMode, int clientBindSequenceNumber) { + StartInputInfo(@UserIdInt int imeUserId, @NonNull IBinder imeToken, int imeDisplayId, + @NonNull String imeId, @StartInputReason int startInputReason, boolean restarting, + @UserIdInt int targetUserId, int targetDisplayId, @Nullable IBinder targetWindow, + @NonNull EditorInfo editorInfo, @SoftInputModeFlags int targetWindowSoftInputMode, + int clientBindSequenceNumber) { mSequenceNumber = sSequenceNumber.getAndIncrement(); mTimestamp = SystemClock.uptimeMillis(); mWallTime = System.currentTimeMillis(); + mImeUserId = imeUserId; mImeToken = imeToken; + mImeDisplayId = imeDisplayId; mImeId = imeId; mStartInputReason = startInputReason; mRestarting = restarting; + mTargetUserId = targetUserId; + mTargetDisplayId = targetDisplayId; mTargetWindow = targetWindow; mEditorInfo = editorInfo; mTargetWindowSoftInputMode = targetWindowSoftInputMode; @@ -749,13 +760,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub int mSequenceNumber; long mTimestamp; long mWallTime; + @UserIdInt + int mImeUserId; @NonNull String mImeTokenString; + int mImeDisplayId; @NonNull String mImeId; @StartInputReason int mStartInputReason; boolean mRestarting; + @UserIdInt + int mTargetUserId; + int mTargetDisplayId; @NonNull String mTargetWindowString; @NonNull @@ -772,12 +789,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mSequenceNumber = original.mSequenceNumber; mTimestamp = original.mTimestamp; mWallTime = original.mWallTime; + mImeUserId = original.mImeUserId; // Intentionally convert to String so as not to keep a strong reference to a Binder // object. mImeTokenString = String.valueOf(original.mImeToken); + mImeDisplayId = original.mImeDisplayId; mImeId = original.mImeId; mStartInputReason = original.mStartInputReason; mRestarting = original.mRestarting; + mTargetUserId = original.mTargetUserId; + mTargetDisplayId = original.mTargetDisplayId; // Intentionally convert to String so as not to keep a strong reference to a Binder // object. mTargetWindowString = String.valueOf(original.mTargetWindow); @@ -821,11 +842,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + " restarting=" + entry.mRestarting); pw.print(prefix); - pw.println(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]"); + pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]"); + pw.print(" imeUserId=" + entry.mImeUserId); + pw.println(" imeDisplayId=" + entry.mImeDisplayId); pw.print(prefix); pw.println(" targetWin=" + entry.mTargetWindowString + " [" + entry.mEditorInfo.packageName + "]" + + " targetUserId=" + entry.mTargetUserId + + " targetDisplayId=" + entry.mTargetDisplayId + " clientBindSeq=" + entry.mClientBindSequenceNumber); pw.print(prefix); @@ -1904,9 +1929,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } final Binder startInputToken = new Binder(); - final StartInputInfo info = new StartInputInfo(mCurToken, mCurId, startInputReason, - !initial, mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, - mCurSeq); + final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), mCurToken, + mCurTokenDisplayId, mCurId, startInputReason, !initial, + UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId, + mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, mCurSeq); mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow); mStartInputHistory.addEntry(info); diff --git a/services/core/java/com/android/server/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/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index bfa539c9007e..2036ed73fdf2 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -645,7 +645,7 @@ public final class DefaultPermissionGrantPolicy { grantPermissionsToSystemPackage(packageName, userId, CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS, PHONE_PERMISSIONS, SMS_PERMISSIONS, CAMERA_PERMISSIONS, - SENSORS_PERMISSIONS, STORAGE_PERMISSIONS); + SENSORS_PERMISSIONS, STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS); grantSystemFixedPermissionsToSystemPackage(packageName, userId, LOCATION_PERMISSIONS, ACTIVITY_RECOGNITION_PERMISSIONS); } diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index cc78588eeb84..932cfd3ae007 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -5631,6 +5631,19 @@ class ActivityStack extends ConfigurationContainer { } } + /** + * Get current bounds of this stack, return empty when it is unavailable. + * @see TaskStack#getAnimationOrCurrentBounds(Rect) + */ + void getAnimationOrCurrentBounds(Rect outBounds) { + final TaskStack stack = getTaskStack(); + if (stack == null) { + outBounds.setEmpty(); + return; + } + stack.getAnimationOrCurrentBounds(outBounds); + } + private boolean skipResizeAnimation(boolean toFullscreen) { if (!toFullscreen) { return false; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 875fc4eab273..7e9979da80f7 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -2452,6 +2452,40 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } + @Override + public void offsetPinnedStackBounds(int stackId, Rect compareBounds, int xOffset, int yOffset, + int animationDuration) { + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "offsetPinnedStackBounds()"); + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + if (xOffset == 0 && yOffset == 0) { + return; + } + final ActivityStack stack = mRootActivityContainer.getStack(stackId); + if (stack == null) { + Slog.w(TAG, "offsetPinnedStackBounds: stackId " + stackId + " not found."); + return; + } + if (stack.getWindowingMode() != WINDOWING_MODE_PINNED) { + throw new IllegalArgumentException("Stack: " + stackId + + " doesn't support animated resize."); + } + final Rect destBounds = new Rect(); + stack.getAnimationOrCurrentBounds(destBounds); + if (!destBounds.isEmpty() || !destBounds.equals(compareBounds)) { + Slog.w(TAG, "The current stack bounds does not matched! It may be obsolete."); + return; + } + destBounds.offset(xOffset, yOffset); + stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds, + animationDuration, false /* fromFullscreen */); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } /** * Moves the specified task to the primary-split-screen stack. * diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 9a8943c0b5e4..0e8b2bdb0777 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -1665,8 +1665,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree final ActivityManager.TaskSnapshot snapshot = snapshotCtrl.getSnapshot( getTask().mTaskId, getTask().mUserId, false /* restoreFromDisk */, false /* reducedResolution */); - mThumbnail = new AppWindowThumbnail(t, this, snapshot.getSnapshot(), - true /* relative */); + if (snapshot != null) { + mThumbnail = new AppWindowThumbnail(t, this, snapshot.getSnapshot(), + true /* relative */); + } } } diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 5ea24518370b..35b8641371be 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -251,7 +251,7 @@ class SurfaceAnimator { if (DEBUG_ANIM) Slog.i(TAG, "Cancelling animation restarting=" + restarting); final SurfaceControl leash = mLeash; final AnimationAdapter animation = mAnimation; - reset(t, forwardCancel); + reset(t, false); if (animation != null) { if (!mAnimationStartDelayed && forwardCancel) { animation.onAnimationCancelled(leash); @@ -260,6 +260,12 @@ class SurfaceAnimator { mAnimationFinishedCallback.run(); } } + + if (forwardCancel && leash != null) { + t.remove(leash); + mService.scheduleAnimationLocked(); + } + if (!restarting) { mAnimationStartDelayed = false; } diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index 69f0012b69ba..4aca9c8a1520 100644 --- a/services/core/java/com/android/server/wm/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -119,6 +119,7 @@ import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Slog; import android.util.proto.ProtoOutputStream; +import android.view.Display; import android.view.DisplayInfo; import com.android.internal.annotations.VisibleForTesting; @@ -2332,6 +2333,7 @@ class TaskRecord extends ConfigurationContainer { info.userId = userId; info.stackId = getStackId(); info.taskId = taskId; + info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId; info.isRunning = getTopActivity() != null; info.baseIntent = new Intent(getBaseIntent()); info.baseActivity = reuseActivitiesReport.base != null diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 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/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java index 4354db72554a..24e5573b891d 100644 --- a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java +++ b/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,7 +11,7 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ package com.android.server.backup.encryption.chunk; @@ -36,7 +36,7 @@ import java.util.Arrays; @RunWith(RobolectricTestRunner.class) @Presubmit -public class ChunkListingTest { +public class ChunkListingMapTest { private static final String CHUNK_A = "CHUNK_A"; private static final String CHUNK_B = "CHUNK_B"; private static final String CHUNK_C = "CHUNK_C"; @@ -62,13 +62,13 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - boolean chunkAInList = chunkListing.hasChunk(mChunkHashA); - boolean chunkBInList = chunkListing.hasChunk(mChunkHashB); - boolean chunkCInList = chunkListing.hasChunk(mChunkHashC); + boolean chunkAInList = chunkListingMap.hasChunk(mChunkHashA); + boolean chunkBInList = chunkListingMap.hasChunk(mChunkHashB); + boolean chunkCInList = chunkListingMap.hasChunk(mChunkHashC); assertThat(chunkAInList).isTrue(); assertThat(chunkBInList).isTrue(); @@ -81,13 +81,13 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); ChunkHash chunkHashEmpty = getHash(""); - boolean chunkCInList = chunkListing.hasChunk(mChunkHashC); - boolean emptyChunkInList = chunkListing.hasChunk(chunkHashEmpty); + boolean chunkCInList = chunkListingMap.hasChunk(mChunkHashC); + boolean emptyChunkInList = chunkListingMap.hasChunk(chunkHashEmpty); assertThat(chunkCInList).isFalse(); assertThat(emptyChunkInList).isFalse(); @@ -99,13 +99,13 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA); - ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB); - ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC); + ChunkListingMap.Entry entryA = chunkListingMap.getChunkEntry(mChunkHashA); + ChunkListingMap.Entry entryB = chunkListingMap.getChunkEntry(mChunkHashB); + ChunkListingMap.Entry entryC = chunkListingMap.getChunkEntry(mChunkHashC); assertThat(entryA.getLength()).isEqualTo(CHUNK_A_LENGTH); assertThat(entryB.getLength()).isEqualTo(CHUNK_B_LENGTH); @@ -118,13 +118,13 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA); - ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB); - ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC); + ChunkListingMap.Entry entryA = chunkListingMap.getChunkEntry(mChunkHashA); + ChunkListingMap.Entry entryB = chunkListingMap.getChunkEntry(mChunkHashB); + ChunkListingMap.Entry entryC = chunkListingMap.getChunkEntry(mChunkHashC); assertThat(entryA.getStart()).isEqualTo(0); assertThat(entryB.getStart()).isEqualTo(CHUNK_A_LENGTH); @@ -137,22 +137,24 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - ChunkListing.Entry chunkEntryNonexistentChunk = chunkListing.getChunkEntry(mChunkHashC); + ChunkListingMap.Entry chunkEntryNonexistentChunk = + chunkListingMap.getChunkEntry(mChunkHashC); assertThat(chunkEntryNonexistentChunk).isNull(); } @Test - public void testReadFromProto_whenEmptyProto_returnsChunkListingWith0Chunks() throws Exception { + public void testReadFromProto_whenEmptyProto_returnsChunkListingMapWith0Chunks() + throws Exception { ProtoInputStream emptyProto = new ProtoInputStream(new ByteArrayInputStream(new byte[] {})); - ChunkListing chunkListing = ChunkListing.readFromProto(emptyProto); + ChunkListingMap chunkListingMap = ChunkListingMap.readFromProto(emptyProto); - assertThat(chunkListing.getChunkCount()).isEqualTo(0); + assertThat(chunkListingMap.getChunkCount()).isEqualTo(0); } @Test @@ -162,11 +164,11 @@ public class ChunkListingTest { new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - assertThat(chunkListing.getChunkCount()).isEqualTo(3); + assertThat(chunkListingMap.getChunkCount()).isEqualTo(3); } private byte[] createChunkListingProto(ChunkHash[] hashes, int[] lengths) { diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java index 53d72bb9a415..e51ee947cba1 100644 --- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java @@ -19,6 +19,7 @@ import static androidx.test.InstrumentationRegistry.getContext; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -51,6 +52,9 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; import android.app.ActivityManagerInternal; import android.app.AlarmManager; @@ -82,6 +86,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; @@ -105,6 +110,8 @@ public class DeviceIdleControllerTest { @Mock private ContentResolver mContentResolver; @Mock + private DeviceIdleController.MyHandler mHandler; + @Mock private IActivityManager mIActivityManager; @Mock private LocationManager mLocationManager; @@ -154,7 +161,7 @@ public class DeviceIdleControllerTest { @Override DeviceIdleController.MyHandler getHandler(DeviceIdleController controller) { - return mock(DeviceIdleController.MyHandler.class, Answers.RETURNS_DEEP_STUBS); + return mHandler; } @Override @@ -232,10 +239,12 @@ public class DeviceIdleControllerTest { .when(() -> LocalServices.getService(ActivityManagerInternal.class)); doReturn(mock(ActivityTaskManagerInternal.class)) .when(() -> LocalServices.getService(ActivityTaskManagerInternal.class)); + doReturn(mock(AlarmManagerInternal.class)) + .when(() -> LocalServices.getService(AlarmManagerInternal.class)); doReturn(mPowerManagerInternal) .when(() -> LocalServices.getService(PowerManagerInternal.class)); - when(mPowerManagerInternal.getLowPowerState(anyInt())).thenReturn( - mock(PowerSaveState.class)); + when(mPowerManagerInternal.getLowPowerState(anyInt())) + .thenReturn(mock(PowerSaveState.class)); doReturn(mock(NetworkPolicyManagerInternal.class)) .when(() -> LocalServices.getService(NetworkPolicyManagerInternal.class)); when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock); @@ -246,8 +255,11 @@ public class DeviceIdleControllerTest { doReturn(true).when(mSensorManager).registerListener(any(), any(), anyInt()); mAppStateTracker = new AppStateTrackerForTest(getContext(), Looper.getMainLooper()); mAnyMotionDetector = new AnyMotionDetectorForTest(); + mHandler = mock(DeviceIdleController.MyHandler.class, Answers.RETURNS_DEEP_STUBS); + doNothing().when(mHandler).handleMessage(any()); mInjector = new InjectorForTest(getContext()); doNothing().when(mContentResolver).registerContentObserver(any(), anyBoolean(), any()); + mDeviceIdleController = new DeviceIdleController(getContext(), mInjector); spyOn(mDeviceIdleController); doNothing().when(mDeviceIdleController).publishBinderService(any(), any()); @@ -423,6 +435,29 @@ public class DeviceIdleControllerTest { mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyStateConditions(STATE_ACTIVE); + + mConstants.WAIT_FOR_UNLOCK = false; + setScreenLocked(true); + setScreenOn(true); + setChargingOn(false); + + mDeviceIdleController.becomeInactiveIfAppropriateLocked(); + verifyStateConditions(STATE_ACTIVE); + + setScreenLocked(false); + setScreenOn(true); + setChargingOn(false); + + mDeviceIdleController.becomeInactiveIfAppropriateLocked(); + verifyStateConditions(STATE_ACTIVE); + + mConstants.WAIT_FOR_UNLOCK = true; + setScreenLocked(false); + setScreenOn(true); + setChargingOn(false); + + mDeviceIdleController.becomeInactiveIfAppropriateLocked(); + verifyStateConditions(STATE_ACTIVE); } @Test @@ -1307,7 +1342,7 @@ public class DeviceIdleControllerTest { } @Test - public void testbecomeActiveLocked_deep() { + public void testBecomeActiveLocked_deep() { // becomeActiveLocked should put everything into ACTIVE. enterDeepState(STATE_ACTIVE); @@ -1344,7 +1379,7 @@ public class DeviceIdleControllerTest { } @Test - public void testbecomeActiveLocked_light() { + public void testBecomeActiveLocked_light() { // becomeActiveLocked should put everything into ACTIVE. enterLightState(LIGHT_STATE_ACTIVE); @@ -1376,6 +1411,163 @@ public class DeviceIdleControllerTest { verifyLightStateConditions(LIGHT_STATE_ACTIVE); } + /** Test based on b/119058625. */ + @Test + public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOn_ScreenThenMotion() { + mConstants.WAIT_FOR_UNLOCK = true; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + mDeviceIdleController.keyguardShowingLocked(true); + setScreenOn(true); + // With WAIT_FOR_UNLOCK = true and the screen locked, turning the screen on by itself + // shouldn't bring the device out of deep IDLE. + verifyStateConditions(STATE_IDLE); + mDeviceIdleController.handleMotionDetectedLocked(1000, "test"); + // Motion should bring the device out of Doze. Since the screen is still locked (albeit + // on), the states should go back into INACTIVE. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt()); + } + + /** Test based on b/119058625. */ + @Test + public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOff_ScreenThenMotion() { + mConstants.WAIT_FOR_UNLOCK = true; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + mDeviceIdleController.keyguardShowingLocked(false); + setScreenOn(true); + // With WAIT_FOR_UNLOCK = true and the screen unlocked, turning the screen on by itself + // should bring the device out of deep IDLE. + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt()); + } + + /** Test based on b/119058625. */ + @Test + public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOn_MotionThenScreen() { + mConstants.WAIT_FOR_UNLOCK = true; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + InOrder alarmManagerInOrder = inOrder(mAlarmManager); + InOrder controllerInOrder = inOrder(mDeviceIdleController); + + mDeviceIdleController.keyguardShowingLocked(true); + mDeviceIdleController.handleMotionDetectedLocked(1000, "test"); + // The screen is still off, so motion should result in the INACTIVE state. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + + setScreenOn(true); + // With WAIT_FOR_UNLOCK = true and the screen locked, turning the screen on by itself + // shouldn't bring the device all the way to ACTIVE. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + alarmManagerInOrder.verify(mAlarmManager, never()).cancel( + eq(mDeviceIdleController.mDeepAlarmListener)); + + // User finally unlocks the device. Device should be fully active. + mDeviceIdleController.keyguardShowingLocked(false); + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + } + + /** Test based on b/119058625. */ + @Test + public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOff_MotionThenScreen() { + mConstants.WAIT_FOR_UNLOCK = true; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + InOrder alarmManagerInOrder = inOrder(mAlarmManager); + InOrder controllerInOrder = inOrder(mDeviceIdleController); + + mDeviceIdleController.keyguardShowingLocked(false); + mDeviceIdleController.handleMotionDetectedLocked(1000, "test"); + // The screen is still off, so motion should result in the INACTIVE state. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + + setScreenOn(true); + // With WAIT_FOR_UNLOCK = true and the screen unlocked, turning the screen on by itself + // should bring the device out of deep IDLE. + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + } + + @Test + public void testExitNotifiesDependencies_WaitForUnlockOff_Screen() { + mConstants.WAIT_FOR_UNLOCK = false; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + setScreenOn(true); + // With WAIT_FOR_UNLOCK = false and the screen locked, turning the screen on by itself + // should bring the device out of deep IDLE. + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt()); + } + + @Test + public void testExitNotifiesDependencies_WaitForUnlockOff_MotionThenScreen() { + mConstants.WAIT_FOR_UNLOCK = false; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + InOrder alarmManagerInOrder = inOrder(mAlarmManager); + InOrder controllerInOrder = inOrder(mDeviceIdleController); + + mDeviceIdleController.handleMotionDetectedLocked(1000, "test"); + // The screen is still off, so motion should result in the INACTIVE state. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + + setScreenOn(true); + // With WAIT_FOR_UNLOCK = false and the screen locked, turning the screen on by itself + // should bring the device out of deep IDLE. + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + } + @Test public void testStepToIdleMode() { float delta = mDeviceIdleController.MIN_PRE_IDLE_FACTOR_CHANGE; @@ -1508,6 +1700,10 @@ public class DeviceIdleControllerTest { mDeviceIdleController.updateChargingLocked(on); } + private void setScreenLocked(boolean locked) { + mDeviceIdleController.keyguardShowingLocked(locked); + } + private void setScreenOn(boolean on) { doReturn(on).when(mPowerManager).isInteractive(); mDeviceIdleController.updateInteractivityLocked(); @@ -1549,7 +1745,8 @@ public class DeviceIdleControllerTest { assertFalse(mDeviceIdleController.mMotionListener.isActive()); assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_IDLE_PENDING: assertEquals( @@ -1557,7 +1754,8 @@ public class DeviceIdleControllerTest { mDeviceIdleController.mMotionListener.isActive()); assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_SENSING: assertEquals( @@ -1567,14 +1765,16 @@ public class DeviceIdleControllerTest { mDeviceIdleController.hasMotionSensor(), mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_LOCATING: assertEquals( mDeviceIdleController.hasMotionSensor(), mDeviceIdleController.mMotionListener.isActive()); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_IDLE: if (mDeviceIdleController.hasMotionSensor()) { @@ -1584,7 +1784,8 @@ public class DeviceIdleControllerTest { } assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); // Light state should be OVERRIDE at this point. verifyLightStateConditions(LIGHT_STATE_OVERRIDE); break; @@ -1596,14 +1797,16 @@ public class DeviceIdleControllerTest { } assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_QUICK_DOZE_DELAY: // If quick doze is enabled, the motion listener should NOT be active. assertFalse(mDeviceIdleController.mMotionListener.isActive()); assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; default: fail("Conditions for " + stateToString(expectedState) + " unknown."); @@ -1632,7 +1835,8 @@ public class DeviceIdleControllerTest { case LIGHT_STATE_IDLE_MAINTENANCE: case LIGHT_STATE_OVERRIDE: assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; default: fail("Conditions for " + lightStateToString(expectedLightState) + " unknown."); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java index 13436e7f8674..821d97acc230 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java @@ -24,14 +24,21 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.testng.Assert.expectThrows; import android.app.KeyguardManager; import android.content.Context; +import android.os.RemoteException; +import android.security.GateKeeper; +import android.security.keystore.AndroidKeyStoreSecretKey; +import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; +import android.service.gatekeeper.IGateKeeperService; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -53,6 +60,8 @@ import java.security.KeyStore; import java.security.UnrecoverableKeyException; import java.util.List; +import javax.crypto.KeyGenerator; + @SmallTest @RunWith(AndroidJUnit4.class) public class PlatformKeyManagerTest { @@ -60,10 +69,15 @@ public class PlatformKeyManagerTest { private static final String DATABASE_FILE_NAME = "recoverablekeystore.db"; private static final int USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS = 15; private static final int USER_ID_FIXTURE = 42; + private static final long USER_SID = 4200L; + private static final String KEY_ALGORITHM = "AES"; + private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore"; + private static final String TESTING_KEYSTORE_KEY_ALIAS = "testing-key-store-key-alias"; @Mock private Context mContext; @Mock private KeyStoreProxy mKeyStoreProxy; @Mock private KeyguardManager mKeyguardManager; + @Mock private IGateKeeperService mGateKeeperService; @Captor private ArgumentCaptor<KeyStore.ProtectionParameter> mProtectionParameterCaptor; @Captor private ArgumentCaptor<KeyStore.Entry> mEntryArgumentCaptor; @@ -74,18 +88,19 @@ public class PlatformKeyManagerTest { private PlatformKeyManager mPlatformKeyManager; @Before - public void setUp() { + public void setUp() throws Exception { MockitoAnnotations.initMocks(this); Context context = InstrumentationRegistry.getTargetContext(); mDatabaseFile = context.getDatabasePath(DATABASE_FILE_NAME); mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context); - mPlatformKeyManager = new PlatformKeyManager( - mContext, mKeyStoreProxy, mRecoverableKeyStoreDb); + mPlatformKeyManager = new PlatformKeyManagerTestable( + mContext, mKeyStoreProxy, mRecoverableKeyStoreDb, mGateKeeperService); when(mContext.getSystemService(anyString())).thenReturn(mKeyguardManager); when(mContext.getSystemServiceName(any())).thenReturn("test"); when(mKeyguardManager.isDeviceSecure(USER_ID_FIXTURE)).thenReturn(true); + when(mGateKeeperService.getSecureUserId(USER_ID_FIXTURE)).thenReturn(USER_SID); } @After @@ -192,11 +207,36 @@ public class PlatformKeyManagerTest { mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals( - USER_ID_FIXTURE, + USER_SID, getDecryptKeyProtection().getBoundToSpecificSecureUserId()); } @Test + public void init_doesNotCreateDecryptKeyIfNoSid() throws Exception { + when(mGateKeeperService.getSecureUserId(USER_ID_FIXTURE)) + .thenReturn(GateKeeper.INVALID_SECURE_USER_ID); + + mPlatformKeyManager.init(USER_ID_FIXTURE); + + verify(mKeyStoreProxy, never()).setEntry( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), + any(), + any()); + } + + @Test + public void init_doesNotCreateDecryptKeyOnGateKeeperException() throws Exception { + when(mGateKeeperService.getSecureUserId(USER_ID_FIXTURE)).thenThrow(new RemoteException()); + + expectThrows(RemoteException.class, () -> mPlatformKeyManager.init(USER_ID_FIXTURE)); + + verify(mKeyStoreProxy, never()).setEntry( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), + any(), + any()); + } + + @Test public void init_createsBothKeysWithSameMaterial() throws Exception { mPlatformKeyManager.init(USER_ID_FIXTURE); @@ -259,6 +299,9 @@ public class PlatformKeyManagerTest { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); + when(mKeyStoreProxy.getKey( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), + any())).thenReturn(generateAndroidKeyStoreKey()); mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); @@ -281,6 +324,9 @@ public class PlatformKeyManagerTest { when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/2/decrypt")).thenReturn(true); + when(mKeyStoreProxy.getKey( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"), + any())).thenReturn(generateAndroidKeyStoreKey()); mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); @@ -352,6 +398,9 @@ public class PlatformKeyManagerTest { doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), any()); + when(mKeyStoreProxy.getKey( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"), + any())).thenReturn(generateAndroidKeyStoreKey()); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" @@ -536,4 +585,34 @@ public class PlatformKeyManagerTest { mProtectionParameterCaptor.capture()); return (KeyProtection) mProtectionParameterCaptor.getValue(); } + + private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception { + KeyGenerator keyGenerator = KeyGenerator.getInstance( + KEY_ALGORITHM, + ANDROID_KEY_STORE_PROVIDER); + keyGenerator.init(new KeyGenParameterSpec.Builder(TESTING_KEYSTORE_KEY_ALIAS, + KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) + .setBlockModes(KeyProperties.BLOCK_MODE_GCM) + .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) + .build()); + return (AndroidKeyStoreSecretKey) keyGenerator.generateKey(); + } + + class PlatformKeyManagerTestable extends PlatformKeyManager { + private IGateKeeperService mGateKeeperService; + + PlatformKeyManagerTestable( + Context context, + KeyStoreProxy keyStoreProxy, + RecoverableKeyStoreDb database, + IGateKeeperService gateKeeperService) { + super(context, keyStoreProxy, database); + mGateKeeperService = gateKeeperService; + } + + @Override + IGateKeeperService getGateKeeperService() { + return mGateKeeperService; + } + } } diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java index 4e43d002d4ae..8caa39dfc9e7 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java @@ -1035,6 +1035,15 @@ public class AppTimeLimitControllerTests { 0L, group.getUsageRemaining()); } + /** Verify that a limit of 0 is allowed for the special case of re-registering an observer. */ + @Test + public void testAppUsageLimitObserver_ZeroTimeLimitIsAllowed() { + addAppUsageLimitObserver(OBS_ID1, GROUP1, 0); + AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1); + assertNotNull("Observer wasn't added", group); + assertEquals("Usage remaining was not 0.", 0, group.getUsageRemaining()); + } + private void startUsage(String packageName) { mController.noteUsageStart(packageName, USER_ID); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index 2de4ae02828c..23bae8881aa1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions; + import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.anyInt; @@ -35,9 +36,7 @@ import android.content.Intent; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.SparseIntArray; -import android.util.proto.ProtoOutputStream; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto; diff --git a/services/tests/wmtests/src/com/android/server/wm/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/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index bc62de12373d..e5e850a3fd08 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -62,7 +62,6 @@ import org.junit.Test; * Build/Install/Run: * atest FrameworksServicesTests:AppWindowTokenTests */ -@FlakyTest(bugId = 68267650) @SmallTest @Presubmit public class AppWindowTokenTests extends WindowTestsBase { @@ -79,6 +78,7 @@ public class AppWindowTokenTests extends WindowTestsBase { mTask = createTaskInStack(mStack, 0 /* userId */); mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent); + mToken.mSkipOnParentChanged = false; mTask.addChild(mToken, 0); } @@ -141,6 +141,7 @@ public class AppWindowTokenTests extends WindowTestsBase { mToken.removeImmediately(); } + @FlakyTest(detail = "Promote to presubmit when shown to be stable.") @Test public void testLandscapeSeascapeRotationByApp() { // Some plumbing to get the service ready for rotation updates. @@ -166,6 +167,8 @@ public class AppWindowTokenTests extends WindowTestsBase { mDisplayContent.updateOrientationFromAppTokens( mDisplayContent.getRequestedOverrideConfiguration(), null /* freezeThisOneIfNeeded */, false /* forceUpdate */); + // In this test, DC will not get config update. Set the waiting flag to false. + mDisplayContent.mWaitingForConfig = false; mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */); assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation()); assertTrue(appWindow.mResizeReported); @@ -300,6 +303,7 @@ public class AppWindowTokenTests extends WindowTestsBase { assertNoStartingWindow(mToken); } + @FlakyTest(detail = "Promote to presubmit when shown to be stable.") @Test public void testAddRemoveRace() { // There was once a race condition between adding and removing starting windows @@ -384,6 +388,7 @@ public class AppWindowTokenTests extends WindowTestsBase { // bottom one. tokenTop.setVisibility(false, false); tokenBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded(); + waitUntilHandlersIdle(); // Assert that the bottom window now has the starting window. assertNoStartingWindow(tokenTop); diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java index 2f90baaceb99..3f83caea613a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java @@ -71,7 +71,6 @@ import java.util.concurrent.TimeUnit; * atest WmTests:AssistDataRequesterTest */ @MediumTest -@FlakyTest(bugId = 113616538) public class AssistDataRequesterTest extends ActivityTestsBase { private static final String TAG = AssistDataRequesterTest.class.getSimpleName(); @@ -154,6 +153,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { .checkOpNoThrow(eq(OP_ASSIST_SCREENSHOT), anyInt(), anyString()); } + @FlakyTest(bugId = 124088319) @Test public void testRequestData() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -174,6 +174,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 0, 0, 0); } + @FlakyTest(bugId = 124088319) @Test public void testCurrentAppDisallow_expectNullCallbacks() throws Exception { setupMocks(!CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -184,6 +185,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 1, 0, 1); } + @FlakyTest(bugId = 124088319) @Test public void testProcessPendingData() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -241,6 +243,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 1, 0, 1); } + @FlakyTest(bugId = 124088319) @Test public void testDisallowAssistContextExtras_expectNullDataCallbacks() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -254,6 +257,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 1, 0, 1); } + @FlakyTest(bugId = 124088319) @Test public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -264,6 +268,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(5, 5, 0, 0); } + @FlakyTest(bugId = 124088319) @Test public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java index 0c363de36328..a0546d7623e7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java @@ -19,11 +19,11 @@ package com.android.server.wm; import static android.view.InsetsState.TYPE_TOP_BAR; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import android.graphics.Insets; import android.graphics.Rect; @@ -31,8 +31,6 @@ import android.platform.test.annotations.Presubmit; import android.view.InsetsSource; import android.view.InsetsState; -import org.junit.Before; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Before; diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index 11526a85aafb..bc62e8c5ab24 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -35,7 +35,6 @@ import androidx.test.filters.SmallTest; import org.junit.Test; @SmallTest -@FlakyTest(detail = "Promote once confirmed non-flaky") @Presubmit public class InsetsStateControllerTest extends WindowTestsBase { @@ -48,6 +47,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertNotNull(getController().getInsetsForDispatch(app).getSource(TYPE_TOP_BAR)); } + @FlakyTest(bugId = 69229402) @Test public void testStripForDispatch_own() { final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); @@ -57,6 +57,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertEquals(new InsetsState(), getController().getInsetsForDispatch(topBar)); } + @FlakyTest(bugId = 124088319) @Test public void testStripForDispatch_navBar() { final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); @@ -68,6 +69,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertEquals(new InsetsState(), getController().getInsetsForDispatch(navBar)); } + @FlakyTest(bugId = 124088319) @Test public void testBarControllingWinChanged() { final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); @@ -80,6 +82,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertEquals(2, controls.length); } + @FlakyTest(bugId = 124088319) @Test public void testControlRevoked() { final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); @@ -91,6 +94,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertNull(getController().getControlsForDispatch(app)); } + @FlakyTest(bugId = 124088319) @Test public void testControlRevoked_animation() { final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java index 86bf3dbb6973..b769fcecc469 100644 --- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java @@ -24,7 +24,6 @@ import android.app.ActivityOptions; import android.platform.test.annotations.Presubmit; import android.view.RemoteAnimationAdapter; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.testutils.OffsettableClock; diff --git a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java index c3d2f33b17dd..83274401f13d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java @@ -28,7 +28,6 @@ import static org.junit.Assert.assertTrue; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import org.junit.After; diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index 67ee4ad91d91..94def2bb7846 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -67,6 +67,7 @@ import org.junit.Before; import org.junit.Test; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -142,7 +143,8 @@ public class RootActivityContainerTests extends ActivityTestsBase { private static void ensureStackPlacement(ActivityStack stack, TaskRecord... tasks) { final ArrayList<TaskRecord> stackTasks = stack.getAllTasks(); - assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0); + assertEquals("Expecting " + Arrays.deepToString(tasks) + " got " + stackTasks, + stackTasks.size(), tasks != null ? tasks.length : 0); if (tasks == null) { return; diff --git a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java index dad6c952d7ab..71118521acf5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java @@ -21,7 +21,6 @@ import static org.junit.Assert.assertEquals; import android.app.ActivityOptions; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import org.junit.Test; diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java index dfdbf323365f..6cce9f088ee4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java @@ -167,7 +167,6 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase { verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L)); } - @FlakyTest(bugId = 74780584) @Test public void testDeferStartingAnimations() throws Exception { mSurfaceAnimationRunner.deferStartingAnimations(); diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java index 8c32e8cea93c..88ac96d74df6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java @@ -34,7 +34,6 @@ import android.view.SurfaceControl.Builder; import android.view.SurfaceControl.Transaction; import android.view.SurfaceSession; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.wm.SurfaceAnimator.Animatable; @@ -51,7 +50,7 @@ import org.mockito.MockitoAnnotations; * Test class for {@link SurfaceAnimatorTest}. * * Build/Install/Run: - * atest FrameworksServicesTests:SurfaceAnimatorTest + * atest WmTests:SurfaceAnimatorTest */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java index 12ed3c28161f..9dfeadf878e0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java @@ -29,8 +29,6 @@ import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.util.SparseBooleanArray; -import androidx.test.filters.FlakyTest; - import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java index 8c6ac23c9202..1e58e413dd1b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java @@ -43,7 +43,6 @@ import org.junit.Test; * Build/Install/Run: * atest FrameworksServicesTests:TaskPositioningControllerTests */ -@FlakyTest(bugId = 117924387) @SmallTest @Presubmit public class TaskPositioningControllerTests extends WindowTestsBase { @@ -90,6 +89,7 @@ public class TaskPositioningControllerTests extends WindowTestsBase { assertNull(mTarget.getDragWindowHandleLocked()); } + @FlakyTest(bugId = 69229402) @Test public void testHandleTapOutsideTask() { synchronized (mWm.mGlobalLock) { diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java index 4a734e5256f6..dcca3167c752 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java @@ -35,9 +35,11 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; import android.support.test.uiautomator.UiDevice; import android.text.TextUtils; +import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import com.android.internal.annotations.GuardedBy; @@ -76,6 +78,7 @@ public class TaskStackChangedListenerTest { } @Test + @Presubmit public void testTaskStackChanged_afterFinish() throws Exception { registerTaskStackChangedListener(new TaskStackListener() { @Override @@ -87,7 +90,8 @@ public class TaskStackChangedListenerTest { }); Context context = getInstrumentation().getContext(); - context.startActivity(new Intent(context, ActivityA.class)); + context.startActivity( + new Intent(context, ActivityA.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); UiDevice.getInstance(getInstrumentation()).waitForIdle(); synchronized (sLock) { assertTrue(sTaskStackChangedCalled); @@ -96,6 +100,7 @@ public class TaskStackChangedListenerTest { } @Test + @FlakyTest(bugId = 119893767) public void testTaskDescriptionChanged() throws Exception { final Object[] params = new Object[2]; final CountDownLatch latch = new CountDownLatch(1); @@ -124,6 +129,7 @@ public class TaskStackChangedListenerTest { } @Test + @FlakyTest(bugId = 119893767) public void testActivityRequestedOrientationChanged() throws Exception { final int[] params = new int[2]; final CountDownLatch latch = new CountDownLatch(1); @@ -146,6 +152,7 @@ public class TaskStackChangedListenerTest { * Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted. */ @Test + @FlakyTest(bugId = 119893767) public void testTaskChangeCallBacks() throws Exception { final Object[] params = new Object[2]; final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1); @@ -221,7 +228,8 @@ public class TaskStackChangedListenerTest { final ActivityMonitor monitor = new ActivityMonitor(activityClass.getName(), null, false); getInstrumentation().addMonitor(monitor); final Context context = getInstrumentation().getContext(); - context.startActivity(new Intent(context, activityClass)); + context.startActivity( + new Intent(context, activityClass).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); final TestActivity activity = (TestActivity) monitor.waitForActivityWithTimeout(1000); if (activity == null) { throw new RuntimeException("Timed out waiting for Activity"); diff --git a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java index b151fb7a613c..e540b3a9db89 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java @@ -61,7 +61,7 @@ import com.android.server.policy.WindowManagerPolicy; import org.mockito.invocation.InvocationOnMock; import org.mockito.quality.Strictness; -import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; /** * A Test utility class to create a mock {@link WindowManagerService} instance for tests. @@ -71,6 +71,8 @@ class TestSystemServices { private static WindowManagerService sService; private static TestWindowManagerPolicy sPolicy; + static AtomicBoolean sCurrentMessagesProcessed = new AtomicBoolean(false); + static void setUpWindowManagerService() { sMockitoSession = mockitoSession() .spyStatic(LockGuard.class) @@ -88,6 +90,7 @@ class TestSystemServices { sPolicy = null; sMockitoSession.finishMocking(); + sMockitoSession = null; } private static void setUpTestWindowService() { @@ -194,21 +197,23 @@ class TestSystemServices { } private static void waitHandlerIdle(Handler handler) { - if (!handler.hasMessagesOrCallbacks()) { - return; - } - final CountDownLatch latch = new CountDownLatch(1); - // Wait for delayed messages are processed. - handler.getLooper().getQueue().addIdleHandler(() -> { - if (handler.hasMessagesOrCallbacks()) { - return true; // keep idle handler. + synchronized (sCurrentMessagesProcessed) { + // Add a message to the handler queue and make sure it is fully processed before we move + // on. This makes sure all previous messages in the handler are fully processed vs. just + // popping them from the message queue. + sCurrentMessagesProcessed.set(false); + handler.post(() -> { + synchronized (sCurrentMessagesProcessed) { + sCurrentMessagesProcessed.set(true); + sCurrentMessagesProcessed.notifyAll(); + } + }); + while (!sCurrentMessagesProcessed.get()) { + try { + sCurrentMessagesProcessed.wait(); + } catch (InterruptedException e) { + } } - latch.countDown(); - return false; // remove idle handler. - }); - try { - latch.await(); - } catch (InterruptedException e) { } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java index 64ceb1bf8dff..d6608f1cabdc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java @@ -49,7 +49,7 @@ import org.junit.Test; * Test class to for {@link android.app.WindowConfiguration}. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowConfigurationTests + * atest WmTests:WindowConfigurationTests */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java index af8ccc981bae..fc7863524240 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java @@ -26,7 +26,6 @@ import static org.junit.Assert.assertTrue; import android.content.res.Configuration; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Test; @@ -35,7 +34,7 @@ import org.junit.Test; * Test class for {@link WindowContainerController}. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowContainerControllerTests + * atest WmTests:WindowContainerControllerTests */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index a9a76c2e9506..b93c994f4d8f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -47,7 +47,6 @@ import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; import android.view.SurfaceSession; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Test; @@ -59,11 +58,10 @@ import java.util.Comparator; * Test class for {@link WindowContainer}. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowContainerTests + * atest WmTests:WindowContainerTests */ @SmallTest @Presubmit -@FlakyTest(bugId = 74078662) public class WindowContainerTests extends WindowTestsBase { @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 3cb28140e2ea..a83bf2af613e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -50,6 +50,7 @@ import android.view.IWindow; import android.view.WindowManager; import com.android.server.AttributeCache; +import com.android.server.wm.utils.MockTracker; import org.junit.After; import org.junit.AfterClass; @@ -77,6 +78,8 @@ class WindowTestsBase { private static int sNextDisplayId = DEFAULT_DISPLAY + 1; static int sNextStackId = 1000; + private static MockTracker sMockTracker; + /** Non-default display. */ DisplayContent mDisplayContent; DisplayInfo mDisplayInfo = new DisplayInfo(); @@ -109,11 +112,18 @@ class WindowTestsBase { TestSystemServices.setUpWindowManagerService(); + // MockTracker needs to be initialized after TestSystemServices because we don't want to + // track static mocks. + sMockTracker = new MockTracker(); + sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class); } @AfterClass - public static void tearDonwOnceBase() { + public static void tearDownOnceBase() { + sMockTracker.close(); + sMockTracker = null; + TestSystemServices.tearDownWindowManagerService(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index d55688665f70..4cdbea0bfb56 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -28,7 +28,6 @@ import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Test; @@ -37,7 +36,7 @@ import org.junit.Test; * Tests for the {@link WindowToken} class. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowTokenTests + * atest WmTests:WindowTokenTests */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java index b6b9a861a282..3c6e2405adff 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java @@ -34,8 +34,8 @@ import android.content.Context; import android.platform.test.annotations.Presubmit; import android.testing.DexmakerShareClassLoaderRule; import android.util.proto.ProtoOutputStream; +import android.view.Choreographer; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.internal.util.Preconditions; @@ -58,7 +58,7 @@ import java.nio.charset.StandardCharsets; * Test class for {@link WindowTracing}. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowTracingTest + * atest WmTests:WindowTracingTest */ @SmallTest @Presubmit @@ -74,6 +74,8 @@ public class WindowTracingTest { @Mock private WindowManagerService mWmMock; + @Mock + private Choreographer mChoreographer; private WindowTracing mWindowTracing; private File mFile; @@ -85,7 +87,9 @@ public class WindowTracingTest { mFile = testContext.getFileStreamPath("tracing_test.dat"); mFile.delete(); - mWindowTracing = new WindowTracing(mFile); + mWindowTracing = new WindowTracing(mFile, mWmMock, mChoreographer, + new WindowManagerGlobalLock()); + mWindowTracing.setContinuousMode(false /* continuous */, null /* pw */); } @After @@ -113,15 +117,14 @@ public class WindowTracingTest { @Test public void trace_discared_whenNotTracing() { - mWindowTracing.traceStateLocked("where", mWmMock); + mWindowTracing.logState("where"); verifyZeroInteractions(mWmMock); } @Test public void trace_dumpsWindowManagerState_whenTracing() throws Exception { mWindowTracing.startTrace(mock(PrintWriter.class)); - mWindowTracing.traceStateLocked("where", mWmMock); - + mWindowTracing.logState("where"); verify(mWmMock).writeToProtoLocked(any(), eq(WindowTraceLogLevel.TRIM)); } @@ -147,7 +150,7 @@ public class WindowTracingTest { WindowManagerTraceProto.WHERE, "TEST_WM_PROTO"); return null; }).when(mWmMock).writeToProtoLocked(any(), any()); - mWindowTracing.traceStateLocked("TEST_WHERE", mWmMock); + mWindowTracing.logState("TEST_WHERE"); mWindowTracing.stopTrace(mock(PrintWriter.class)); diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java index 3dcea75b8ae5..f3b8a6265eb3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java @@ -51,9 +51,8 @@ import java.util.LinkedList; * Tests for the {@link DisplayContent#assignChildLayers(SurfaceControl.Transaction)} method. * * Build/Install/Run: - * atest FrameworksServicesTests:ZOrderingTests + * atest WmTests:ZOrderingTests */ -@FlakyTest(bugId = 74078662) @SmallTest @Presubmit public class ZOrderingTests extends WindowTestsBase { @@ -207,6 +206,7 @@ public class ZOrderingTests extends WindowTestsBase { return createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, name); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeWithNoTarget() { mDisplayContent.mInputMethodTarget = null; @@ -224,6 +224,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeWithAppTarget() { final WindowState imeAppTarget = createWindow("imeAppTarget"); @@ -243,6 +244,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() { final WindowState imeAppTarget = createWindow("imeAppTarget"); @@ -269,6 +271,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() { final WindowState appBelowImeTarget = createWindow("appBelowImeTarget"); @@ -292,6 +295,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForImeNonAppImeTarget() { final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY, @@ -319,6 +323,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testAssignWindowLayers_ForStatusBarImeTarget() { mDisplayContent.mInputMethodTarget = mStatusBarWindow; @@ -333,6 +338,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mImeDialogWindow, mImeWindow); } + @FlakyTest(bugId = 124088319) @Test public void testStackLayers() { final WindowState anyWindow1 = createWindow("anyWindow"); @@ -398,6 +404,7 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(mediaOverlayChild, child); } + @FlakyTest(bugId = 124088319) @Test public void testDockedDividerPosition() { final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED, diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java new file mode 100644 index 000000000000..1ce463bbbd9e --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm.utils; + +import android.util.Log; + +import org.mockito.Mockito; +import org.mockito.MockitoFramework; +import org.mockito.internal.creation.settings.CreationSettings; +import org.mockito.listeners.MockCreationListener; +import org.mockito.mock.MockCreationSettings; + +import java.lang.reflect.Field; +import java.util.IdentityHashMap; + +/** + * An util class used to track mock creation, and reset them when closing. Note only one instance is + * allowed at anytime, as Mockito framework throws exception if there is already a listener of the + * same type registered. + */ +public class MockTracker implements MockCreationListener, AutoCloseable { + private static final String TAG = "MockTracker"; + + private static final Field SPIED_INSTANCE_FIELD; + + static { + try { + SPIED_INSTANCE_FIELD = CreationSettings.class.getDeclaredField("spiedInstance"); + SPIED_INSTANCE_FIELD.setAccessible(true); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + } + + private final MockitoFramework mMockitoFramework = Mockito.framework(); + + private final IdentityHashMap<Object, Void> mMocks = new IdentityHashMap<>(); + + public MockTracker() { + mMockitoFramework.addListener(this); + } + + @Override + public void onMockCreated(Object mock, MockCreationSettings settings) { + mMocks.put(mock, null); + clearSpiedInstanceIfNeeded(mock, settings); + } + + // HACK: Changing Mockito core implementation details. + // TODO(b/123984854): Remove this once there is a real fix. + private void clearSpiedInstanceIfNeeded(Object mock, MockCreationSettings settings) { + if (mock != settings.getSpiedInstance()) { + // Not a spyOn instance. + return; + } + if (!(settings instanceof CreationSettings)) { + throw new IllegalStateException("Unexpected type of settings: " + settings.getClass()); + } + try { + SPIED_INSTANCE_FIELD.set(settings, null); + Log.d(TAG, "Setting spiedInstance for " + mock + " to null."); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @Override + public void close() { + mMockitoFramework.removeListener(this); + + for (final Object mock : mMocks.keySet()) { + try { + Mockito.reset(mock); + } catch (Exception e) { + Log.e(TAG, "Failed to reset " + mock, e); + } + } + mMocks.clear(); + } +} diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java index 873ada05bc27..731cbf42eca7 100644 --- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java +++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java @@ -840,7 +840,8 @@ public class AppTimeLimitController { */ public void addAppUsageLimitObserver(int requestingUid, int observerId, String[] observed, long timeLimit, PendingIntent callbackIntent, @UserIdInt int userId) { - if (timeLimit < getMinTimeLimit()) { + // Allow the special case of the limit being 0, but with no callback. + if (timeLimit != 0L && timeLimit < getMinTimeLimit()) { throw new IllegalArgumentException("Time limit must be >= " + getMinTimeLimit()); } synchronized (mLock) { @@ -858,7 +859,7 @@ public class AppTimeLimitController { "Too many app usage observers added by uid " + requestingUid); } group = new AppUsageLimitGroup(user, observerApp, observerId, observed, timeLimit, - callbackIntent); + timeLimit == 0L ? null : callbackIntent); observerApp.appUsageLimitGroups.append(observerId, group); if (DEBUG) { diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index df2f45512465..af5278f222b8 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -1377,7 +1377,7 @@ public class UsageStatsService extends SystemService implements if (packages == null || packages.length == 0) { throw new IllegalArgumentException("Must specify at least one package"); } - if (callbackIntent == null) { + if (callbackIntent == null && timeLimitMs != 0L) { throw new NullPointerException("callbackIntent can't be null"); } final int callingUid = Binder.getCallingUid(); diff --git a/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/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index 4539ab3dc310..a1c32b5f80a3 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -2717,6 +2717,41 @@ public final class Telephony { Uri RCS_EVENT_QUERY_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY, RCS_EVENT_QUERY_URI_PATH); } + + /** + * Allows RCS specific canonical address handling. + */ + interface RcsCanonicalAddressHelper { + /** + * Returns the canonical address ID for a canonical address, if now row exists, this + * will add a row and return its ID. This helper works against the same table used by + * the SMS and MMS threads, but is accessible only by the phone process for use by RCS + * message storage. + * + * @throws IllegalArgumentException if unable to retrieve or create the canonical + * address entry. + */ + static long getOrCreateCanonicalAddressId( + ContentResolver contentResolver, String canonicalAddress) { + + Uri.Builder uriBuilder = CONTENT_AND_AUTHORITY.buildUpon(); + uriBuilder.appendPath("canonical-address"); + uriBuilder.appendQueryParameter("address", canonicalAddress); + Uri uri = uriBuilder.build(); + + try (Cursor cursor = contentResolver.query(uri, null, null, null)) { + if (cursor != null && cursor.moveToFirst()) { + return cursor.getLong(cursor.getColumnIndex(CanonicalAddressesColumns._ID)); + } else { + Rlog.e(TAG, "getOrCreateCanonicalAddressId returned no rows"); + } + } + + Rlog.e(TAG, "getOrCreateCanonicalAddressId failed"); + throw new IllegalArgumentException( + "Unable to find or allocate a canonical address ID"); + } + } } /** diff --git a/telephony/java/android/telephony/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/test-runner/Android.mk b/test-runner/Android.mk deleted file mode 100644 index 18bde8517351..000000000000 --- a/test-runner/Android.mk +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (C) 2008 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -LOCAL_PATH:= $(call my-dir) - -# additionally, build unit tests in a separate .apk -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/test-runner/tests/Android.bp b/test-runner/tests/Android.bp new file mode 100644 index 000000000000..03c73986118d --- /dev/null +++ b/test-runner/tests/Android.bp @@ -0,0 +1,40 @@ +// Copyright 2010, The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +android_test { + name: "FrameworkTestRunnerTests", + + // We only want this apk build for tests. + // + // Run the tests using the following commands: + // adb install -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworkTestRunnerTests/FrameworkTestRunnerTests.apk + // adb shell am instrument \ + // -e notAnnotation android.test.suitebuilder.examples.error.RunAsPartOfSeparateTest \ + // -w com.android.frameworks.testrunner.tests/android.test.InstrumentationTestRunner \ + // + + libs: [ + "android.test.runner", + "android.test.base", + "android.test.mock", + ], + static_libs: ["junit"], + + // Include all test java files. + srcs: ["src/**/*.java"], + + // Because of android.test.mock. + platform_apis: true, + +} diff --git a/test-runner/tests/Android.mk b/test-runner/tests/Android.mk deleted file mode 100644 index f97d1c986b1c..000000000000 --- a/test-runner/tests/Android.mk +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2010, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -# We only want this apk build for tests. -# -# Run the tests using the following commands: -# adb install -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworkTestRunnerTests/FrameworkTestRunnerTests.apk -# adb shell am instrument \ - -e notAnnotation android.test.suitebuilder.examples.error.RunAsPartOfSeparateTest \ - -w com.android.frameworks.testrunner.tests/android.test.InstrumentationTestRunner -# -LOCAL_MODULE_TAGS := tests - -LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock -LOCAL_STATIC_JAVA_LIBRARIES := junit - -# Include all test java files. -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_PACKAGE_NAME := FrameworkTestRunnerTests -# Because of android.test.mock. -LOCAL_PRIVATE_PLATFORM_APIS := true - -include $(BUILD_PACKAGE) - diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index e2d59d648563..a7c95c78d05d 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -554,7 +554,7 @@ public class ConnectivityServiceTest { if (mNmValidationRedirectUrl != null) { mNmCallbacks.showProvisioningNotification( - "test_provisioning_notif_action"); + "test_provisioning_notif_action", "com.android.test.package"); mNmProvNotificationRequested = true; } } catch (RemoteException e) { diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index b6356076db60..a4a735d1a89d 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -35,6 +35,7 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY; import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -274,6 +275,11 @@ public class TetheringTest { isTetheringSupportedCalls++; return true; } + + @Override + public int getDefaultDataSubscriptionId() { + return INVALID_SUBSCRIPTION_ID; + } } private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6, diff --git a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java index ec286759354a..193f3806dbf6 100644 --- a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java @@ -21,6 +21,7 @@ import static android.net.ConnectivityManager.TETHERING_WIFI; import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN; import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -140,7 +141,8 @@ public final class EntitlementManagerTest { mMockContext = new MockContext(mContext); mSM = new TestStateMachine(); mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, mSystemProperties); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog)); + mEnMgr.updateConfiguration( + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); } @After @@ -168,7 +170,8 @@ public final class EntitlementManagerTest { @Test public void canRequireProvisioning() { setupForRequiredProvisioning(); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog)); + mEnMgr.updateConfiguration( + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); assertTrue(mEnMgr.isTetherProvisioningRequired()); } @@ -177,7 +180,8 @@ public final class EntitlementManagerTest { setupForRequiredProvisioning(); when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE)) .thenReturn(null); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog)); + mEnMgr.updateConfiguration( + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); // Couldn't get the CarrierConfigManager, but still had a declared provisioning app. // Therefore provisioning still be required. assertTrue(mEnMgr.isTetherProvisioningRequired()); @@ -187,7 +191,8 @@ public final class EntitlementManagerTest { public void toleratesCarrierConfigMissing() { setupForRequiredProvisioning(); when(mCarrierConfigManager.getConfig()).thenReturn(null); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog)); + mEnMgr.updateConfiguration( + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); // We still have a provisioning app configured, so still require provisioning. assertTrue(mEnMgr.isTetherProvisioningRequired()); } @@ -197,11 +202,13 @@ public final class EntitlementManagerTest { setupForRequiredProvisioning(); when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app)) .thenReturn(null); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog)); + mEnMgr.updateConfiguration( + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); assertFalse(mEnMgr.isTetherProvisioningRequired()); when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app)) .thenReturn(new String[] {"malformedApp"}); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog)); + mEnMgr.updateConfiguration( + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); assertFalse(mEnMgr.isTetherProvisioningRequired()); } @@ -223,7 +230,8 @@ public final class EntitlementManagerTest { assertFalse(mEnMgr.everRunUiEntitlement); setupForRequiredProvisioning(); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog)); + mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog, + INVALID_SUBSCRIPTION_ID)); // 2. No cache value and don't need to run entitlement check. mEnMgr.everRunUiEntitlement = false; receiver = new ResultReceiver(null) { diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java index 521778484d91..01b904d8f088 100644 --- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java +++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java @@ -22,10 +22,12 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_NOT_REQUIRED; import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_REQUIRED; import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_UNSPECIFIED; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -44,26 +46,39 @@ import android.test.mock.MockContentResolver; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; -import java.util.Iterator; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Iterator; @RunWith(AndroidJUnit4.class) @SmallTest public class TetheringConfigurationTest { private final SharedLog mLog = new SharedLog("TetheringConfigurationTest"); + + private static final String[] PROVISIONING_APP_NAME = {"some", "app"}; @Mock private Context mContext; @Mock private TelephonyManager mTelephonyManager; @Mock private Resources mResources; + @Mock private Resources mResourcesForSubId; private MockContentResolver mContentResolver; private Context mMockContext; private boolean mHasTelephonyManager; + private class MockTetheringConfiguration extends TetheringConfiguration { + MockTetheringConfiguration(Context ctx, SharedLog log, int id) { + super(ctx, log, id); + } + + @Override + protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) { + return mResourcesForSubId; + } + } + private class MockContext extends BroadcastInterceptingContext { MockContext(Context base) { super(base); @@ -99,6 +114,9 @@ public class TetheringConfigurationTest { .thenReturn(new String[0]); when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[0]); + when(mResources.getStringArray( + com.android.internal.R.array.config_mobile_hotspot_provision_app)) + .thenReturn(new String[0]); mContentResolver = new MockContentResolver(); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); mMockContext = new MockContext(mContext); @@ -111,7 +129,8 @@ public class TetheringConfigurationTest { mHasTelephonyManager = true; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_REQUIRED); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertTrue(cfg.isDunRequired); assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); @@ -127,7 +146,8 @@ public class TetheringConfigurationTest { mHasTelephonyManager = true; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_NOT_REQUIRED); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertFalse(cfg.isDunRequired); assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); @@ -143,7 +163,8 @@ public class TetheringConfigurationTest { mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertTrue(cfg.isDunRequired); assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); // Just to prove we haven't clobbered Wi-Fi: @@ -160,7 +181,8 @@ public class TetheringConfigurationTest { mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); assertTrue(upstreamIterator.hasNext()); assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue()); @@ -181,7 +203,8 @@ public class TetheringConfigurationTest { mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); assertTrue(upstreamIterator.hasNext()); assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue()); @@ -199,7 +222,8 @@ public class TetheringConfigurationTest { mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); assertTrue(upstreamIterator.hasNext()); assertEquals(TYPE_WIFI, upstreamIterator.next().intValue()); @@ -214,7 +238,8 @@ public class TetheringConfigurationTest { public void testNewDhcpServerDisabled() { Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertTrue(cfg.enableLegacyDhcpServer); } @@ -222,7 +247,41 @@ public class TetheringConfigurationTest { public void testNewDhcpServerEnabled() { Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0); - final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertFalse(cfg.enableLegacyDhcpServer); } + + @Test + public void testGetResourcesBySubId() { + setUpResourceForSubId(); + final TetheringConfiguration cfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(cfg.provisioningApp.length == 0); + final int anyValidSubId = 1; + final MockTetheringConfiguration mockCfg = + new MockTetheringConfiguration(mMockContext, mLog, anyValidSubId); + assertEquals(mockCfg.provisioningApp[0], PROVISIONING_APP_NAME[0]); + assertEquals(mockCfg.provisioningApp[1], PROVISIONING_APP_NAME[1]); + } + + private void setUpResourceForSubId() { + when(mResourcesForSubId.getStringArray( + com.android.internal.R.array.config_tether_dhcp_range)).thenReturn(new String[0]); + when(mResourcesForSubId.getStringArray( + com.android.internal.R.array.config_tether_usb_regexs)).thenReturn(new String[0]); + when(mResourcesForSubId.getStringArray( + com.android.internal.R.array.config_tether_wifi_regexs)) + .thenReturn(new String[]{ "test_wlan\\d" }); + when(mResourcesForSubId.getStringArray( + com.android.internal.R.array.config_tether_bluetooth_regexs)) + .thenReturn(new String[0]); + when(mResourcesForSubId.getIntArray( + com.android.internal.R.array.config_tether_upstream_types)) + .thenReturn(new int[0]); + when(mResourcesForSubId.getStringArray( + com.android.internal.R.array.config_mobile_hotspot_provision_app)) + .thenReturn(PROVISIONING_APP_NAME); + } + } diff --git a/tools/preload/Android.bp b/tools/preload/Android.bp new file mode 100644 index 000000000000..809ee474969a --- /dev/null +++ b/tools/preload/Android.bp @@ -0,0 +1,17 @@ +java_library_host { + name: "preload", + srcs: [ + "Compile.java", + "LoadedClass.java", + "MemoryUsage.java", + "Operation.java", + "Policy.java", + "PrintCsv.java", + "PrintHtmlDiff.java", + "PrintPsTree.java", + "Proc.java", + "Record.java", + "Root.java", + "WritePreloadedClassFile.java", + ], +} diff --git a/tools/preload/Android.mk b/tools/preload/Android.mk deleted file mode 100644 index 14a4547cccbf..000000000000 --- a/tools/preload/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - Compile.java \ - LoadedClass.java \ - MemoryUsage.java \ - Operation.java \ - Policy.java \ - PrintCsv.java \ - PrintHtmlDiff.java \ - PrintPsTree.java \ - Proc.java \ - Record.java \ - Root.java \ - WritePreloadedClassFile.java - -LOCAL_MODULE:= preload - -include $(BUILD_HOST_JAVA_LIBRARY) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tools/preload/loadclass/Android.bp b/tools/preload/loadclass/Android.bp new file mode 100644 index 000000000000..6f12015dae2b --- /dev/null +++ b/tools/preload/loadclass/Android.bp @@ -0,0 +1,4 @@ +java_test { + name: "loadclass", + srcs: ["**/*.java"], +} diff --git a/tools/preload/loadclass/Android.mk b/tools/preload/loadclass/Android.mk deleted file mode 100644 index 65828be617df..000000000000 --- a/tools/preload/loadclass/Android.mk +++ /dev/null @@ -1,9 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(call all-subdir-java-files) -LOCAL_MODULE_TAGS := tests - -LOCAL_MODULE := loadclass - -include $(BUILD_JAVA_LIBRARY) diff --git a/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()); } } |