diff options
265 files changed, 3997 insertions, 1070 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 b793470bdb66..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 { @@ -55869,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); @@ -56672,13 +57158,18 @@ package android.widget { method public boolean executeKeyEvent(android.view.KeyEvent); method public void fling(int); method public boolean fullScroll(int); + method @ColorInt public int getBottomEdgeEffectColor(); method public int getMaxScrollAmount(); + method @ColorInt public int getTopEdgeEffectColor(); method public boolean isFillViewport(); method public boolean isSmoothScrollingEnabled(); method public boolean pageScroll(int); method public void scrollToDescendant(android.view.View); + method public void setBottomEdgeEffectColor(@ColorInt int); + method public void setEdgeEffectColor(@ColorInt int); method public void setFillViewport(boolean); method public void setSmoothScrollingEnabled(boolean); + method public void setTopEdgeEffectColor(@ColorInt int); method public final void smoothScrollBy(int, int); method public final void smoothScrollTo(int, int); } diff --git a/api/system-current.txt b/api/system-current.txt index c9b8c3867e59..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 @@ -1150,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); @@ -5778,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"; } @@ -5786,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"; @@ -7018,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 @@ -7833,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 b2ead4ab2464..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"; @@ -2694,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/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 ea3f3b32b0c4..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 { 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 92aa998d9720..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,8 @@ 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) { 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/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 51397a243420..dc5bdc673249 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -745,7 +745,11 @@ public final class UsageStatsManager { * Registering an {@code observerId} that was already registered will override the previous one. * No more than 1000 unique {@code observerId} may be registered by a single uid * at any one time. - * A limit may be unregistered via {@link #unregisterAppUsageLimitObserver} + * A limit is not cleared when the usage time is exceeded. It needs to be unregistered via + * {@link #unregisterAppUsageLimitObserver}. + * <p> + * Note: usage limits are not persisted in the system and are cleared on reboots. Callers + * must reset any limits that they need on reboots. * <p> * This method is similar to {@link #registerAppUsageObserver}, but the usage limit set here * will be visible to the launcher so that it can report the limit to the user and how much @@ -757,12 +761,15 @@ public final class UsageStatsManager { * @param observedEntities The list of packages and token to observe for usage time. Cannot be * null and must include at least one package or token. * @param timeLimit The total time the set of apps can be in the foreground before the - * callbackIntent is delivered. Must be at least one minute. + * callbackIntent is delivered. Must be at least one minute. Note: a limit of + * 0 can be set to indicate that the user has already exhausted the limit for + * a group, in which case, the given {@code callbackIntent} will be ignored. * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null. - * @param callbackIntent The PendingIntent that will be dispatched when the usage limit is + * @param callbackIntent The PendingIntent that will be dispatched when the usage limit is * exceeded by the group of apps. The delivered Intent will also contain * the extras {@link #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and - * {@link #EXTRA_TIME_USED}. Cannot be null. + * {@link #EXTRA_TIME_USED}. Cannot be {@code null} unless the observer is + * being registered with a {@code timeLimit} of 0. * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE * permissions. * @hide @@ -772,7 +779,7 @@ public final class UsageStatsManager { android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities, - long timeLimit, @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) { + long timeLimit, @NonNull TimeUnit timeUnit, PendingIntent callbackIntent) { try { mService.registerAppUsageLimitObserver(observerId, observedEntities, timeUnit.toMillis(timeLimit), callbackIntent, mContext.getOpPackageName()); diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 47034a6df8a7..7cc439138527 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -1029,10 +1029,18 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { } /** + * Returns true if the activity has maximum or minimum aspect ratio. + * @hide + */ + public boolean hasFixedAspectRatio() { + return maxAspectRatio != 0 || minAspectRatio != 0; + } + + /** * Returns true if the activity's orientation is fixed. * @hide */ - boolean isFixedOrientation() { + public boolean isFixedOrientation() { return isFixedOrientationLandscape() || isFixedOrientationPortrait() || screenOrientation == SCREEN_ORIENTATION_LOCKED; } diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index b27c5dc1b457..6c6fcb2ea558 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -650,6 +650,18 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int PRIVATE_FLAG_USE_EMBEDDED_DEX = 1 << 25; + /** + * Value for {@link #privateFlags}: indicates whether this application's data will be cleared + * on a failed restore. + * + * <p>Comes from the + * android.R.styleable#AndroidManifestApplication_allowClearUserDataOnFailedRestore attribute + * of the <application> tag. + * + * @hide + */ + public static final int PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE = 1 << 26; + /** @hide */ @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = { PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE, @@ -676,6 +688,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { PRIVATE_FLAG_VENDOR, PRIVATE_FLAG_VIRTUAL_PRELOAD, PRIVATE_FLAG_HAS_FRAGILE_USER_DATA, + PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE }) @Retention(RetentionPolicy.SOURCE) public @interface ApplicationInfoPrivateFlags {} diff --git a/core/java/android/content/pm/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/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/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/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/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/ListView.java b/core/java/android/widget/ListView.java index 311f8968150c..2aa019b5d0f4 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -236,6 +236,8 @@ public class ListView extends AbsListView { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.ListView, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.ListView, + attrs, a, defStyleAttr, defStyleRes); final CharSequence[] entries = a.getTextArray(R.styleable.ListView_entries); if (entries != null) { diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index 157992a98a4a..89bb2738b899 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -639,6 +639,8 @@ public class NumberPicker extends LinearLayout { // process style attributes final TypedArray attributesArray = context.obtainStyledAttributes( attrs, R.styleable.NumberPicker, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.NumberPicker, + attrs, attributesArray, defStyleAttr, defStyleRes); final int layoutResId = attributesArray.getResourceId( R.styleable.NumberPicker_internalLayout, DEFAULT_LAYOUT_RESOURCE_ID); diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 30df5b5a09a3..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; @@ -267,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; 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 106b90959ba0..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); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index d87600125a54..51eaa12aa314 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -664,7 +664,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @UnsupportedAppUsage private CharWrapper mCharWrapper; - @UnsupportedAppUsage + @UnsupportedAppUsage(trackingBug = 124050217) private Marquee mMarquee; @UnsupportedAppUsage private boolean mRestartMarquee; diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index b239ce638e68..97a8ade589d1 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -127,6 +127,8 @@ public class TimePicker extends FrameLayout { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.TimePicker, + attrs, a, defStyleAttr, defStyleRes); final boolean isDialogMode = a.getBoolean(R.styleable.TimePicker_dialogMode, false); final int requestedMode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER); a.recycle(); diff --git a/core/java/android/widget/ToggleButton.java b/core/java/android/widget/ToggleButton.java index bba6da6b7b4c..b76c2cafd912 100644 --- a/core/java/android/widget/ToggleButton.java +++ b/core/java/android/widget/ToggleButton.java @@ -48,6 +48,8 @@ public class ToggleButton extends CompoundButton { final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.ToggleButton, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ToggleButton, + attrs, a, defStyleAttr, defStyleRes); mTextOn = a.getText(com.android.internal.R.styleable.ToggleButton_textOn); mTextOff = a.getText(com.android.internal.R.styleable.ToggleButton_textOff); mDisabledAlpha = a.getFloat(com.android.internal.R.styleable.ToggleButton_disabledAlpha, 0.5f); diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index a33c47d86673..f25109ee82df 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -237,6 +237,8 @@ public class Toolbar extends ViewGroup { final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Toolbar, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, R.styleable.Toolbar, + attrs, a, defStyleAttr, defStyleRes); mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0); mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0); diff --git a/core/java/android/widget/TwoLineListItem.java b/core/java/android/widget/TwoLineListItem.java index 553b86e1f0c2..4c613a71a3ac 100644 --- a/core/java/android/widget/TwoLineListItem.java +++ b/core/java/android/widget/TwoLineListItem.java @@ -62,6 +62,8 @@ public class TwoLineListItem extends RelativeLayout { final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.TwoLineListItem, defStyleAttr, defStyleRes); + saveAttributeDataForStyleable(context, com.android.internal.R.styleable.TwoLineListItem, + attrs, a, defStyleAttr, defStyleRes); a.recycle(); } diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java index 2c272dea073b..7f4d8a2d0587 100644 --- a/core/java/com/android/internal/os/BinderCallsStats.java +++ b/core/java/com/android/internal/os/BinderCallsStats.java @@ -52,6 +52,8 @@ public class BinderCallsStats implements BinderInternal.Observer { public static final boolean ENABLED_DEFAULT = true; public static final boolean DETAILED_TRACKING_DEFAULT = true; public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 100; + public static final boolean DEFAULT_TRACK_SCREEN_INTERACTIVE = false; + public static final boolean DEFAULT_TRACK_DIRECT_CALLING_UID = true; public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 5000; private static final String DEBUG_ENTRY_PREFIX = "__DEBUG_"; @@ -85,6 +87,8 @@ public class BinderCallsStats implements BinderInternal.Observer { private long mStartElapsedTime = SystemClock.elapsedRealtime(); private long mCallStatsCount = 0; private boolean mAddDebugEntries = false; + private boolean mTrackDirectCallingUid = DEFAULT_TRACK_DIRECT_CALLING_UID; + private boolean mTrackScreenInteractive = DEFAULT_TRACK_SCREEN_INTERACTIVE; private CachedDeviceState.Readonly mDeviceState; private CachedDeviceState.TimeInStateStopwatch mBatteryStopwatch; @@ -160,7 +164,12 @@ public class BinderCallsStats implements BinderInternal.Observer { duration = 0; latencyDuration = 0; } - final int callingUid = getCallingUid(); + final boolean screenInteractive = mTrackScreenInteractive + ? mDeviceState.isScreenInteractive() + : OVERFLOW_SCREEN_INTERACTIVE; + final int callingUid = mTrackDirectCallingUid + ? getCallingUid() + : OVERFLOW_DIRECT_CALLING_UID; synchronized (mLock) { // This was already checked in #callStart but check again while synchronized. @@ -177,7 +186,7 @@ public class BinderCallsStats implements BinderInternal.Observer { final CallStat callStat = uidEntry.getOrCreate( callingUid, s.binderClass, s.transactionCode, - mDeviceState.isScreenInteractive(), + screenInteractive, mCallStatsCount >= mMaxBinderCallStatsCount); final boolean isNewCallStat = callStat.callCount == 0; if (isNewCallStat) { @@ -484,6 +493,30 @@ public class BinderCallsStats implements BinderInternal.Observer { } } + /** + * Whether to track the screen state. + */ + public void setTrackScreenInteractive(boolean enabled) { + synchronized (mLock) { + if (enabled != mTrackScreenInteractive) { + mTrackScreenInteractive = enabled; + reset(); + } + } + } + + /** + * Whether to track direct caller uid. + */ + public void setTrackDirectCallerUid(boolean enabled) { + synchronized (mLock) { + if (enabled != mTrackDirectCallingUid) { + mTrackDirectCallingUid = enabled; + reset(); + } + } + } + public void setAddDebugEntries(boolean addDebugEntries) { mAddDebugEntries = addDebugEntries; } diff --git a/core/java/com/android/internal/os/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/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 130f6291b516..18eb7e96d748 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3425,8 +3425,14 @@ --> <string-array translatable="false" name="config_convert_to_emergency_number_map" /> - <!-- An array of packages for which notifications cannot be blocked. --> - <string-array translatable="false" name="config_nonBlockableNotificationPackages" /> + <!-- An array of packages for which notifications cannot be blocked. + Should only be used for core device functionality that must not be + rendered inoperative for safety reasons, like the phone dialer and + SMS handler. --> + <string-array translatable="false" name="config_nonBlockableNotificationPackages"> + <item>com.android.dialer</item> + <item>com.android.messaging</item> + </string-array> <!-- An array of packages which can listen for notifications on low ram devices. --> <string-array translatable="false" name="config_allowedManagedServicesOnLowRamDevices" /> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index d2c3b40cc3b6..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"> 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/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/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/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/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/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/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 89c6c8a66231..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> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index fc1843ba982a..822920e63460 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -187,7 +187,9 @@ public class KeyguardClockSwitch extends RelativeLayout { View bigClockView = mClockPlugin.getBigClockView(); if (bigClockView != null) { container.addView(bigClockView); - container.setVisibility(View.VISIBLE); + if (container.getVisibility() == View.GONE) { + container.setVisibility(View.VISIBLE); + } } } mBigClockContainer = container; diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java index 3591dc82c8ec..4d8cf963ff50 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java @@ -22,6 +22,7 @@ import android.content.res.Resources; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; +import android.widget.FrameLayout.LayoutParams; import com.android.keyguard.R; @@ -80,8 +81,9 @@ public class ClockLayout extends FrameLayout { // Put digital clock in two left corner of the screen. if (mDigitalClock != null) { - mDigitalClock.setX(0.1f * getWidth() + offsetX); - mDigitalClock.setY(0.1f * getHeight() + offsetY); + LayoutParams params = (LayoutParams) mDigitalClock.getLayoutParams(); + mDigitalClock.setX(offsetX + params.leftMargin); + mDigitalClock.setY(offsetY + params.topMargin); } // Put the analog clock in the middle of the screen. diff --git a/packages/SystemUI/src/com/android/systemui/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/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/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java index c7b2fab54fff..37237317fc95 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java @@ -84,6 +84,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G public static final int ACTION_UNDO = 1; public static final int ACTION_TOGGLE_SILENT = 2; public static final int ACTION_BLOCK = 3; + public static final int ACTION_DELIVER_SILENTLY = 4; private INotificationManager mINotificationManager; private PackageManager mPm; @@ -135,30 +136,26 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G }; private OnClickListener mOnToggleSilent = v -> { - Runnable saveImportance = () -> { - swapContent(ACTION_TOGGLE_SILENT, true /* animate */); - if (mIsForBlockingHelper) { - mMetricsLogger.write(getLogMaker() - .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER) - .setType(MetricsEvent.TYPE_ACTION) - .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME)); - } - }; - if (mCheckSaveListener != null) { - mCheckSaveListener.checkSave(saveImportance, mSbn); - } else { - saveImportance.run(); - } + handleSaveImportance(ACTION_TOGGLE_SILENT, MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME); + }; + + private OnClickListener mOnDeliverSilently = v -> { + handleSaveImportance( + ACTION_DELIVER_SILENTLY, MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT); }; private OnClickListener mOnStopOrMinimizeNotifications = v -> { + handleSaveImportance(ACTION_BLOCK, MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED); + }; + + private void handleSaveImportance(int action, int metricsSubtype) { Runnable saveImportance = () -> { - swapContent(ACTION_BLOCK, true /* animate */); + swapContent(action, true /* animate */); if (mIsForBlockingHelper) { mMetricsLogger.write(getLogMaker() .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER) .setType(MetricsEvent.TYPE_ACTION) - .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED)); + .setSubtype(metricsSubtype)); } }; if (mCheckSaveListener != null) { @@ -166,7 +163,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } else { saveImportance.run(); } - }; + } private OnClickListener mOnUndo = v -> { // Reset exit counter that we'll log and record an undo event separately (not an exit event) @@ -283,8 +280,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G mMetricsLogger.write(notificationControlsLogMaker()); } - - private void bindHeader() throws RemoteException { // Package name Drawable pkgicon = null; @@ -479,17 +474,21 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G findViewById(R.id.block_or_minimize).setVisibility(VISIBLE); findViewById(R.id.interruptiveness_settings).setVisibility(GONE); View block = findViewById(R.id.block); - TextView keep = findViewById(R.id.keep); + TextView done = findViewById(R.id.done); View minimize = findViewById(R.id.minimize); + View deliverSilently = findViewById(R.id.deliver_silently); + block.setOnClickListener(mOnStopOrMinimizeNotifications); - keep.setOnClickListener(mOnKeepShowing); + done.setOnClickListener(mOnKeepShowing); minimize.setOnClickListener(mOnStopOrMinimizeNotifications); + deliverSilently.setOnClickListener(mOnDeliverSilently); if (mIsNonblockable) { - keep.setText(android.R.string.ok); + done.setText(android.R.string.ok); block.setVisibility(GONE); minimize.setVisibility(GONE); + deliverSilently.setVisibility(GONE); } else if (mIsForeground) { block.setVisibility(GONE); minimize.setVisibility(VISIBLE); @@ -499,7 +498,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } // Set up app settings link (i.e. Customize) - TextView settingsLinkView = findViewById(R.id.app_settings); + View settingsLinkView = findViewById(R.id.app_settings); Intent settingsIntent = getAppSettingsIntent(mPm, mPackageName, mSingleNotificationChannel, mSbn.getId(), mSbn.getTag()); @@ -507,7 +506,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G && settingsIntent != null && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) { settingsLinkView.setVisibility(VISIBLE); - settingsLinkView.setText(mContext.getString(R.string.notification_app_settings)); settingsLinkView.setOnClickListener((View view) -> { mAppSettingsClickListener.onClick(view, settingsIntent); }); @@ -531,6 +529,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G case ACTION_UNDO: mChosenImportance = mStartingChannelImportance; break; + case ACTION_DELIVER_SILENTLY: + mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY; + mChosenImportance = IMPORTANCE_LOW; + confirmationText.setText(R.string.notification_channel_silenced); + break; case ACTION_TOGGLE_SILENT: mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT; if (mWasShownHighPriority) { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java index 5d03f19f4655..b0d1106ecb24 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java @@ -35,7 +35,6 @@ import android.testing.TestableLooper.RunWithLooper; import android.text.TextPaint; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.TextClock; @@ -60,6 +59,8 @@ import org.mockito.MockitoAnnotations; @RunWithLooper(setAsMainLooper = true) public class KeyguardClockSwitchTest extends SysuiTestCase { private FrameLayout mClockContainer; + private FrameLayout mBigClockContainer; + private TextClock mBigClock; private StatusBarStateController.StateListener mStateListener; @Mock @@ -73,6 +74,8 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { mKeyguardClockSwitch = (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null); mClockContainer = mKeyguardClockSwitch.findViewById(R.id.clock_view); + mBigClockContainer = new FrameLayout(getContext()); + mBigClock = new TextClock(getContext()); MockitoAnnotations.initMocks(this); when(mClockView.getPaint()).thenReturn(mock(TextPaint.class)); mStateListener = mKeyguardClockSwitch.getStateListener(); @@ -93,19 +96,17 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { @Test public void onPluginConnected_showPluginBigClock() { // GIVEN that the container for the big clock has visibility GONE - FrameLayout bigClockContainer = new FrameLayout(getContext()); - bigClockContainer.setVisibility(GONE); - mKeyguardClockSwitch.setBigClockContainer(bigClockContainer); + mBigClockContainer.setVisibility(GONE); + mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); // AND the plugin returns a view for the big clock ClockPlugin plugin = mock(ClockPlugin.class); - TextClock pluginView = new TextClock(getContext()); - when(plugin.getBigClockView()).thenReturn(pluginView); + when(plugin.getBigClockView()).thenReturn(mBigClock); // WHEN the plugin is connected mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); // THEN the big clock container is visible and it is the parent of the // big clock view. - assertThat(bigClockContainer.getVisibility()).isEqualTo(VISIBLE); - assertThat(pluginView.getParent()).isEqualTo(bigClockContainer); + assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mBigClock.getParent()).isEqualTo(mBigClockContainer); } @Test @@ -246,24 +247,64 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { @Test public void onStateChanged_InvisibleInShade() { // GIVEN that the big clock container is visible - ViewGroup container = mock(ViewGroup.class); - when(container.getVisibility()).thenReturn(View.VISIBLE); - mKeyguardClockSwitch.setBigClockContainer(container); + mBigClockContainer.setVisibility(View.VISIBLE); + mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); // WHEN transitioned to SHADE state mStateListener.onStateChanged(StatusBarState.SHADE); // THEN the container is invisible. - verify(container).setVisibility(View.INVISIBLE); + assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.INVISIBLE); } @Test public void onStateChanged_VisibleInKeyguard() { // GIVEN that the big clock container is invisible - ViewGroup container = mock(ViewGroup.class); - when(container.getVisibility()).thenReturn(View.INVISIBLE); - mKeyguardClockSwitch.setBigClockContainer(container); + mBigClockContainer.setVisibility(View.INVISIBLE); + mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); // WHEN transitioned to KEYGUARD state mStateListener.onStateChanged(StatusBarState.KEYGUARD); // THEN the container is visible. - verify(container).setVisibility(View.VISIBLE); + assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void setBigClockContainer_visible() { + // GIVEN that the big clock container is visible + mBigClockContainer.setVisibility(View.VISIBLE); + // AND GIVEN that a plugin is active. + ClockPlugin plugin = mock(ClockPlugin.class); + when(plugin.getBigClockView()).thenReturn(mBigClock); + mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); + // WHEN the container is associated with the clock switch + mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); + // THEN the container remains visible. + assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void setBigClockContainer_invisible() { + // GIVEN that the big clock container is invisible + mBigClockContainer.setVisibility(View.INVISIBLE); + // AND GIVEN that a plugin is active. + ClockPlugin plugin = mock(ClockPlugin.class); + when(plugin.getBigClockView()).thenReturn(mBigClock); + mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); + // WHEN the container is associated with the clock switch + mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); + // THEN the container remains invisible. + assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.INVISIBLE); + } + + @Test + public void setBigClockContainer_gone() { + // GIVEN that the big clock container is gone + mBigClockContainer.setVisibility(View.GONE); + // AND GIVEN that a plugin is active. + ClockPlugin plugin = mock(ClockPlugin.class); + when(plugin.getBigClockView()).thenReturn(mBigClock); + mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); + // WHEN the container is associated with the clock switch + mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); + // THEN the container is made visible. + assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java index 105bd9dd8793..19a73f6c2d5b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java @@ -737,7 +737,7 @@ public class NotificationInfoTest extends SysuiTestCase { guts.setGutsContent(mNotificationInfo); mNotificationInfo.setGutsParent(guts); - mNotificationInfo.findViewById(R.id.keep).performClick(); + mNotificationInfo.findViewById(R.id.done).performClick(); verify(mBlockingHelperManager).dismissCurrentBlockingHelper(); mTestableLooper.processAllMessages(); @@ -765,7 +765,7 @@ public class NotificationInfoTest extends SysuiTestCase { guts.setGutsContent(mNotificationInfo); mNotificationInfo.setGutsParent(guts); - mNotificationInfo.findViewById(R.id.keep).performClick(); + mNotificationInfo.findViewById(R.id.done).performClick(); verify(mBlockingHelperManager).dismissCurrentBlockingHelper(); mTestableLooper.processAllMessages(); @@ -961,6 +961,41 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test + public void testSilentlyChangedCallsUpdateNotificationChannel_blockingHelper() + throws Exception { + mNotificationChannel.setImportance(IMPORTANCE_LOW); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + 1 /* numChannels */, + mSbn, + null /* checkSaveListener */, + null /* onSettingsClick */, + null /* onAppSettingsClick */, + true /*provisioned */, + false /* isNonblockable */, + true /* isForBlockingHelper */, + true /* isUserSentimentNegative */, + IMPORTANCE_DEFAULT, + false); + + mNotificationInfo.findViewById(R.id.deliver_silently).performClick(); + waitForUndoButton(); + mNotificationInfo.handleCloseControls(true, false); + + mTestableLooper.processAllMessages(); + ArgumentCaptor<NotificationChannel> updated = + ArgumentCaptor.forClass(NotificationChannel.class); + verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( + anyString(), eq(TEST_UID), updated.capture()); + assertTrue((updated.getValue().getUserLockedFields() + & USER_LOCKED_IMPORTANCE) != 0); + assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance()); + } + + @Test public void testKeepUpdatesNotificationChannel() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto index 82359c547a88..ad0ed8beb7c5 100644 --- a/proto/src/wifi.proto +++ b/proto/src/wifi.proto @@ -518,6 +518,9 @@ message WifiLog { // WifiConfigStore read/write metrics. optional WifiConfigStoreIO wifi_config_store_io = 137; + + // Total number of saved networks with mac randomization enabled. + optional int32 num_saved_networks_with_mac_randomization = 138; } // Information that gets logged for every WiFi connection. 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/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/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 4faf910f52ea..0251efb872bc 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -75,12 +75,12 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; import static android.content.pm.ActivityInfo.isFixedOrientationPortrait; import static android.content.res.Configuration.EMPTY; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.content.res.Configuration.UI_MODE_TYPE_MASK; import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET; import static android.os.Build.VERSION_CODES.HONEYCOMB; @@ -2610,10 +2610,6 @@ final class ActivityRecord extends ConfigurationContainer { } } - int getRequestedOrientation() { - return getOrientation(); - } - void setRequestedOrientation(int requestedOrientation) { setOrientation(requestedOrientation, mayFreezeScreenLocked(app)); mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged( @@ -2641,7 +2637,7 @@ final class ActivityRecord extends ConfigurationContainer { int getOrientation() { if (mAppWindowToken == null) { - return SCREEN_ORIENTATION_UNSPECIFIED; + return info.screenOrientation; } return mAppWindowToken.getOrientationIgnoreVisibility(); @@ -2677,25 +2673,92 @@ final class ActivityRecord extends ConfigurationContainer { mLastReportedConfiguration.setConfiguration(global, override); } + /** + * Get the configuration orientation by the requested screen orientation + * ({@link ActivityInfo.ScreenOrientation}) of this activity. + * + * @return orientation in ({@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}, + * {@link #ORIENTATION_UNDEFINED}). + */ + int getRequestedConfigurationOrientation() { + final int screenOrientation = getOrientation(); + if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { + // NOSENSOR means the display's "natural" orientation, so return that. + final ActivityDisplay display = getDisplay(); + if (display != null && display.mDisplayContent != null) { + return display.mDisplayContent.getNaturalOrientation(); + } + } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { + // LOCKED means the activity's orientation remains unchanged, so return existing value. + return getConfiguration().orientation; + } else if (isFixedOrientationLandscape(screenOrientation)) { + return ORIENTATION_LANDSCAPE; + } else if (isFixedOrientationPortrait(screenOrientation)) { + return ORIENTATION_PORTRAIT; + } + return ORIENTATION_UNDEFINED; + } + + /** + * Indicates the activity will keep the bounds and screen configuration when it was first + * launched, no matter how its parent changes. + * + * @return {@code true} if this activity is declared as non-resizable and fixed orientation or + * aspect ratio. + */ + private boolean inSizeCompatMode() { + return !isResizeable() && (info.isFixedOrientation() || info.hasFixedAspectRatio()) + // The configuration of non-standard type should be enforced by system. + && isActivityTypeStandard() + && !mAtmService.mForceResizableActivities; + } + // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer. private void updateOverrideConfiguration() { + final boolean inSizeCompatMode = inSizeCompatMode(); + if (inSizeCompatMode) { + if (!matchParentBounds()) { + // The override configuration is set only once in size compatible mode. + return; + } + if (!hasProcess() && !isConfigurationCompatible(task.getConfiguration())) { + // Don't compute when launching in fullscreen and the fixed orientation is not the + // current orientation. It is more accurately to compute the override bounds from + // the updated configuration after the fixed orientation is applied. + return; + } + } + computeBounds(mTmpBounds); + if (inSizeCompatMode && mTmpBounds.isEmpty()) { + mTmpBounds.set(task.getWindowConfiguration().getBounds()); + } if (mTmpBounds.equals(getRequestedOverrideBounds())) { + // The bounds is not changed or the activity is resizable (both the 2 bounds are empty). return; } - setBounds(mTmpBounds); - - // Bounds changed...update configuration to match. - if (!matchParentBounds()) { - mTmpConfig.setTo(getRequestedOverrideConfiguration()); - task.computeConfigResourceOverrides(mTmpConfig, task.getParent().getConfiguration()); - } else { - mTmpConfig.unset(); + final Configuration overrideConfig = mTmpConfig; + overrideConfig.unset(); + if (!mTmpBounds.isEmpty()) { + overrideConfig.windowConfiguration.setBounds(mTmpBounds); + if (inSizeCompatMode) { + // Ensure the screen related fields are set. It is used to prevent activity relaunch + // when moving between displays. For screenWidthDp and screenWidthDp, because they + // are relative to bounds and density, they will be calculated in + // {@link TaskRecord#computeConfigResourceOverrides} and the result will also be + // relatively fixed. + final Configuration srcConfig = task.getConfiguration(); + overrideConfig.colorMode = srcConfig.colorMode; + overrideConfig.densityDpi = srcConfig.densityDpi; + overrideConfig.screenLayout = srcConfig.screenLayout; + // The smallest screen width is the short side of screen bounds. Because the bounds + // and density won't be changed, smallestScreenWidthDp is also fixed. + overrideConfig.smallestScreenWidthDp = srcConfig.smallestScreenWidthDp; + } } - - onRequestedOverrideConfigurationChanged(mTmpConfig); + onRequestedOverrideConfigurationChanged(overrideConfig); } @Override @@ -2707,6 +2770,86 @@ final class ActivityRecord extends ConfigurationContainer { // layout traversals. mConfigurationSeq = Math.max(++mConfigurationSeq, 1); getResolvedOverrideConfiguration().seq = mConfigurationSeq; + + if (matchParentBounds()) { + return; + } + + final Configuration resolvedConfig = getResolvedOverrideConfiguration(); + if (!inSizeCompatMode()) { + computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, + ORIENTATION_UNDEFINED, true /* insideParentBounds */); + return; + } + + final Configuration displayConfig = getDisplay().getConfiguration(); + int orientation = getConfiguration().orientation; + if (orientation != displayConfig.orientation && isConfigurationCompatible(displayConfig)) { + // The activity is compatible to apply the orientation change or it requests different + // fixed orientation. + orientation = displayConfig.orientation; + } else { + if (resolvedConfig.windowConfiguration.getAppBounds() != null) { + // Keep the computed resolved override configuration. + return; + } + final int requestedOrientation = getRequestedConfigurationOrientation(); + if (requestedOrientation != ORIENTATION_UNDEFINED) { + orientation = requestedOrientation; + } + } + + // Adjust the bounds to match the current orientation. + if (orientation != ORIENTATION_UNDEFINED) { + final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); + final int longSide = Math.max(resolvedBounds.height(), resolvedBounds.width()); + final int shortSide = Math.min(resolvedBounds.height(), resolvedBounds.width()); + final boolean toBeLandscape = orientation == ORIENTATION_LANDSCAPE; + final int width = toBeLandscape ? longSide : shortSide; + final int height = toBeLandscape ? shortSide : longSide; + // Assume the bounds is always started from zero because the size may be bigger than its + // parent (task ~ display). The actual letterboxing will be done by surface offset. + resolvedBounds.set(0, 0, width, height); + } + + // In size compatible mode, activity is allowed to have larger bounds than its parent. + computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, orientation, + false /* insideParentBounds */); + } + + private void computeConfigResourceOverrides(Configuration inOutConfig, + Configuration parentConfig, int orientation, boolean insideParentBounds) { + // Set the real orientation or undefined value to ensure the output orientation won't be the + // old value. Also reset app bounds so it will be updated according to bounds. + inOutConfig.orientation = orientation; + final Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); + if (outAppBounds != null) { + outAppBounds.setEmpty(); + } + + // TODO(b/112288258): Remove below calculation because the position information in bounds + // will be replaced by the offset of surface. + final Rect appBounds = parentConfig.windowConfiguration.getAppBounds(); + if (appBounds != null) { + final Rect outBounds = inOutConfig.windowConfiguration.getBounds(); + final int activityWidth = outBounds.width(); + final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId()); + if (navBarPosition == NAV_BAR_LEFT) { + // Position the activity frame on the opposite side of the nav bar. + outBounds.left = appBounds.right - activityWidth; + outBounds.right = appBounds.right; + } else if (navBarPosition == NAV_BAR_RIGHT) { + // Position the activity frame on the opposite side of the nav bar. + outBounds.left = 0; + outBounds.right = activityWidth + appBounds.left; + } else if (appBounds.width() > activityWidth) { + // Horizontally center the frame. + outBounds.left = appBounds.left + (appBounds.width() - activityWidth) / 2; + outBounds.right = outBounds.left + activityWidth; + } + } + + task.computeConfigResourceOverrides(inOutConfig, parentConfig, insideParentBounds); } @Override @@ -2739,8 +2882,7 @@ final class ActivityRecord extends ConfigurationContainer { /** Returns true if the configuration is compatible with this activity. */ boolean isConfigurationCompatible(Configuration config) { - final int orientation = mAppWindowToken != null - ? getOrientation() : info.screenOrientation; + final int orientation = getOrientation(); if (isFixedOrientationPortrait(orientation) && config.orientation != ORIENTATION_PORTRAIT) { return false; @@ -2822,21 +2964,6 @@ final class ActivityRecord extends ConfigurationContainer { // away later in StackWindowController.adjustConfigurationForBounds(). Otherwise, the app // bounds would end up too small. outBounds.set(0, 0, activityWidth + appBounds.left, activityHeight + appBounds.top); - - final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId()); - if (navBarPosition == NAV_BAR_LEFT) { - // Position the activity frame on the opposite side of the nav bar. - outBounds.left = appBounds.right - activityWidth; - outBounds.right = appBounds.right; - } else if (navBarPosition == NAV_BAR_RIGHT) { - // Position the activity frame on the opposite side of the nav bar. - outBounds.left = 0; - outBounds.right = activityWidth + appBounds.left; - } else { - // Horizontally center the frame. - outBounds.left = appBounds.left + (containingAppWidth - activityWidth) / 2; - outBounds.right = outBounds.left + activityWidth; - } } /** diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 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/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 678a896bddbc..c33a2c179ab7 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -989,8 +989,8 @@ class ActivityStarter { if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) { return false; } - // don't abort if the callingPackage is a device owner - if (mService.getDevicePolicyManager().isDeviceOwnerApp(callingPackage)) { + // don't abort if the callingPackage is the device owner + if (mService.isDeviceOwner(callingPackage)) { return false; } // anything that has fallen through would currently be aborted diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 1a5e6a14e733..5a20959dcdbf 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -492,4 +492,9 @@ public abstract class ActivityTaskManagerInternal { /** Returns true if uid has a visible window or its process is in a top state. */ public abstract boolean isUidForeground(int uid); + + /** + * Called by DevicePolicyManagerService to set the package name of the device owner. + */ + public abstract void setDeviceOwnerPackageName(String deviceOwnerPkg); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 875fc4eab273..258819fdece9 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -151,7 +151,6 @@ import android.app.RemoteAction; import android.app.WaitResult; import android.app.WindowConfiguration; import android.app.admin.DevicePolicyCache; -import android.app.admin.DevicePolicyManager; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.app.usage.UsageStatsManagerInternal; @@ -363,7 +362,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { WindowManagerService mWindowManager; private UserManagerService mUserManager; private AppOpsService mAppOpsService; - private DevicePolicyManager mDpm; /** All active uids in the system. */ private final SparseArray<Integer> mActiveUids = new SparseArray<>(); private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>(); @@ -623,6 +621,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { private FontScaleSettingObserver mFontScaleSettingObserver; + private String mDeviceOwnerPackageName; + private final class FontScaleSettingObserver extends ContentObserver { private final Uri mFontScaleUri = Settings.System.getUriFor(FONT_SCALE); private final Uri mHideErrorDialogsUri = Settings.Global.getUriFor(HIDE_ERROR_DIALOGS); @@ -838,13 +838,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mAppOpsService; } - DevicePolicyManager getDevicePolicyManager() { - if (mDpm == null) { - mDpm = mContext.getSystemService(DevicePolicyManager.class); - } - return mDpm; - } - boolean hasUserRestriction(String restriction, int userId) { return getUserManager().hasUserRestriction(restriction, userId); } @@ -1720,7 +1713,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (r == null) { return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } - return r.getRequestedOrientation(); + return r.getOrientation(); } } @@ -2452,6 +2445,40 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } + @Override + public void offsetPinnedStackBounds(int stackId, Rect compareBounds, int xOffset, int yOffset, + int animationDuration) { + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "offsetPinnedStackBounds()"); + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + if (xOffset == 0 && yOffset == 0) { + return; + } + final ActivityStack stack = mRootActivityContainer.getStack(stackId); + if (stack == null) { + Slog.w(TAG, "offsetPinnedStackBounds: stackId " + stackId + " not found."); + return; + } + if (stack.getWindowingMode() != WINDOWING_MODE_PINNED) { + throw new IllegalArgumentException("Stack: " + stackId + + " doesn't support animated resize."); + } + final Rect destBounds = new Rect(); + stack.getAnimationOrCurrentBounds(destBounds); + if (!destBounds.isEmpty() || !destBounds.equals(compareBounds)) { + Slog.w(TAG, "The current stack bounds does not matched! It may be obsolete."); + return; + } + destBounds.offset(xOffset, yOffset); + stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds, + animationDuration, false /* fromFullscreen */); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } /** * Moves the specified task to the primary-split-screen stack. * @@ -5691,6 +5718,17 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { || mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid); } + boolean isDeviceOwner(String packageName) { + if (packageName == null) { + return false; + } + return packageName.equals(mDeviceOwnerPackageName); + } + + void setDeviceOwnerPackageName(String deviceOwnerPkg) { + mDeviceOwnerPackageName = deviceOwnerPkg; + } + /** * @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on * the whitelist @@ -7108,5 +7146,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return ActivityTaskManagerService.this.isUidForeground(uid); } } + + @Override + public void setDeviceOwnerPackageName(String deviceOwnerPkg) { + synchronized (mGlobalLock) { + ActivityTaskManagerService.this.setDeviceOwnerPackageName(deviceOwnerPkg); + } + } } } diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index bcf6abaac5da..88c8b953a2e9 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -239,6 +239,17 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>(); ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>(); + /** + * The scale to fit at least one side of the activity to its parent. If the activity uses + * 1920x1080, and the actually size on the screen is 960x540, then the scale is 0.5. + */ + private float mSizeCompatScale = 1f; + /** + * The bounds in global coordinates for activity in size compatibility mode. + * @see ActivityRecord#inSizeCompatMode + */ + private Rect mSizeCompatBounds; + private boolean mDisablePreviewScreenshots; private Task mLastParent; @@ -884,6 +895,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree dc.setFocusedApp(null); mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); } + if (mLetterbox != null) { + mLetterbox.destroy(); + mLetterbox = null; + } if (!delayed) { updateReportedVisibilityLocked(); @@ -1297,6 +1312,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } } } + + if (prevDc != mDisplayContent && mLetterbox != null) { + mLetterbox.onMovedToDisplay(mDisplayContent.getDisplayId()); + } } /** @@ -1555,11 +1574,52 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return mOrientation; } + /** @return {@code true} if the compatibility bounds is taking effect. */ + boolean inSizeCompatMode() { + return mSizeCompatBounds != null; + } + + @Override + float getSizeCompatScale() { + return inSizeCompatMode() ? mSizeCompatScale : super.getSizeCompatScale(); + } + + /** + * @return Non-empty bounds if the activity has override bounds. + * @see ActivityRecord#resolveOverrideConfiguration(Configuration) + */ + Rect getResolvedOverrideBounds() { + // Get bounds from resolved override configuration because it is computed with orientation. + return getResolvedOverrideConfiguration().windowConfiguration.getBounds(); + } + @Override public void onConfigurationChanged(Configuration newParentConfig) { final int prevWinMode = getWindowingMode(); mTmpPrevBounds.set(getBounds()); super.onConfigurationChanged(newParentConfig); + + final Task task = getTask(); + final Rect overrideBounds = getResolvedOverrideBounds(); + if (task != null && !overrideBounds.isEmpty() + // If the changes come from change-listener, the incoming parent configuration is + // still the old one. Make sure their orientations are the same to reduce computing + // the compatibility bounds for the intermediate state. + && getResolvedOverrideConfiguration().orientation == newParentConfig.orientation) { + final Rect taskBounds = task.getBounds(); + // Since we only center the activity horizontally, if only the fixed height is smaller + // than its container, the override bounds don't need to take effect. + if ((overrideBounds.width() != taskBounds.width() + || overrideBounds.height() > taskBounds.height())) { + calculateCompatBoundsTransformation(newParentConfig); + updateSurfacePosition(); + } else if (mSizeCompatBounds != null) { + mSizeCompatBounds = null; + mSizeCompatScale = 1f; + updateSurfacePosition(); + } + } + final int winMode = getWindowingMode(); if (prevWinMode == winMode) { @@ -1657,8 +1717,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree final ActivityManager.TaskSnapshot snapshot = snapshotCtrl.getSnapshot( getTask().mTaskId, getTask().mUserId, false /* restoreFromDisk */, false /* reducedResolution */); - mThumbnail = new AppWindowThumbnail(t, this, snapshot.getSnapshot(), - true /* relative */); + if (snapshot != null) { + mThumbnail = new AppWindowThumbnail(t, this, snapshot.getSnapshot(), + true /* relative */); + } } } @@ -1671,6 +1733,54 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return mThumbnail; } + /** + * Calculates the scale and offset to horizontal center the size compatibility bounds into the + * region which is available to application. + */ + private void calculateCompatBoundsTransformation(Configuration newParentConfig) { + final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds(); + final Rect viewportBounds = parentAppBounds != null + ? parentAppBounds : newParentConfig.windowConfiguration.getBounds(); + final Rect contentBounds = getResolvedOverrideBounds(); + final float contentW = contentBounds.width(); + final float contentH = contentBounds.height(); + final float viewportW = viewportBounds.width(); + final float viewportH = viewportBounds.height(); + // Only allow to scale down. + mSizeCompatScale = (contentW <= viewportW && contentH <= viewportH) + ? 1 : Math.min(viewportW / contentW, viewportH / contentH); + final int offsetX = (int) ((viewportW - contentW * mSizeCompatScale + 1) * 0.5f) + + viewportBounds.left; + + if (mSizeCompatBounds == null) { + mSizeCompatBounds = new Rect(); + } + mSizeCompatBounds.set(contentBounds); + mSizeCompatBounds.offsetTo(0, 0); + mSizeCompatBounds.scale(mSizeCompatScale); + mSizeCompatBounds.left += offsetX; + mSizeCompatBounds.right += offsetX; + } + + @Override + public Rect getBounds() { + if (mSizeCompatBounds != null) { + return mSizeCompatBounds; + } + return super.getBounds(); + } + + @Override + public boolean matchParentBounds() { + if (super.matchParentBounds()) { + return true; + } + // An activity in size compatibility mode may have override bounds which equals to its + // parent bounds, so the exact bounds should also be checked. + final WindowContainer parent = getParent(); + return parent == null || parent.getBounds().equals(getResolvedOverrideBounds()); + } + @Override void checkAppWindowsReadyToShow() { if (allDrawn == mLastAllDrawn) { @@ -1844,6 +1954,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (needsLetterbox) { if (mLetterbox == null) { mLetterbox = new Letterbox(() -> makeChildSurface(null)); + mLetterbox.attachInput(w); } getPosition(mTmpPoint); mLetterbox.layout(getParent().getBounds(), w.getFrameLw(), mTmpPoint); @@ -2864,6 +2975,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (mPendingRelaunchCount != 0) { pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount); } + if (mSizeCompatScale != 1f || mSizeCompatBounds != null) { + pw.println(prefix + "mSizeCompatScale=" + mSizeCompatScale + " mSizeCompatBounds=" + + mSizeCompatBounds); + } if (mRemovingFromDisplay) { pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay); } diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index 987492024546..d67193ea9e69 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -20,7 +20,15 @@ import static android.view.SurfaceControl.HIDDEN; import android.graphics.Point; import android.graphics.Rect; +import android.os.Binder; +import android.os.Process; +import android.view.InputChannel; +import android.view.InputEventReceiver; +import android.view.InputWindowHandle; import android.view.SurfaceControl; +import android.view.WindowManager; + +import com.android.server.UiThread; import java.util.function.Supplier; @@ -40,6 +48,7 @@ public class Letterbox { private final LetterboxSurface mLeft = new LetterboxSurface("left"); private final LetterboxSurface mBottom = new LetterboxSurface("bottom"); private final LetterboxSurface mRight = new LetterboxSurface("right"); + private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom }; /** * Constructs a Letterbox. @@ -87,8 +96,12 @@ public class Letterbox { * Returns true if any part of the letterbox overlaps with the given {@code rect}. */ public boolean isOverlappingWith(Rect rect) { - return mTop.isOverlappingWith(rect) || mLeft.isOverlappingWith(rect) - || mBottom.isOverlappingWith(rect) || mRight.isOverlappingWith(rect); + for (LetterboxSurface surface : mSurfaces) { + if (surface.isOverlappingWith(rect)) { + return true; + } + } + return false; } /** @@ -107,25 +120,94 @@ public class Letterbox { mOuter.setEmpty(); mInner.setEmpty(); - mTop.remove(); - mLeft.remove(); - mBottom.remove(); - mRight.remove(); + for (LetterboxSurface surface : mSurfaces) { + surface.remove(); + } } /** Returns whether a call to {@link #applySurfaceChanges} would change the surface. */ public boolean needsApplySurfaceChanges() { - return mTop.needsApplySurfaceChanges() - || mLeft.needsApplySurfaceChanges() - || mBottom.needsApplySurfaceChanges() - || mRight.needsApplySurfaceChanges(); + for (LetterboxSurface surface : mSurfaces) { + if (surface.needsApplySurfaceChanges()) { + return true; + } + } + return false; } public void applySurfaceChanges(SurfaceControl.Transaction t) { - mTop.applySurfaceChanges(t); - mLeft.applySurfaceChanges(t); - mBottom.applySurfaceChanges(t); - mRight.applySurfaceChanges(t); + for (LetterboxSurface surface : mSurfaces) { + surface.applySurfaceChanges(t); + } + } + + /** Enables touches to slide into other neighboring surfaces. */ + void attachInput(WindowState win) { + for (LetterboxSurface surface : mSurfaces) { + surface.attachInput(win); + } + } + + void onMovedToDisplay(int displayId) { + for (LetterboxSurface surface : mSurfaces) { + if (surface.mInputInterceptor != null) { + surface.mInputInterceptor.mWindowHandle.displayId = displayId; + } + } + } + + private static class InputInterceptor { + final InputChannel mServerChannel; + final InputChannel mClientChannel; + final InputWindowHandle mWindowHandle; + final InputEventReceiver mInputEventReceiver; + final WindowManagerService mWmService; + + InputInterceptor(String namePrefix, WindowState win) { + mWmService = win.mWmService; + final String name = namePrefix + (win.mAppToken != null ? win.mAppToken : win); + final InputChannel[] channels = InputChannel.openInputChannelPair(name); + mServerChannel = channels[0]; + mClientChannel = channels[1]; + mInputEventReceiver = new SimpleInputReceiver(mClientChannel); + + final Binder token = new Binder(); + mWmService.mInputManager.registerInputChannel(mServerChannel, token); + + mWindowHandle = new InputWindowHandle(null /* inputApplicationHandle */, + null /* clientWindow */, win.getDisplayId()); + mWindowHandle.name = name; + mWindowHandle.token = token; + mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH + | WindowManager.LayoutParams.FLAG_SLIPPERY; + mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER; + mWindowHandle.dispatchingTimeoutNanos = + WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; + mWindowHandle.visible = true; + mWindowHandle.ownerPid = Process.myPid(); + mWindowHandle.ownerUid = Process.myUid(); + mWindowHandle.scaleFactor = 1.0f; + } + + void updateTouchableRegion(Rect frame) { + mWindowHandle.touchableRegion.set(frame); + mWindowHandle.touchableRegion.translate(-frame.left, -frame.top); + } + + void dispose() { + mWmService.mInputManager.unregisterInputChannel(mServerChannel); + mInputEventReceiver.dispose(); + mServerChannel.dispose(); + mClientChannel.dispose(); + } + + private static class SimpleInputReceiver extends InputEventReceiver { + SimpleInputReceiver(InputChannel inputChannel) { + super(inputChannel, UiThread.getHandler().getLooper()); + } + } } private class LetterboxSurface { @@ -137,6 +219,8 @@ public class Letterbox { private final Rect mLayoutFrameGlobal = new Rect(); private final Rect mLayoutFrameRelative = new Rect(); + private InputInterceptor mInputInterceptor; + public LetterboxSurface(String type) { mType = type; } @@ -154,11 +238,22 @@ public class Letterbox { mSurface.setColor(new float[]{0, 0, 0}); } + void attachInput(WindowState win) { + if (mInputInterceptor != null) { + mInputInterceptor.dispose(); + } + mInputInterceptor = new InputInterceptor("Letterbox_" + mType + "_", win); + } + public void remove() { if (mSurface != null) { mSurface.remove(); mSurface = null; } + if (mInputInterceptor != null) { + mInputInterceptor.dispose(); + mInputInterceptor = null; + } } public int getWidth() { @@ -193,6 +288,10 @@ public class Letterbox { t.setPosition(mSurface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top); t.setWindowCrop(mSurface, mSurfaceFrameRelative.width(), mSurfaceFrameRelative.height()); + if (mInputInterceptor != null) { + mInputInterceptor.updateTouchableRegion(mSurfaceFrameRelative); + t.setInputWindowInfo(mSurface, mInputInterceptor.mWindowHandle); + } t.show(mSurface); } else if (mSurface != null) { t.hide(mSurface); diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 5ea24518370b..35b8641371be 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -251,7 +251,7 @@ class SurfaceAnimator { if (DEBUG_ANIM) Slog.i(TAG, "Cancelling animation restarting=" + restarting); final SurfaceControl leash = mLeash; final AnimationAdapter animation = mAnimation; - reset(t, forwardCancel); + reset(t, false); if (animation != null) { if (!mAnimationStartDelayed && forwardCancel) { animation.onAnimationCancelled(leash); @@ -260,6 +260,12 @@ class SurfaceAnimator { mAnimationFinishedCallback.run(); } } + + if (forwardCancel && leash != null) { + t.remove(leash); + mService.scheduleAnimationLocked(); + } + if (!restarting) { mAnimationStartDelayed = false; } diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index 69f0012b69ba..59d7560fc5b0 100644 --- a/services/core/java/com/android/server/wm/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -119,6 +119,7 @@ import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Slog; import android.util.proto.ProtoOutputStream; +import android.view.Display; import android.view.DisplayInfo; import com.android.internal.annotations.VisibleForTesting; @@ -1288,22 +1289,7 @@ class TaskRecord extends ConfigurationContainer { || top == null) { return getRequestedOverrideConfiguration().orientation; } - int screenOrientation = top.getOrientation(); - if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { - // NOSENSOR means the display's "natural" orientation, so return that. - ActivityDisplay display = mStack != null ? mStack.getDisplay() : null; - if (display != null && display.mDisplayContent != null) { - return mStack.getDisplay().mDisplayContent.getNaturalOrientation(); - } - } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { - // LOCKED means the activity's orientation remains unchanged, so return existing value. - return top.getConfiguration().orientation; - } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) { - return ORIENTATION_LANDSCAPE; - } else if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) { - return ORIENTATION_PORTRAIT; - } - return ORIENTATION_UNDEFINED; + return top.getRequestedConfigurationOrientation(); } /** @@ -2084,6 +2070,11 @@ class TaskRecord extends ConfigurationContainer { return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; } + void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, + @NonNull Configuration parentConfig) { + computeConfigResourceOverrides(inOutConfig, parentConfig, true /* insideParentBounds */); + } + /** * Calculates configuration values used by the client to get resources. This should be run * using app-facing bounds (bounds unmodified by animations or transient interactions). @@ -2093,7 +2084,7 @@ class TaskRecord extends ConfigurationContainer { * just be inherited from the parent configuration. **/ void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, - @NonNull Configuration parentConfig) { + @NonNull Configuration parentConfig, boolean insideParentBounds) { int windowingMode = inOutConfig.windowConfiguration.getWindowingMode(); if (windowingMode == WINDOWING_MODE_UNDEFINED) { windowingMode = parentConfig.windowConfiguration.getWindowingMode(); @@ -2111,7 +2102,7 @@ class TaskRecord extends ConfigurationContainer { inOutConfig.windowConfiguration.setAppBounds(bounds); outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); } - if (windowingMode != WINDOWING_MODE_FREEFORM) { + if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) { final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds(); if (parentAppBounds != null && !parentAppBounds.isEmpty()) { outAppBounds.intersect(parentAppBounds); @@ -2120,7 +2111,7 @@ class TaskRecord extends ConfigurationContainer { if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { - if (mStack != null) { + if (insideParentBounds && mStack != null) { final DisplayInfo di = new DisplayInfo(); mStack.getDisplay().mDisplay.getDisplayInfo(di); @@ -2135,12 +2126,16 @@ class TaskRecord extends ConfigurationContainer { } if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) { - inOutConfig.screenWidthDp = Math.min((int) (mTmpStableBounds.width() / density), - parentConfig.screenWidthDp); + final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density); + inOutConfig.screenWidthDp = insideParentBounds + ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp) + : overrideScreenWidthDp; } if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { - inOutConfig.screenHeightDp = Math.min((int) (mTmpStableBounds.height() / density), - parentConfig.screenHeightDp); + final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density); + inOutConfig.screenHeightDp = insideParentBounds + ? Math.min(overrideScreenHeightDp, parentConfig.screenWidthDp) + : overrideScreenHeightDp; } if (inOutConfig.smallestScreenWidthDp @@ -2162,7 +2157,7 @@ class TaskRecord extends ConfigurationContainer { if (inOutConfig.orientation == ORIENTATION_UNDEFINED) { inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp) - ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; + ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; } if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) { // For calculating screen layout, we need to use the non-decor inset screen area for the @@ -2332,6 +2327,7 @@ class TaskRecord extends ConfigurationContainer { info.userId = userId; info.stackId = getStackId(); info.taskId = taskId; + info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId; info.isRunning = getTopActivity() != null; info.baseIntent = new Intent(getBaseIntent()); info.baseActivity = reuseActivitiesReport.base != null diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 00105be87cd4..c747c6d95fcd 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -47,7 +47,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; @@ -1839,6 +1838,9 @@ public class WindowManagerService extends IWindowManager.Stub return; } outDisplayFrame.set(win.getDisplayFrameLw()); + if (win.inSizeCompatMode()) { + outDisplayFrame.scale(win.mInvGlobalScale); + } } } @@ -1963,8 +1965,6 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Relayout " + win + ": viewVisibility=" + viewVisibility + " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs); winAnimator.mSurfaceDestroyDeferred = (flags & RELAYOUT_DEFER_SURFACE_DESTROY) != 0; - win.mEnforceSizeCompat = - (win.mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0; if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) { winAnimator.mAlpha = attrs.alpha; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 85b251a99f83..48cd6b68c416 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -246,7 +246,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final boolean mIsWallpaper; private final boolean mIsFloatingLayer; int mSeq; - boolean mEnforceSizeCompat; int mViewVisibility; int mSystemUiVisibility; /** @@ -505,7 +504,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ private PowerManager.WakeLock mDrawLock; - final private Rect mTmpRect = new Rect(); + private final Rect mTmpRect = new Rect(); + private final Point mTmpPoint = new Point(); /** * Whether the window was resized by us while it was gone for layout. @@ -655,7 +655,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mContext = mWmService.mContext; DeathRecipient deathRecipient = new DeathRecipient(); mSeq = seq; - mEnforceSizeCompat = (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0; mPowerManagerWrapper = powerManagerWrapper; mForceSeamlesslyRotate = token.mRoundedCornerOverlay; if (localLOGV) Slog.v( @@ -733,6 +732,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } /** + * @return {@code true} if the application runs in size compatibility mode. + * @see android.content.res.CompatibilityInfo#supportsScreen + * @see ActivityRecord#inSizeCompatMode + */ + boolean inSizeCompatMode() { + return (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0 + || (mAppToken != null && mAppToken.inSizeCompatMode() + // Exclude starting window because it is not displayed by the application. + && mAttrs.type != TYPE_APPLICATION_STARTING); + } + + /** * Returns whether this {@link WindowState} has been considered for drawing by its parent. */ boolean getDrawnStateEvaluated() { @@ -995,7 +1006,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mWindowFrames.offsetFrames(-layoutXDiff, -layoutYDiff); mWindowFrames.mCompatFrame.set(mWindowFrames.mFrame); - if (mEnforceSizeCompat) { + if (inSizeCompatMode()) { // If there is a size compatibility scale being applied to the // window, we need to apply this to its insets so that they are // reported to the app in its coordinate space. @@ -1354,8 +1365,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } void prelayout() { - if (mEnforceSizeCompat) { - mGlobalScale = getDisplayContent().mCompatibleScreenScale; + if (inSizeCompatMode()) { + mGlobalScale = mToken.getSizeCompatScale(); mInvGlobalScale = 1 / mGlobalScale; } else { mGlobalScale = mInvGlobalScale = 1; @@ -2145,6 +2156,30 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP int getSurfaceTouchableRegion(Region region, int flags) { final boolean modal = (flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0; + if (mAppToken != null && !mAppToken.getResolvedOverrideBounds().isEmpty()) { + // There may have touchable letterboxes around the activity, so in order to let the + // letterboxes are able to receive touch event and slip to activity, the activity with + // compatibility bounds cannot occupy full screen touchable region. + if (modal) { + // A modal window uses the whole compatibility bounds. + flags |= FLAG_NOT_TOUCH_MODAL; + mTmpRect.set(mAppToken.getResolvedOverrideBounds()); + // TODO(b/112288258): Remove the forced offset when the override bounds always + // starts from zero (See {@link ActivityRecord#resolveOverrideConfiguration}). + mTmpRect.offsetTo(0, 0); + } else { + // Non-modal uses the application based frame. + mTmpRect.set(mWindowFrames.mCompatFrame); + } + // The offset of compatibility bounds is applied to surface of {@link #AppWindowToken} + // and frame, so it is unnecessary to translate twice in surface based coordinates. + final int surfaceOffsetX = mAppToken.inSizeCompatMode() + ? mAppToken.getBounds().left : 0; + mTmpRect.offset(surfaceOffsetX - mWindowFrames.mFrame.left, -mWindowFrames.mFrame.top); + region.set(mTmpRect); + return flags; + } + if (modal && mAppToken != null) { // Limit the outer touch to the activity stack region. flags |= FLAG_NOT_TOUCH_MODAL; @@ -2943,7 +2978,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == DRAW_PENDING) Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING"); - final Rect frame = mWindowFrames.mFrame; + final Rect frame = mWindowFrames.mCompatFrame; final Rect overscanInsets = mWindowFrames.mLastOverscanInsets; final Rect contentInsets = mWindowFrames.mLastContentInsets; final Rect visibleInsets = mWindowFrames.mLastVisibleInsets; @@ -3353,7 +3388,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP pw.println(prefix + "mHasSurface=" + mHasSurface + " isReadyForDisplay()=" + isReadyForDisplay() + " mWindowRemovalAllowed=" + mWindowRemovalAllowed); - if (mEnforceSizeCompat) { + if (inSizeCompatMode()) { pw.println(prefix + "mCompatFrame=" + mWindowFrames.mCompatFrame.toShortString(sTmpSB)); } if (dumpAll) { @@ -3477,17 +3512,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP float x, y; int w,h; + final boolean inSizeCompatMode = inSizeCompatMode(); if ((mAttrs.flags & FLAG_SCALED) != 0) { if (mAttrs.width < 0) { w = pw; - } else if (mEnforceSizeCompat) { + } else if (inSizeCompatMode) { w = (int)(mAttrs.width * mGlobalScale + .5f); } else { w = mAttrs.width; } if (mAttrs.height < 0) { h = ph; - } else if (mEnforceSizeCompat) { + } else if (inSizeCompatMode) { h = (int)(mAttrs.height * mGlobalScale + .5f); } else { h = mAttrs.height; @@ -3495,21 +3531,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } else { if (mAttrs.width == MATCH_PARENT) { w = pw; - } else if (mEnforceSizeCompat) { + } else if (inSizeCompatMode) { w = (int)(mRequestedWidth * mGlobalScale + .5f); } else { w = mRequestedWidth; } if (mAttrs.height == MATCH_PARENT) { h = ph; - } else if (mEnforceSizeCompat) { + } else if (inSizeCompatMode) { h = (int)(mRequestedHeight * mGlobalScale + .5f); } else { h = mRequestedHeight; } } - if (mEnforceSizeCompat) { + if (inSizeCompatMode) { x = mAttrs.x * mGlobalScale; y = mAttrs.y * mGlobalScale; } else { @@ -3537,7 +3573,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // We need to make sure we update the CompatFrame as it is used for // cropping decisions, etc, on systems where we lack a decor layer. mWindowFrames.mCompatFrame.set(mWindowFrames.mFrame); - if (mEnforceSizeCompat) { + if (inSizeCompatMode) { // See comparable block in computeFrameLw. mWindowFrames.mCompatFrame.scale(mInvGlobalScale); } @@ -3650,7 +3686,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP float translateToWindowX(float x) { float winX = x - mWindowFrames.mFrame.left; - if (mEnforceSizeCompat) { + if (inSizeCompatMode()) { winX *= mGlobalScale; } return winX; @@ -3658,7 +3694,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP float translateToWindowY(float y) { float winY = y - mWindowFrames.mFrame.top; - if (mEnforceSizeCompat) { + if (inSizeCompatMode()) { winY *= mGlobalScale; } return winY; @@ -4233,12 +4269,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ void calculatePolicyCrop(Rect policyCrop) { final DisplayContent displayContent = getDisplayContent(); - final DisplayInfo displayInfo = displayContent.getDisplayInfo(); - if (!isDefaultDisplay()) { + if (!displayContent.isDefaultDisplay && !displayContent.supportsSystemDecorations()) { // On a different display there is no system decor. Crop the window // by the screen boundaries. - // TODO(multi-display) + final DisplayInfo displayInfo = displayContent.getDisplayInfo(); policyCrop.set(0, 0, mWindowFrames.mCompatFrame.width(), mWindowFrames.mCompatFrame.height()); policyCrop.intersect(-mWindowFrames.mCompatFrame.left, -mWindowFrames.mCompatFrame.top, @@ -4304,7 +4339,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // scale function because we want to round things to make the crop // always round to a larger rect to ensure we don't crop too // much and hide part of the window that should be seen. - if (mEnforceSizeCompat && mInvGlobalScale != 1.0f) { + if (inSizeCompatMode() && mInvGlobalScale != 1.0f) { final float scale = mInvGlobalScale; systemDecorRect.left = (int) (systemDecorRect.left * scale - 0.5f); systemDecorRect.top = (int) (systemDecorRect.top * scale - 0.5f); @@ -4664,8 +4699,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Since the parent was outset by its surface insets, we need to undo the outsetting // with insetting by the same amount. final WindowState parent = getParentWindow(); - outPoint.offset(-parent.mWindowFrames.mFrame.left + parent.mAttrs.surfaceInsets.left, - -parent.mWindowFrames.mFrame.top + parent.mAttrs.surfaceInsets.top); + transformSurfaceInsetsPosition(mTmpPoint, parent.mAttrs.surfaceInsets); + outPoint.offset(-parent.mWindowFrames.mFrame.left + mTmpPoint.x, + -parent.mWindowFrames.mFrame.top + mTmpPoint.y); } else if (parentWindowContainer != null) { final Rect parentBounds = parentWindowContainer.getDisplayedBounds(); outPoint.offset(-parentBounds.left, -parentBounds.top); @@ -4683,7 +4719,22 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } // Expand for surface insets. See WindowState.expandForSurfaceInsets. - outPoint.offset(-mAttrs.surfaceInsets.left, -mAttrs.surfaceInsets.top); + transformSurfaceInsetsPosition(mTmpPoint, mAttrs.surfaceInsets); + outPoint.offset(-mTmpPoint.x, -mTmpPoint.y); + } + + /** + * The surface insets from layout parameter are in application coordinate. If the window is + * scaled, the insets also need to be scaled for surface position in global coordinate. + */ + private void transformSurfaceInsetsPosition(Point outPos, Rect surfaceInsets) { + if (!inSizeCompatMode()) { + outPos.x = surfaceInsets.left; + outPos.y = surfaceInsets.top; + return; + } + outPos.x = (int) (surfaceInsets.left * mGlobalScale + 0.5f); + outPos.y = (int) (surfaceInsets.top * mGlobalScale + 0.5f); } boolean needsRelativeLayeringToIme() { diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 3b9b8bab9e61..f0b9c62f2843 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -182,6 +182,14 @@ class WindowToken extends WindowContainer<WindowState> { } /** + * @return The scale for applications running in compatibility mode. Multiply the size in the + * application by this scale will be the size in the screen. + */ + float getSizeCompatScale() { + return mDisplayContent.mCompatibleScreenScale; + } + + /** * Returns true if the new window is considered greater than the existing window in terms of * z-order. */ diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index e30acf71d328..093ac89b97c0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -247,6 +247,7 @@ import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.pm.UserRestrictionsUtils; import com.android.server.storage.DeviceStorageMonitorInternal; import com.android.server.uri.UriGrantsManagerInternal; +import com.android.server.wm.ActivityTaskManagerInternal; import com.google.android.collect.Sets; @@ -1870,7 +1871,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Owners newOwners() { return new Owners(getUserManager(), getUserManagerInternal(), - getPackageManagerInternal()); + getPackageManagerInternal(), getActivityTaskManagerInternal()); } UserManager getUserManager() { @@ -1885,6 +1886,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return LocalServices.getService(PackageManagerInternal.class); } + ActivityTaskManagerInternal getActivityTaskManagerInternal() { + return LocalServices.getService(ActivityTaskManagerInternal.class); + } + UsageStatsManagerInternal getUsageStatsManagerInternal() { return LocalServices.getService(UsageStatsManagerInternal.class); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java index ee1c1df3f162..27cd70c9a606 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java @@ -41,6 +41,7 @@ import android.util.Xml; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FastXmlSerializer; import com.android.server.LocalServices; +import com.android.server.wm.ActivityTaskManagerInternal; import libcore.io.IoUtils; @@ -104,6 +105,7 @@ class Owners { private final UserManager mUserManager; private final UserManagerInternal mUserManagerInternal; private final PackageManagerInternal mPackageManagerInternal; + private final ActivityTaskManagerInternal mActivityTaskManagerInternal; private boolean mSystemReady; @@ -129,18 +131,22 @@ class Owners { public Owners(UserManager userManager, UserManagerInternal userManagerInternal, - PackageManagerInternal packageManagerInternal) { - this(userManager, userManagerInternal, packageManagerInternal, new Injector()); + PackageManagerInternal packageManagerInternal, + ActivityTaskManagerInternal activityTaskManagerInternal) { + this(userManager, userManagerInternal, packageManagerInternal, + activityTaskManagerInternal, new Injector()); } @VisibleForTesting Owners(UserManager userManager, UserManagerInternal userManagerInternal, PackageManagerInternal packageManagerInternal, + ActivityTaskManagerInternal activityTaskManagerInternal, Injector injector) { mUserManager = userManager; mUserManagerInternal = userManagerInternal; mPackageManagerInternal = packageManagerInternal; + mActivityTaskManagerInternal = activityTaskManagerInternal; mInjector = injector; } @@ -187,6 +193,7 @@ class Owners { getDeviceOwnerUserId())); } pushToPackageManagerLocked(); + pushToActivityTaskManagerLocked(); pushToAppOpsLocked(); } } @@ -201,6 +208,11 @@ class Owners { po); } + private void pushToActivityTaskManagerLocked() { + mActivityTaskManagerInternal.setDeviceOwnerPackageName(mDeviceOwner != null + ? mDeviceOwner.packageName : null); + } + String getDeviceOwnerPackageName() { synchronized (mLock) { return mDeviceOwner != null ? mDeviceOwner.packageName : null; @@ -275,6 +287,7 @@ class Owners { mUserManagerInternal.setDeviceManaged(true); pushToPackageManagerLocked(); + pushToActivityTaskManagerLocked(); pushToAppOpsLocked(); } } @@ -286,6 +299,7 @@ class Owners { mUserManagerInternal.setDeviceManaged(false); pushToPackageManagerLocked(); + pushToActivityTaskManagerLocked(); pushToAppOpsLocked(); } } @@ -333,6 +347,7 @@ class Owners { mDeviceOwner.remoteBugreportHash, /* canAccessDeviceIds =*/ mDeviceOwner.canAccessDeviceIds); pushToPackageManagerLocked(); + pushToActivityTaskManagerLocked(); pushToAppOpsLocked(); } } diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java index 4354db72554a..24e5573b891d 100644 --- a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java +++ b/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,7 +11,7 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ package com.android.server.backup.encryption.chunk; @@ -36,7 +36,7 @@ import java.util.Arrays; @RunWith(RobolectricTestRunner.class) @Presubmit -public class ChunkListingTest { +public class ChunkListingMapTest { private static final String CHUNK_A = "CHUNK_A"; private static final String CHUNK_B = "CHUNK_B"; private static final String CHUNK_C = "CHUNK_C"; @@ -62,13 +62,13 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - boolean chunkAInList = chunkListing.hasChunk(mChunkHashA); - boolean chunkBInList = chunkListing.hasChunk(mChunkHashB); - boolean chunkCInList = chunkListing.hasChunk(mChunkHashC); + boolean chunkAInList = chunkListingMap.hasChunk(mChunkHashA); + boolean chunkBInList = chunkListingMap.hasChunk(mChunkHashB); + boolean chunkCInList = chunkListingMap.hasChunk(mChunkHashC); assertThat(chunkAInList).isTrue(); assertThat(chunkBInList).isTrue(); @@ -81,13 +81,13 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); ChunkHash chunkHashEmpty = getHash(""); - boolean chunkCInList = chunkListing.hasChunk(mChunkHashC); - boolean emptyChunkInList = chunkListing.hasChunk(chunkHashEmpty); + boolean chunkCInList = chunkListingMap.hasChunk(mChunkHashC); + boolean emptyChunkInList = chunkListingMap.hasChunk(chunkHashEmpty); assertThat(chunkCInList).isFalse(); assertThat(emptyChunkInList).isFalse(); @@ -99,13 +99,13 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA); - ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB); - ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC); + ChunkListingMap.Entry entryA = chunkListingMap.getChunkEntry(mChunkHashA); + ChunkListingMap.Entry entryB = chunkListingMap.getChunkEntry(mChunkHashB); + ChunkListingMap.Entry entryC = chunkListingMap.getChunkEntry(mChunkHashC); assertThat(entryA.getLength()).isEqualTo(CHUNK_A_LENGTH); assertThat(entryB.getLength()).isEqualTo(CHUNK_B_LENGTH); @@ -118,13 +118,13 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA); - ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB); - ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC); + ChunkListingMap.Entry entryA = chunkListingMap.getChunkEntry(mChunkHashA); + ChunkListingMap.Entry entryB = chunkListingMap.getChunkEntry(mChunkHashB); + ChunkListingMap.Entry entryC = chunkListingMap.getChunkEntry(mChunkHashC); assertThat(entryA.getStart()).isEqualTo(0); assertThat(entryB.getStart()).isEqualTo(CHUNK_A_LENGTH); @@ -137,22 +137,24 @@ public class ChunkListingTest { createChunkListingProto( new ChunkHash[] {mChunkHashA, mChunkHashB}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - ChunkListing.Entry chunkEntryNonexistentChunk = chunkListing.getChunkEntry(mChunkHashC); + ChunkListingMap.Entry chunkEntryNonexistentChunk = + chunkListingMap.getChunkEntry(mChunkHashC); assertThat(chunkEntryNonexistentChunk).isNull(); } @Test - public void testReadFromProto_whenEmptyProto_returnsChunkListingWith0Chunks() throws Exception { + public void testReadFromProto_whenEmptyProto_returnsChunkListingMapWith0Chunks() + throws Exception { ProtoInputStream emptyProto = new ProtoInputStream(new ByteArrayInputStream(new byte[] {})); - ChunkListing chunkListing = ChunkListing.readFromProto(emptyProto); + ChunkListingMap chunkListingMap = ChunkListingMap.readFromProto(emptyProto); - assertThat(chunkListing.getChunkCount()).isEqualTo(0); + assertThat(chunkListingMap.getChunkCount()).isEqualTo(0); } @Test @@ -162,11 +164,11 @@ public class ChunkListingTest { new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); - ChunkListing chunkListing = - ChunkListing.readFromProto( + ChunkListingMap chunkListingMap = + ChunkListingMap.readFromProto( new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); - assertThat(chunkListing.getChunkCount()).isEqualTo(3); + assertThat(chunkListingMap.getChunkCount()).isEqualTo(3); } private byte[] createChunkListingProto(ChunkHash[] hashes, int[] lengths) { diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java index 53d72bb9a415..e51ee947cba1 100644 --- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java @@ -19,6 +19,7 @@ import static androidx.test.InstrumentationRegistry.getContext; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -51,6 +52,9 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; import android.app.ActivityManagerInternal; import android.app.AlarmManager; @@ -82,6 +86,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; @@ -105,6 +110,8 @@ public class DeviceIdleControllerTest { @Mock private ContentResolver mContentResolver; @Mock + private DeviceIdleController.MyHandler mHandler; + @Mock private IActivityManager mIActivityManager; @Mock private LocationManager mLocationManager; @@ -154,7 +161,7 @@ public class DeviceIdleControllerTest { @Override DeviceIdleController.MyHandler getHandler(DeviceIdleController controller) { - return mock(DeviceIdleController.MyHandler.class, Answers.RETURNS_DEEP_STUBS); + return mHandler; } @Override @@ -232,10 +239,12 @@ public class DeviceIdleControllerTest { .when(() -> LocalServices.getService(ActivityManagerInternal.class)); doReturn(mock(ActivityTaskManagerInternal.class)) .when(() -> LocalServices.getService(ActivityTaskManagerInternal.class)); + doReturn(mock(AlarmManagerInternal.class)) + .when(() -> LocalServices.getService(AlarmManagerInternal.class)); doReturn(mPowerManagerInternal) .when(() -> LocalServices.getService(PowerManagerInternal.class)); - when(mPowerManagerInternal.getLowPowerState(anyInt())).thenReturn( - mock(PowerSaveState.class)); + when(mPowerManagerInternal.getLowPowerState(anyInt())) + .thenReturn(mock(PowerSaveState.class)); doReturn(mock(NetworkPolicyManagerInternal.class)) .when(() -> LocalServices.getService(NetworkPolicyManagerInternal.class)); when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock); @@ -246,8 +255,11 @@ public class DeviceIdleControllerTest { doReturn(true).when(mSensorManager).registerListener(any(), any(), anyInt()); mAppStateTracker = new AppStateTrackerForTest(getContext(), Looper.getMainLooper()); mAnyMotionDetector = new AnyMotionDetectorForTest(); + mHandler = mock(DeviceIdleController.MyHandler.class, Answers.RETURNS_DEEP_STUBS); + doNothing().when(mHandler).handleMessage(any()); mInjector = new InjectorForTest(getContext()); doNothing().when(mContentResolver).registerContentObserver(any(), anyBoolean(), any()); + mDeviceIdleController = new DeviceIdleController(getContext(), mInjector); spyOn(mDeviceIdleController); doNothing().when(mDeviceIdleController).publishBinderService(any(), any()); @@ -423,6 +435,29 @@ public class DeviceIdleControllerTest { mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyStateConditions(STATE_ACTIVE); + + mConstants.WAIT_FOR_UNLOCK = false; + setScreenLocked(true); + setScreenOn(true); + setChargingOn(false); + + mDeviceIdleController.becomeInactiveIfAppropriateLocked(); + verifyStateConditions(STATE_ACTIVE); + + setScreenLocked(false); + setScreenOn(true); + setChargingOn(false); + + mDeviceIdleController.becomeInactiveIfAppropriateLocked(); + verifyStateConditions(STATE_ACTIVE); + + mConstants.WAIT_FOR_UNLOCK = true; + setScreenLocked(false); + setScreenOn(true); + setChargingOn(false); + + mDeviceIdleController.becomeInactiveIfAppropriateLocked(); + verifyStateConditions(STATE_ACTIVE); } @Test @@ -1307,7 +1342,7 @@ public class DeviceIdleControllerTest { } @Test - public void testbecomeActiveLocked_deep() { + public void testBecomeActiveLocked_deep() { // becomeActiveLocked should put everything into ACTIVE. enterDeepState(STATE_ACTIVE); @@ -1344,7 +1379,7 @@ public class DeviceIdleControllerTest { } @Test - public void testbecomeActiveLocked_light() { + public void testBecomeActiveLocked_light() { // becomeActiveLocked should put everything into ACTIVE. enterLightState(LIGHT_STATE_ACTIVE); @@ -1376,6 +1411,163 @@ public class DeviceIdleControllerTest { verifyLightStateConditions(LIGHT_STATE_ACTIVE); } + /** Test based on b/119058625. */ + @Test + public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOn_ScreenThenMotion() { + mConstants.WAIT_FOR_UNLOCK = true; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + mDeviceIdleController.keyguardShowingLocked(true); + setScreenOn(true); + // With WAIT_FOR_UNLOCK = true and the screen locked, turning the screen on by itself + // shouldn't bring the device out of deep IDLE. + verifyStateConditions(STATE_IDLE); + mDeviceIdleController.handleMotionDetectedLocked(1000, "test"); + // Motion should bring the device out of Doze. Since the screen is still locked (albeit + // on), the states should go back into INACTIVE. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt()); + } + + /** Test based on b/119058625. */ + @Test + public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOff_ScreenThenMotion() { + mConstants.WAIT_FOR_UNLOCK = true; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + mDeviceIdleController.keyguardShowingLocked(false); + setScreenOn(true); + // With WAIT_FOR_UNLOCK = true and the screen unlocked, turning the screen on by itself + // should bring the device out of deep IDLE. + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt()); + } + + /** Test based on b/119058625. */ + @Test + public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOn_MotionThenScreen() { + mConstants.WAIT_FOR_UNLOCK = true; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + InOrder alarmManagerInOrder = inOrder(mAlarmManager); + InOrder controllerInOrder = inOrder(mDeviceIdleController); + + mDeviceIdleController.keyguardShowingLocked(true); + mDeviceIdleController.handleMotionDetectedLocked(1000, "test"); + // The screen is still off, so motion should result in the INACTIVE state. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + + setScreenOn(true); + // With WAIT_FOR_UNLOCK = true and the screen locked, turning the screen on by itself + // shouldn't bring the device all the way to ACTIVE. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + alarmManagerInOrder.verify(mAlarmManager, never()).cancel( + eq(mDeviceIdleController.mDeepAlarmListener)); + + // User finally unlocks the device. Device should be fully active. + mDeviceIdleController.keyguardShowingLocked(false); + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + } + + /** Test based on b/119058625. */ + @Test + public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOff_MotionThenScreen() { + mConstants.WAIT_FOR_UNLOCK = true; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + InOrder alarmManagerInOrder = inOrder(mAlarmManager); + InOrder controllerInOrder = inOrder(mDeviceIdleController); + + mDeviceIdleController.keyguardShowingLocked(false); + mDeviceIdleController.handleMotionDetectedLocked(1000, "test"); + // The screen is still off, so motion should result in the INACTIVE state. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + + setScreenOn(true); + // With WAIT_FOR_UNLOCK = true and the screen unlocked, turning the screen on by itself + // should bring the device out of deep IDLE. + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + } + + @Test + public void testExitNotifiesDependencies_WaitForUnlockOff_Screen() { + mConstants.WAIT_FOR_UNLOCK = false; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + setScreenOn(true); + // With WAIT_FOR_UNLOCK = false and the screen locked, turning the screen on by itself + // should bring the device out of deep IDLE. + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt()); + } + + @Test + public void testExitNotifiesDependencies_WaitForUnlockOff_MotionThenScreen() { + mConstants.WAIT_FOR_UNLOCK = false; + enterDeepState(STATE_IDLE); + reset(mAlarmManager); + spyOn(mDeviceIdleController); + + InOrder alarmManagerInOrder = inOrder(mAlarmManager); + InOrder controllerInOrder = inOrder(mDeviceIdleController); + + mDeviceIdleController.handleMotionDetectedLocked(1000, "test"); + // The screen is still off, so motion should result in the INACTIVE state. + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + + setScreenOn(true); + // With WAIT_FOR_UNLOCK = false and the screen locked, turning the screen on by itself + // should bring the device out of deep IDLE. + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + alarmManagerInOrder.verify(mAlarmManager) + .cancel(eq(mDeviceIdleController.mDeepAlarmListener)); + controllerInOrder.verify(mDeviceIdleController) + .scheduleReportActiveLocked(anyString(), anyInt()); + } + @Test public void testStepToIdleMode() { float delta = mDeviceIdleController.MIN_PRE_IDLE_FACTOR_CHANGE; @@ -1508,6 +1700,10 @@ public class DeviceIdleControllerTest { mDeviceIdleController.updateChargingLocked(on); } + private void setScreenLocked(boolean locked) { + mDeviceIdleController.keyguardShowingLocked(locked); + } + private void setScreenOn(boolean on) { doReturn(on).when(mPowerManager).isInteractive(); mDeviceIdleController.updateInteractivityLocked(); @@ -1549,7 +1745,8 @@ public class DeviceIdleControllerTest { assertFalse(mDeviceIdleController.mMotionListener.isActive()); assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_IDLE_PENDING: assertEquals( @@ -1557,7 +1754,8 @@ public class DeviceIdleControllerTest { mDeviceIdleController.mMotionListener.isActive()); assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_SENSING: assertEquals( @@ -1567,14 +1765,16 @@ public class DeviceIdleControllerTest { mDeviceIdleController.hasMotionSensor(), mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_LOCATING: assertEquals( mDeviceIdleController.hasMotionSensor(), mDeviceIdleController.mMotionListener.isActive()); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_IDLE: if (mDeviceIdleController.hasMotionSensor()) { @@ -1584,7 +1784,8 @@ public class DeviceIdleControllerTest { } assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); // Light state should be OVERRIDE at this point. verifyLightStateConditions(LIGHT_STATE_OVERRIDE); break; @@ -1596,14 +1797,16 @@ public class DeviceIdleControllerTest { } assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; case STATE_QUICK_DOZE_DELAY: // If quick doze is enabled, the motion listener should NOT be active. assertFalse(mDeviceIdleController.mMotionListener.isActive()); assertFalse(mAnyMotionDetector.isMonitoring); assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; default: fail("Conditions for " + stateToString(expectedState) + " unknown."); @@ -1632,7 +1835,8 @@ public class DeviceIdleControllerTest { case LIGHT_STATE_IDLE_MAINTENANCE: case LIGHT_STATE_OVERRIDE: assertFalse(mDeviceIdleController.isCharging()); - assertFalse(mDeviceIdleController.isScreenOn()); + assertFalse(mDeviceIdleController.isScreenOn() + && !mDeviceIdleController.isKeyguardShowing()); break; default: fail("Conditions for " + lightStateToString(expectedLightState) + " unknown."); diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index dc31c0f7ebbb..fce7599d0b59 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -66,6 +66,8 @@ <uses-permission android:name="android.permission.CONTROL_KEYGUARD"/> <uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"/> <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" /> + <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> + <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <!-- Uses API introduced in O (26) --> <uses-sdk android:minSdkVersion="1" diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index a847b6ab105c..2ce4c54a932b 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -65,7 +65,8 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi public OwnersTestable(MockSystemServices services) { super(services.userManager, services.userManagerInternal, - services.packageManagerInternal, new MockInjector(services)); + services.packageManagerInternal, services.activityTaskManagerInternal, + new MockInjector(services)); } static class MockInjector extends Injector { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java index 4724f1cdd324..8f0aeea3dbf8 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java @@ -64,6 +64,7 @@ import android.view.IWindowManager; import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.widget.LockPatternUtils; import com.android.server.net.NetworkPolicyManagerInternal; +import com.android.server.wm.ActivityTaskManagerInternal; import java.io.File; import java.io.IOException; @@ -94,6 +95,7 @@ public class MockSystemServices { public final IActivityManager iactivityManager; public final IActivityTaskManager iactivityTaskManager; public ActivityManagerInternal activityManagerInternal; + public ActivityTaskManagerInternal activityTaskManagerInternal; public final IPackageManager ipackageManager; public final IBackupManager ibackupManager; public final IAudioService iaudioService; @@ -133,6 +135,7 @@ public class MockSystemServices { iactivityManager = mock(IActivityManager.class); iactivityTaskManager = mock(IActivityTaskManager.class); activityManagerInternal = mock(ActivityManagerInternal.class); + activityTaskManagerInternal = mock(ActivityTaskManagerInternal.class); ipackageManager = mock(IPackageManager.class); ibackupManager = mock(IBackupManager.class); iaudioService = mock(IAudioService.class); diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java index 4e43d002d4ae..8caa39dfc9e7 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java @@ -1035,6 +1035,15 @@ public class AppTimeLimitControllerTests { 0L, group.getUsageRemaining()); } + /** Verify that a limit of 0 is allowed for the special case of re-registering an observer. */ + @Test + public void testAppUsageLimitObserver_ZeroTimeLimitIsAllowed() { + addAppUsageLimitObserver(OBS_ID1, GROUP1, 0); + AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1); + assertNotNull("Observer wasn't added", group); + assertEquals("Usage remaining was not 0.", 0, group.getUsageRemaining()); + } + private void startUsage(String packageName) { mController.noteUsageStart(packageName, USER_ID); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index 2de4ae02828c..23bae8881aa1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions; + import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.anyInt; @@ -35,9 +36,7 @@ import android.content.Intent; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.SparseIntArray; -import android.util.proto.ProtoOutputStream; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto; diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 4073ff106592..8c36905d8422 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -183,11 +183,14 @@ public class ActivityRecordTests extends ActivityTestsBase { .thenReturn(navBarPosition); mTask.getConfiguration().windowConfiguration.setAppBounds(taskBounds); mActivity.info.maxAspectRatio = aspectRatio; - mActivity.ensureActivityConfiguration( - 0 /* globalChanges */, false /* preserveWindow */); + ensureActivityConfiguration(); assertEquals(expectedActivityBounds, mActivity.getBounds()); } + private void ensureActivityConfiguration() { + mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); + } + @Test public void testCanBeLaunchedOnDisplay() { mService.mSupportsMultiWindow = true; @@ -281,7 +284,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; - mActivity.ensureActivityConfiguration(0, false, false); + ensureActivityConfiguration(); assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE, mActivity.mRelaunchReason); @@ -305,7 +308,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; - mActivity.ensureActivityConfiguration(0, false, false); + ensureActivityConfiguration(); assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE, mActivity.mRelaunchReason); @@ -327,7 +330,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; - mActivity.ensureActivityConfiguration(0, false, false); + ensureActivityConfiguration(); assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE, mActivity.mRelaunchReason); @@ -433,4 +436,46 @@ public class ActivityRecordTests extends ActivityTestsBase { stack.getDisplay().removeChild(stack); } } + + @Test + public void testFixedScreenConfigurationWhenMovingToDisplay() { + // Initialize different bounds on a new display. + final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); + newDisplay.setBounds(0, 0, 1000, 2000); + newDisplay.getConfiguration().densityDpi = 300; + + mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds()); + mTask.getConfiguration().densityDpi = 200; + when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn( + ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); + mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE; + mActivity.info.maxAspectRatio = 1.5f; + ensureActivityConfiguration(); + final Rect originalBounds = new Rect(mActivity.getBounds()); + final int originalDpi = mActivity.getConfiguration().densityDpi; + + // Move the non-resizable activity to the new display. + mStack.reparent(newDisplay, true /* onTop */, false /* displayRemoved */); + ensureActivityConfiguration(); + + assertEquals(originalBounds, mActivity.getBounds()); + assertEquals(originalDpi, mActivity.getConfiguration().densityDpi); + } + + @Test + public void testFixedScreenBoundsWhenDisplaySizeChanged() { + when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn( + ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds()); + mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; + mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE; + ensureActivityConfiguration(); + final Rect originalBounds = new Rect(mActivity.getBounds()); + + // Change the size of current display. + mStack.getDisplay().setBounds(0, 0, 1000, 2000); + ensureActivityConfiguration(); + + assertEquals(originalBounds, mActivity.getBounds()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 60f1ae26f5dd..392b0106c8e5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -61,7 +61,6 @@ import static org.mockito.ArgumentMatchers.eq; import android.app.ActivityOptions; import android.app.IApplicationThread; -import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -643,7 +642,7 @@ public class ActivityStarterTests extends ActivityTestsBase { UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, false, false, false, true, false); runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callingPackageIsDeviceOwner_notAborted", false, + "disallowed_callingPackageNameIsDeviceOwner_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, false, false, false, false, true); @@ -655,7 +654,7 @@ public class ActivityStarterTests extends ActivityTestsBase { boolean hasForegroundActivities, boolean callerIsRecents, boolean callerIsTempWhitelisted, boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges, - boolean isCallingPackageDeviceOwner) { + boolean isCallingPackageNameDeviceOwner) { // window visibility doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot) .isAnyNonToastWindowVisibleForUid(callingUid); @@ -681,9 +680,8 @@ public class ActivityStarterTests extends ActivityTestsBase { // caller is instrumenting with background activity starts privileges callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges, callerIsInstrumentingWithBackgroundActivityStartPrivileges); - // caller is device owner - DevicePolicyManager dpmMock = mService.getDevicePolicyManager(); - doReturn(isCallingPackageDeviceOwner).when(dpmMock).isDeviceOwnerApp(any()); + // calling package name is whitelisted + doReturn(isCallingPackageNameDeviceOwner).when(mService).isDeviceOwner(any()); final ActivityOptions options = spy(ActivityOptions.makeBasic()); ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK) diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index e27dd94b1a2c..abc0bd64c0e0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -42,7 +42,6 @@ import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.IApplicationThread; -import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -72,8 +71,10 @@ import com.android.server.am.PendingIntentController; import com.android.server.appop.AppOpsService; import com.android.server.firewall.IntentFirewall; import com.android.server.uri.UriGrantsManagerInternal; +import com.android.server.wm.utils.MockTracker; import org.junit.After; +import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; @@ -88,6 +89,8 @@ import java.util.List; class ActivityTestsBase { private static int sNextDisplayId = DEFAULT_DISPLAY + 1; + private static MockTracker sMockTracker; + @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = new DexmakerShareClassLoaderRule(); @@ -107,9 +110,17 @@ class ActivityTestsBase { @BeforeClass public static void setUpOnceBase() { + sMockTracker = new MockTracker(); + AttributeCache.init(getInstrumentation().getTargetContext()); } + @AfterClass + public static void tearDownOnceBase() { + sMockTracker.close(); + sMockTracker = null; + } + @Before public void setUpBase() { mTestInjector.setUp(); @@ -425,7 +436,6 @@ class ActivityTestsBase { spyOn(getLifecycleManager()); spyOn(getLockTaskController()); doReturn(mock(IPackageManager.class)).when(this).getPackageManager(); - doReturn(mock(DevicePolicyManager.class)).when(this).getDevicePolicyManager(); // allow background activity starts by default doReturn(true).when(this).isBackgroundActivityStartsEnabled(); doNothing().when(this).updateCpuStats(); @@ -657,12 +667,11 @@ class ActivityTestsBase { private static WindowManagerService sMockWindowManagerService; private static WindowManagerService prepareMockWindowManager() { - if (sMockWindowManagerService != null) { - return sMockWindowManagerService; + if (sMockWindowManagerService == null) { + sMockWindowManagerService = mock(WindowManagerService.class); } - final WindowManagerService service = mock(WindowManagerService.class); - service.mRoot = mock(RootWindowContainer.class); + sMockWindowManagerService.mRoot = mock(RootWindowContainer.class); doAnswer((InvocationOnMock invocationOnMock) -> { final Runnable runnable = invocationOnMock.<Runnable>getArgument(0); @@ -670,10 +679,9 @@ class ActivityTestsBase { runnable.run(); } return null; - }).when(service).inSurfaceTransaction(any()); + }).when(sMockWindowManagerService).inSurfaceTransaction(any()); - sMockWindowManagerService = service; - return service; + return sMockWindowManagerService; } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index bc62de12373d..cd1320986972 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -44,6 +44,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; +import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; @@ -62,7 +63,6 @@ import org.junit.Test; * Build/Install/Run: * atest FrameworksServicesTests:AppWindowTokenTests */ -@FlakyTest(bugId = 68267650) @SmallTest @Presubmit public class AppWindowTokenTests extends WindowTestsBase { @@ -79,6 +79,7 @@ public class AppWindowTokenTests extends WindowTestsBase { mTask = createTaskInStack(mStack, 0 /* userId */); mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent); + mToken.mSkipOnParentChanged = false; mTask.addChild(mToken, 0); } @@ -141,6 +142,7 @@ public class AppWindowTokenTests extends WindowTestsBase { mToken.removeImmediately(); } + @FlakyTest(detail = "Promote to presubmit when shown to be stable.") @Test public void testLandscapeSeascapeRotationByApp() { // Some plumbing to get the service ready for rotation updates. @@ -166,6 +168,8 @@ public class AppWindowTokenTests extends WindowTestsBase { mDisplayContent.updateOrientationFromAppTokens( mDisplayContent.getRequestedOverrideConfiguration(), null /* freezeThisOneIfNeeded */, false /* forceUpdate */); + // In this test, DC will not get config update. Set the waiting flag to false. + mDisplayContent.mWaitingForConfig = false; mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */); assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation()); assertTrue(appWindow.mResizeReported); @@ -211,6 +215,48 @@ public class AppWindowTokenTests extends WindowTestsBase { } @Test + public void testSizeCompatBounds() { + // The real surface transaction is unnecessary. + mToken.setSkipPrepareSurfaces(true); + + final Rect fixedBounds = mToken.getRequestedOverrideConfiguration().windowConfiguration + .getBounds(); + fixedBounds.set(0, 0, 1200, 1600); + final Configuration newParentConfig = mTask.getConfiguration(); + + // Change the size of the container to two times smaller with insets. + newParentConfig.windowConfiguration.setAppBounds(200, 0, 800, 800); + final Rect containerAppBounds = newParentConfig.windowConfiguration.getAppBounds(); + final Rect containerBounds = newParentConfig.windowConfiguration.getBounds(); + containerBounds.set(0, 0, 600, 800); + mToken.onConfigurationChanged(newParentConfig); + + assertTrue(mToken.inSizeCompatMode()); + assertEquals(containerAppBounds, mToken.getBounds()); + assertEquals((float) containerAppBounds.width() / fixedBounds.width(), + mToken.getSizeCompatScale(), 0.0001f /* delta */); + + // Change the width of the container to two times bigger. + containerAppBounds.set(0, 0, 2400, 1600); + containerBounds.set(containerAppBounds); + mToken.onConfigurationChanged(newParentConfig); + + assertTrue(mToken.inSizeCompatMode()); + // Don't scale up, so the bounds keep the same as the fixed width. + assertEquals(fixedBounds.width(), mToken.getBounds().width()); + // Assert the position is horizontal center. + assertEquals((containerAppBounds.width() - fixedBounds.width()) / 2, + mToken.getBounds().left); + assertEquals(1f, mToken.getSizeCompatScale(), 0.0001f /* delta */); + + // Change the width of the container to fit the fixed bounds. + containerBounds.set(0, 0, 1200, 2000); + mToken.onConfigurationChanged(newParentConfig); + // Assert don't use fixed bounds because the region is enough. + assertFalse(mToken.inSizeCompatMode()); + } + + @Test @Presubmit public void testGetOrientation() { mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); @@ -300,6 +346,7 @@ public class AppWindowTokenTests extends WindowTestsBase { assertNoStartingWindow(mToken); } + @FlakyTest(detail = "Promote to presubmit when shown to be stable.") @Test public void testAddRemoveRace() { // There was once a race condition between adding and removing starting windows @@ -384,6 +431,7 @@ public class AppWindowTokenTests extends WindowTestsBase { // bottom one. tokenTop.setVisibility(false, false); tokenBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded(); + waitUntilHandlersIdle(); // Assert that the bottom window now has the starting window. assertNoStartingWindow(tokenTop); diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java index 2f90baaceb99..3f83caea613a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java @@ -71,7 +71,6 @@ import java.util.concurrent.TimeUnit; * atest WmTests:AssistDataRequesterTest */ @MediumTest -@FlakyTest(bugId = 113616538) public class AssistDataRequesterTest extends ActivityTestsBase { private static final String TAG = AssistDataRequesterTest.class.getSimpleName(); @@ -154,6 +153,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { .checkOpNoThrow(eq(OP_ASSIST_SCREENSHOT), anyInt(), anyString()); } + @FlakyTest(bugId = 124088319) @Test public void testRequestData() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -174,6 +174,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 0, 0, 0); } + @FlakyTest(bugId = 124088319) @Test public void testCurrentAppDisallow_expectNullCallbacks() throws Exception { setupMocks(!CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -184,6 +185,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 1, 0, 1); } + @FlakyTest(bugId = 124088319) @Test public void testProcessPendingData() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -241,6 +243,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 1, 0, 1); } + @FlakyTest(bugId = 124088319) @Test public void testDisallowAssistContextExtras_expectNullDataCallbacks() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -254,6 +257,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 1, 0, 1); } + @FlakyTest(bugId = 124088319) @Test public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -264,6 +268,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(5, 5, 0, 0); } + @FlakyTest(bugId = 124088319) @Test public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java index 0c363de36328..a0546d7623e7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java @@ -19,11 +19,11 @@ package com.android.server.wm; import static android.view.InsetsState.TYPE_TOP_BAR; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import android.graphics.Insets; import android.graphics.Rect; @@ -31,8 +31,6 @@ import android.platform.test.annotations.Presubmit; import android.view.InsetsSource; import android.view.InsetsState; -import org.junit.Before; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Before; diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index 11526a85aafb..bc62e8c5ab24 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -35,7 +35,6 @@ import androidx.test.filters.SmallTest; import org.junit.Test; @SmallTest -@FlakyTest(detail = "Promote once confirmed non-flaky") @Presubmit public class InsetsStateControllerTest extends WindowTestsBase { @@ -48,6 +47,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertNotNull(getController().getInsetsForDispatch(app).getSource(TYPE_TOP_BAR)); } + @FlakyTest(bugId = 69229402) @Test public void testStripForDispatch_own() { final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); @@ -57,6 +57,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertEquals(new InsetsState(), getController().getInsetsForDispatch(topBar)); } + @FlakyTest(bugId = 124088319) @Test public void testStripForDispatch_navBar() { final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); @@ -68,6 +69,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertEquals(new InsetsState(), getController().getInsetsForDispatch(navBar)); } + @FlakyTest(bugId = 124088319) @Test public void testBarControllingWinChanged() { final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); @@ -80,6 +82,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertEquals(2, controls.length); } + @FlakyTest(bugId = 124088319) @Test public void testControlRevoked() { final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); @@ -91,6 +94,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertNull(getController().getControlsForDispatch(app)); } + @FlakyTest(bugId = 124088319) @Test public void testControlRevoked_animation() { final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java index 86bf3dbb6973..b769fcecc469 100644 --- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java @@ -24,7 +24,6 @@ import android.app.ActivityOptions; import android.platform.test.annotations.Presubmit; import android.view.RemoteAnimationAdapter; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.testutils.OffsettableClock; diff --git a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java index c3d2f33b17dd..83274401f13d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java @@ -28,7 +28,6 @@ import static org.junit.Assert.assertTrue; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import org.junit.After; diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index 67ee4ad91d91..94def2bb7846 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -67,6 +67,7 @@ import org.junit.Before; import org.junit.Test; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -142,7 +143,8 @@ public class RootActivityContainerTests extends ActivityTestsBase { private static void ensureStackPlacement(ActivityStack stack, TaskRecord... tasks) { final ArrayList<TaskRecord> stackTasks = stack.getAllTasks(); - assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0); + assertEquals("Expecting " + Arrays.deepToString(tasks) + " got " + stackTasks, + stackTasks.size(), tasks != null ? tasks.length : 0); if (tasks == null) { return; diff --git a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java index dad6c952d7ab..71118521acf5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java @@ -21,7 +21,6 @@ import static org.junit.Assert.assertEquals; import android.app.ActivityOptions; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import org.junit.Test; diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java index dfdbf323365f..6cce9f088ee4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java @@ -167,7 +167,6 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase { verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L)); } - @FlakyTest(bugId = 74780584) @Test public void testDeferStartingAnimations() throws Exception { mSurfaceAnimationRunner.deferStartingAnimations(); diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java index 8c32e8cea93c..88ac96d74df6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java @@ -34,7 +34,6 @@ import android.view.SurfaceControl.Builder; import android.view.SurfaceControl.Transaction; import android.view.SurfaceSession; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.wm.SurfaceAnimator.Animatable; @@ -51,7 +50,7 @@ import org.mockito.MockitoAnnotations; * Test class for {@link SurfaceAnimatorTest}. * * Build/Install/Run: - * atest FrameworksServicesTests:SurfaceAnimatorTest + * atest WmTests:SurfaceAnimatorTest */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java index 12ed3c28161f..9dfeadf878e0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java @@ -29,8 +29,6 @@ import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.util.SparseBooleanArray; -import androidx.test.filters.FlakyTest; - import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java index 8c6ac23c9202..1e58e413dd1b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java @@ -43,7 +43,6 @@ import org.junit.Test; * Build/Install/Run: * atest FrameworksServicesTests:TaskPositioningControllerTests */ -@FlakyTest(bugId = 117924387) @SmallTest @Presubmit public class TaskPositioningControllerTests extends WindowTestsBase { @@ -90,6 +89,7 @@ public class TaskPositioningControllerTests extends WindowTestsBase { assertNull(mTarget.getDragWindowHandleLocked()); } + @FlakyTest(bugId = 69229402) @Test public void testHandleTapOutsideTask() { synchronized (mWm.mGlobalLock) { diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java index 4a734e5256f6..dcca3167c752 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java @@ -35,9 +35,11 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; import android.support.test.uiautomator.UiDevice; import android.text.TextUtils; +import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import com.android.internal.annotations.GuardedBy; @@ -76,6 +78,7 @@ public class TaskStackChangedListenerTest { } @Test + @Presubmit public void testTaskStackChanged_afterFinish() throws Exception { registerTaskStackChangedListener(new TaskStackListener() { @Override @@ -87,7 +90,8 @@ public class TaskStackChangedListenerTest { }); Context context = getInstrumentation().getContext(); - context.startActivity(new Intent(context, ActivityA.class)); + context.startActivity( + new Intent(context, ActivityA.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); UiDevice.getInstance(getInstrumentation()).waitForIdle(); synchronized (sLock) { assertTrue(sTaskStackChangedCalled); @@ -96,6 +100,7 @@ public class TaskStackChangedListenerTest { } @Test + @FlakyTest(bugId = 119893767) public void testTaskDescriptionChanged() throws Exception { final Object[] params = new Object[2]; final CountDownLatch latch = new CountDownLatch(1); @@ -124,6 +129,7 @@ public class TaskStackChangedListenerTest { } @Test + @FlakyTest(bugId = 119893767) public void testActivityRequestedOrientationChanged() throws Exception { final int[] params = new int[2]; final CountDownLatch latch = new CountDownLatch(1); @@ -146,6 +152,7 @@ public class TaskStackChangedListenerTest { * Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted. */ @Test + @FlakyTest(bugId = 119893767) public void testTaskChangeCallBacks() throws Exception { final Object[] params = new Object[2]; final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1); @@ -221,7 +228,8 @@ public class TaskStackChangedListenerTest { final ActivityMonitor monitor = new ActivityMonitor(activityClass.getName(), null, false); getInstrumentation().addMonitor(monitor); final Context context = getInstrumentation().getContext(); - context.startActivity(new Intent(context, activityClass)); + context.startActivity( + new Intent(context, activityClass).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); final TestActivity activity = (TestActivity) monitor.waitForActivityWithTimeout(1000); if (activity == null) { throw new RuntimeException("Timed out waiting for Activity"); diff --git a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java index b151fb7a613c..e540b3a9db89 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java @@ -61,7 +61,7 @@ import com.android.server.policy.WindowManagerPolicy; import org.mockito.invocation.InvocationOnMock; import org.mockito.quality.Strictness; -import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; /** * A Test utility class to create a mock {@link WindowManagerService} instance for tests. @@ -71,6 +71,8 @@ class TestSystemServices { private static WindowManagerService sService; private static TestWindowManagerPolicy sPolicy; + static AtomicBoolean sCurrentMessagesProcessed = new AtomicBoolean(false); + static void setUpWindowManagerService() { sMockitoSession = mockitoSession() .spyStatic(LockGuard.class) @@ -88,6 +90,7 @@ class TestSystemServices { sPolicy = null; sMockitoSession.finishMocking(); + sMockitoSession = null; } private static void setUpTestWindowService() { @@ -194,21 +197,23 @@ class TestSystemServices { } private static void waitHandlerIdle(Handler handler) { - if (!handler.hasMessagesOrCallbacks()) { - return; - } - final CountDownLatch latch = new CountDownLatch(1); - // Wait for delayed messages are processed. - handler.getLooper().getQueue().addIdleHandler(() -> { - if (handler.hasMessagesOrCallbacks()) { - return true; // keep idle handler. + synchronized (sCurrentMessagesProcessed) { + // Add a message to the handler queue and make sure it is fully processed before we move + // on. This makes sure all previous messages in the handler are fully processed vs. just + // popping them from the message queue. + sCurrentMessagesProcessed.set(false); + handler.post(() -> { + synchronized (sCurrentMessagesProcessed) { + sCurrentMessagesProcessed.set(true); + sCurrentMessagesProcessed.notifyAll(); + } + }); + while (!sCurrentMessagesProcessed.get()) { + try { + sCurrentMessagesProcessed.wait(); + } catch (InterruptedException e) { + } } - latch.countDown(); - return false; // remove idle handler. - }); - try { - latch.await(); - } catch (InterruptedException e) { } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java index 64ceb1bf8dff..d6608f1cabdc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java @@ -49,7 +49,7 @@ import org.junit.Test; * Test class to for {@link android.app.WindowConfiguration}. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowConfigurationTests + * atest WmTests:WindowConfigurationTests */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java index af8ccc981bae..fc7863524240 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java @@ -26,7 +26,6 @@ import static org.junit.Assert.assertTrue; import android.content.res.Configuration; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Test; @@ -35,7 +34,7 @@ import org.junit.Test; * Test class for {@link WindowContainerController}. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowContainerControllerTests + * atest WmTests:WindowContainerControllerTests */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index a9a76c2e9506..b93c994f4d8f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -47,7 +47,6 @@ import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; import android.view.SurfaceSession; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Test; @@ -59,11 +58,10 @@ import java.util.Comparator; * Test class for {@link WindowContainer}. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowContainerTests + * atest WmTests:WindowContainerTests */ @SmallTest @Presubmit -@FlakyTest(bugId = 74078662) public class WindowContainerTests extends WindowTestsBase { @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java index 0a4a8a43fbc5..fb30f8b2b107 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java @@ -449,8 +449,7 @@ public class WindowFrameTests extends WindowTestsBase { // Now simulate switch to fullscreen for letterboxed app. final int xInset = logicalWidth / 10; - final int yInset = logicalWidth / 10; - final Rect cf = new Rect(xInset, yInset, logicalWidth - xInset, logicalHeight - yInset); + final Rect cf = new Rect(xInset, 0, logicalWidth - xInset, logicalHeight); Configuration config = new Configuration(w.mAppToken.getRequestedOverrideConfiguration()); config.windowConfiguration.setBounds(cf); w.mAppToken.onRequestedOverrideConfigurationChanged(config); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index a4948899c855..114eac911bd7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -151,6 +151,7 @@ public class WindowTestUtils { /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */ public static class TestAppWindowToken extends AppWindowToken { boolean mOnTop = false; + private boolean mSkipPrepareSurfaces; private Transaction mPendingTransactionOverride; boolean mSkipOnParentChanged = true; @@ -213,6 +214,17 @@ public class WindowTestUtils { return mOnTop; } + @Override + void prepareSurfaces() { + if (!mSkipPrepareSurfaces) { + super.prepareSurfaces(); + } + } + + void setSkipPrepareSurfaces(boolean ignore) { + mSkipPrepareSurfaces = ignore; + } + void setPendingTransaction(Transaction transaction) { mPendingTransactionOverride = transaction; } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 3cb28140e2ea..a83bf2af613e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -50,6 +50,7 @@ import android.view.IWindow; import android.view.WindowManager; import com.android.server.AttributeCache; +import com.android.server.wm.utils.MockTracker; import org.junit.After; import org.junit.AfterClass; @@ -77,6 +78,8 @@ class WindowTestsBase { private static int sNextDisplayId = DEFAULT_DISPLAY + 1; static int sNextStackId = 1000; + private static MockTracker sMockTracker; + /** Non-default display. */ DisplayContent mDisplayContent; DisplayInfo mDisplayInfo = new DisplayInfo(); @@ -109,11 +112,18 @@ class WindowTestsBase { TestSystemServices.setUpWindowManagerService(); + // MockTracker needs to be initialized after TestSystemServices because we don't want to + // track static mocks. + sMockTracker = new MockTracker(); + sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class); } @AfterClass - public static void tearDonwOnceBase() { + public static void tearDownOnceBase() { + sMockTracker.close(); + sMockTracker = null; + TestSystemServices.tearDownWindowManagerService(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index d55688665f70..4cdbea0bfb56 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -28,7 +28,6 @@ import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Test; @@ -37,7 +36,7 @@ import org.junit.Test; * Tests for the {@link WindowToken} class. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowTokenTests + * atest WmTests:WindowTokenTests */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java index 2970c211e29c..3c6e2405adff 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java @@ -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 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/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/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/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()); } } |