Merge "Protect mock with lock to fix flakiness, add two tests to presubmit"
diff --git a/Android.bp b/Android.bp
index 6288940..385149e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -845,6 +845,7 @@
// specified on the build command line.
java_library {
name: "framework-atb-backward-compatibility",
+ installable: true,
srcs: [
"core/java/android/content/pm/AndroidTestBaseUpdater.java",
],
@@ -1514,7 +1515,7 @@
],
proofread_file: "ds-docs-proofrerad.txt",
args: framework_docs_only_args +
- " -toroot / -samplegroup Admin " +
+ " -toroot / -yamlV2 -metalavaApiSince -samplegroup Admin " +
" -samplegroup Background " +
" -samplegroup Connectivity " +
" -samplegroup Content " +
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
index e7fe235..e805ab9 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
@@ -71,7 +71,7 @@
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
RenderNode node = RenderNode.create("LinearLayout", null);
while (state.keepRunning()) {
- node.startRecording(100, 100);
+ node.beginRecording(100, 100);
node.endRecording();
}
}
@@ -86,7 +86,7 @@
while (state.keepRunning()) {
for (int i = 0; i < nodes.length; i++) {
- nodes[i].startRecording(100, 100);
+ nodes[i].beginRecording(100, 100);
}
for (int i = nodes.length - 1; i >= 0; i--) {
nodes[i].endRecording();
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index bd7522d..8a6c60f 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -265,7 +265,7 @@
state.pauseTiming();
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
- final RecordingCanvas c = node.startRecording(1200, 200);
+ final RecordingCanvas c = node.beginRecording(1200, 200);
state.resumeTiming();
layout.draw(c);
@@ -282,7 +282,7 @@
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
- final RecordingCanvas c = node.startRecording(1200, 200);
+ final RecordingCanvas c = node.beginRecording(1200, 200);
state.resumeTiming();
layout.draw(c);
@@ -299,7 +299,7 @@
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
- final RecordingCanvas c = node.startRecording(1200, 200);
+ final RecordingCanvas c = node.beginRecording(1200, 200);
state.resumeTiming();
layout.draw(c);
@@ -316,7 +316,7 @@
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
- final RecordingCanvas c = node.startRecording(1200, 200);
+ final RecordingCanvas c = node.beginRecording(1200, 200);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
@@ -334,7 +334,7 @@
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
- final RecordingCanvas c = node.startRecording(1200, 200);
+ final RecordingCanvas c = node.beginRecording(1200, 200);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
@@ -353,7 +353,7 @@
mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
- final RecordingCanvas c = node.startRecording(1200, 200);
+ final RecordingCanvas c = node.beginRecording(1200, 200);
state.resumeTiming();
layout.draw(c);
@@ -371,7 +371,7 @@
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
- final RecordingCanvas c = node.startRecording(1200, 200);
+ final RecordingCanvas c = node.beginRecording(1200, 200);
state.resumeTiming();
layout.draw(c);
@@ -389,7 +389,7 @@
mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
- final RecordingCanvas c = node.startRecording(1200, 200);
+ final RecordingCanvas c = node.beginRecording(1200, 200);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
@@ -408,7 +408,7 @@
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
- final RecordingCanvas c = node.startRecording(1200, 200);
+ final RecordingCanvas c = node.beginRecording(1200, 200);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
index 0bc9ee4..55d54e4 100644
--- a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
@@ -344,7 +344,7 @@
textView.setText(text);
textView.measure(width, height);
textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
- final RecordingCanvas c = node.startRecording(
+ final RecordingCanvas c = node.beginRecording(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
@@ -371,7 +371,7 @@
textView.setText(text);
textView.measure(width, height);
textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
- final RecordingCanvas c = node.startRecording(
+ final RecordingCanvas c = node.beginRecording(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
@@ -400,7 +400,7 @@
textView.setText(text);
textView.measure(width, height);
textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
- final RecordingCanvas c = node.startRecording(
+ final RecordingCanvas c = node.beginRecording(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
@@ -430,7 +430,7 @@
textView.setText(text);
textView.measure(width, height);
textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
- final RecordingCanvas c = node.startRecording(
+ final RecordingCanvas c = node.beginRecording(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
diff --git a/api/current.txt b/api/current.txt
index 7e0156f..0967479 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11457,10 +11457,10 @@
method public boolean isActive();
method public boolean isMultiPackage();
method public boolean isSealed();
- method public boolean isSessionApplied();
- method public boolean isSessionFailed();
- method public boolean isSessionReady();
method public boolean isStaged();
+ method public boolean isStagedSessionApplied();
+ method public boolean isStagedSessionFailed();
+ method public boolean isStagedSessionReady();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR;
field public static final int INVALID_ID = -1; // 0xffffffff
@@ -11664,6 +11664,7 @@
field public static final String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
field public static final String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
field public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint";
+ field public static final String FEATURE_FOLDABLE = "android.hardware.type.foldable";
field public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management";
field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad";
field public static final String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
@@ -14945,13 +14946,15 @@
public final class RenderNode {
ctor public RenderNode(@Nullable String);
- method public int computeApproximateMemoryUsage();
+ method public android.graphics.RecordingCanvas beginRecording(int, int);
+ method public android.graphics.RecordingCanvas beginRecording();
+ method public long computeApproximateMemoryUsage();
method public void discardDisplayList();
method public void endRecording();
method public float getAlpha();
- method public int getAmbientShadowColor();
+ method @ColorInt public int getAmbientShadowColor();
method public int getBottom();
- method public float getCameraDistance();
+ method @FloatRange(from=0.0f, to=java.lang.Float.MAX_VALUE) public float getCameraDistance();
method public boolean getClipToBounds();
method public boolean getClipToOutline();
method public float getElevation();
@@ -14962,12 +14965,12 @@
method public float getPivotX();
method public float getPivotY();
method public int getRight();
- method public float getRotation();
method public float getRotationX();
method public float getRotationY();
+ method public float getRotationZ();
method public float getScaleX();
method public float getScaleY();
- method public int getSpotShadowColor();
+ method @ColorInt public int getSpotShadowColor();
method public int getTop();
method public float getTranslationX();
method public float getTranslationY();
@@ -14985,36 +14988,31 @@
method public boolean offsetTopAndBottom(int);
method public boolean resetPivot();
method public boolean setAlpha(float);
- method public boolean setAmbientShadowColor(int);
- method public boolean setBottom(int);
- method public boolean setCameraDistance(float);
- method public boolean setClipBounds(@Nullable android.graphics.Rect);
+ method public boolean setAmbientShadowColor(@ColorInt int);
+ method public boolean setCameraDistance(@FloatRange(from=0.0f, to=java.lang.Float.MAX_VALUE) float);
+ method public boolean setClipRect(@Nullable android.graphics.Rect);
method public boolean setClipToBounds(boolean);
method public boolean setClipToOutline(boolean);
method public boolean setElevation(float);
method public boolean setForceDarkAllowed(boolean);
method public boolean setHasOverlappingRendering(boolean);
- method public boolean setLeft(int);
- method public boolean setLeftTopRightBottom(int, int, int, int);
method public boolean setOutline(@Nullable android.graphics.Outline);
method public boolean setPivotX(float);
method public boolean setPivotY(float);
+ method public boolean setPosition(int, int, int, int);
+ method public boolean setPosition(android.graphics.Rect);
method public boolean setProjectBackwards(boolean);
method public boolean setProjectionReceiver(boolean);
- method public boolean setRight(int);
- method public boolean setRotation(float);
method public boolean setRotationX(float);
method public boolean setRotationY(float);
+ method public boolean setRotationZ(float);
method public boolean setScaleX(float);
method public boolean setScaleY(float);
- method public boolean setSpotShadowColor(int);
- method public boolean setTop(int);
+ method public boolean setSpotShadowColor(@ColorInt int);
method public boolean setTranslationX(float);
method public boolean setTranslationY(float);
method public boolean setTranslationZ(float);
method public boolean setUseCompositingLayer(boolean, @Nullable android.graphics.Paint);
- method public android.graphics.RecordingCanvas startRecording(int, int);
- method public android.graphics.RecordingCanvas startRecording();
}
public class Shader {
@@ -44861,6 +44859,7 @@
method @Deprecated public int getCdmaDbm();
method @Deprecated public int getCdmaEcio();
method @NonNull public java.util.List<android.telephony.CellSignalStrength> getCellSignalStrengths();
+ method public <T extends android.telephony.CellSignalStrength> java.util.List<T> getCellSignalStrengths(@NonNull Class<T>);
method @Deprecated public int getEvdoDbm();
method @Deprecated public int getEvdoEcio();
method @Deprecated public int getEvdoSnr();
@@ -45668,465 +45667,6 @@
}
-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 class RcsEventQueryResult {
- method public android.telephony.ims.RcsQueryContinuationToken getContinuationToken();
- method public java.util.List<android.telephony.ims.RcsEvent> getEvents();
- }
-
- 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 {
- ctor public RcsGroupThreadIconChangedEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @Nullable android.net.Uri);
- method @Nullable public android.net.Uri getNewIcon();
- }
-
- public final class RcsGroupThreadNameChangedEvent extends android.telephony.ims.RcsGroupThreadEvent {
- ctor public RcsGroupThreadNameChangedEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @Nullable String);
- method @Nullable public String getNewName();
- }
-
- public final class RcsGroupThreadParticipantJoinedEvent extends android.telephony.ims.RcsGroupThreadEvent {
- ctor public RcsGroupThreadParticipantJoinedEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @NonNull android.telephony.ims.RcsParticipant);
- method public android.telephony.ims.RcsParticipant getJoinedParticipant();
- }
-
- public final class RcsGroupThreadParticipantLeftEvent extends android.telephony.ims.RcsGroupThreadEvent {
- ctor public RcsGroupThreadParticipantLeftEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @NonNull android.telephony.ims.RcsParticipant);
- method @NonNull public android.telephony.ims.RcsParticipant getLeavingParticipant();
- method public void persist() throws android.telephony.ims.RcsMessageStoreException;
- }
-
- 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 {
- ctor public RcsParticipantAliasChangedEvent(long, @NonNull android.telephony.ims.RcsParticipant, @Nullable String);
- method @Nullable public String getNewAlias();
- method @NonNull public android.telephony.ims.RcsParticipant getParticipant();
- }
-
- 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 {
diff --git a/api/system-current.txt b/api/system-current.txt
index b448f61..6f314f3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1305,8 +1305,8 @@
}
public abstract class ContentResolver {
- method @Nullable public android.os.Bundle getCache(@NonNull android.net.Uri);
- method public void putCache(@NonNull android.net.Uri, @Nullable android.os.Bundle);
+ method @Nullable @RequiresPermission("android.permission.CACHE_CONTENT") public android.os.Bundle getCache(@NonNull android.net.Uri);
+ method @RequiresPermission("android.permission.CACHE_CONTENT") public void putCache(@NonNull android.net.Uri, @Nullable android.os.Bundle);
}
public abstract class Context {
@@ -1715,8 +1715,13 @@
field public boolean handleAllWebDataURI;
}
+ public final class ShortcutInfo implements android.os.Parcelable {
+ method @Nullable public android.app.Person[] getPersons();
+ }
+
public class ShortcutManager {
method @NonNull public java.util.List<android.content.pm.ShortcutManager.ShareShortcutInfo> getShareTargets(@NonNull android.content.IntentFilter);
+ method public boolean hasShareTargets(@NonNull String);
}
public static final class ShortcutManager.ShareShortcutInfo implements android.os.Parcelable {
@@ -1894,7 +1899,7 @@
public final class BrightnessConfiguration implements android.os.Parcelable {
method public int describeContents();
method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByCategory(int);
- method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(String);
+ method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(@NonNull String);
method public android.util.Pair<float[],float[]> getCurve();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR;
@@ -1902,8 +1907,8 @@
public static class BrightnessConfiguration.Builder {
ctor public BrightnessConfiguration.Builder(float[], float[]);
- method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByCategory(int, android.hardware.display.BrightnessCorrection);
- method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByPackageName(String, android.hardware.display.BrightnessCorrection);
+ method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByCategory(int, @NonNull android.hardware.display.BrightnessCorrection);
+ method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByPackageName(@NonNull String, @NonNull android.hardware.display.BrightnessCorrection);
method public android.hardware.display.BrightnessConfiguration build();
method public int getMaxCorrectionsByCategory();
method public int getMaxCorrectionsByPackageName();
@@ -1911,7 +1916,7 @@
}
public final class BrightnessCorrection implements android.os.Parcelable {
- method public float apply(float);
+ method @FloatRange(from=0.0) public float apply(@FloatRange(from=0.0) float);
method @NonNull public static android.hardware.display.BrightnessCorrection createScaleAndTranslateLog(float, float);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -5128,6 +5133,7 @@
method public void onError(int);
method public void onFinished();
method public void onProgress(float);
+ field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5
field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1
field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2
field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4
@@ -7470,7 +7476,7 @@
field public static final int VSNCP_TIMEOUT = 2236; // 0x8bc
}
- public class DisconnectCause {
+ public final class DisconnectCause {
field public static final int ALREADY_DIALING = 72; // 0x48
field public static final int ANSWERED_ELSEWHERE = 52; // 0x34
field public static final int BUSY = 4; // 0x4
@@ -7648,18 +7654,18 @@
public class PhoneStateListener {
method public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
- method public void onCallDisconnectCauseChanged(int, int);
- method public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
- method public void onPreciseCallStateChanged(android.telephony.PreciseCallState);
- method public void onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState);
+ method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onCallDisconnectCauseChanged(int, int);
+ method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
+ method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
+ method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState);
method public void onRadioPowerStateChanged(int);
method public void onSrvccStateChanged(int);
method public void onVoiceActivationStateChanged(int);
field public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
- field public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
- field public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000
- field public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800
- field public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
+ field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
+ field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000
+ field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800
+ field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
field public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000
field public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
@@ -7694,7 +7700,7 @@
field public static final android.os.Parcelable.Creator<android.telephony.PreciseDataConnectionState> CREATOR;
}
- public class PreciseDisconnectCause {
+ public final class PreciseDisconnectCause {
field public static final int ACCESS_CLASS_BLOCKED = 260; // 0x104
field public static final int ACCESS_INFORMATION_DISCARDED = 43; // 0x2b
field public static final int ACM_LIMIT_EXCEEDED = 68; // 0x44
@@ -7912,7 +7918,7 @@
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState();
method public int getSimApplicationState();
method public int getSimCardState();
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getSimLocale();
+ method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Locale getSimLocale();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getSupportedRadioAccessFamily();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.UiccSlotInfo[] getUiccSlotsInfo();
@@ -9232,7 +9238,7 @@
package android.telephony.mbms.vendor {
- public class MbmsDownloadServiceBase extends android.os.Binder {
+ public class MbmsDownloadServiceBase extends android.os.Binder implements android.os.IInterface {
ctor public MbmsDownloadServiceBase();
method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
@@ -9265,7 +9271,7 @@
method public void updateGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>);
}
- public class MbmsStreamingServiceBase extends android.os.Binder {
+ public class MbmsStreamingServiceBase extends android.os.Binder implements android.os.IInterface {
ctor public MbmsStreamingServiceBase();
method public android.os.IBinder asBinder();
method public void dispose(int) throws android.os.RemoteException;
diff --git a/api/test-current.txt b/api/test-current.txt
index ba497d4..0cd20be 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -765,7 +765,7 @@
public final class BrightnessConfiguration implements android.os.Parcelable {
method public int describeContents();
method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByCategory(int);
- method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(String);
+ method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(@NonNull String);
method public android.util.Pair<float[],float[]> getCurve();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR;
@@ -773,8 +773,8 @@
public static class BrightnessConfiguration.Builder {
ctor public BrightnessConfiguration.Builder(float[], float[]);
- method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByCategory(int, android.hardware.display.BrightnessCorrection);
- method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByPackageName(String, android.hardware.display.BrightnessCorrection);
+ method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByCategory(int, @NonNull android.hardware.display.BrightnessCorrection);
+ method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByPackageName(@NonNull String, @NonNull android.hardware.display.BrightnessCorrection);
method public android.hardware.display.BrightnessConfiguration build();
method public int getMaxCorrectionsByCategory();
method public int getMaxCorrectionsByPackageName();
@@ -782,7 +782,7 @@
}
public final class BrightnessCorrection implements android.os.Parcelable {
- method public float apply(float);
+ method @FloatRange(from=0.0) public float apply(@FloatRange(from=0.0) float);
method @NonNull public static android.hardware.display.BrightnessCorrection createScaleAndTranslateLog(float, float);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -1952,6 +1952,7 @@
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 AUTOMATIC_POWER_SAVER_MODE = "automatic_power_saver_mode";
+ field public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants";
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";
field public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url";
@@ -2381,7 +2382,7 @@
package android.telephony.mbms.vendor {
- public class MbmsDownloadServiceBase extends android.os.Binder {
+ public class MbmsDownloadServiceBase extends android.os.Binder implements android.os.IInterface {
ctor public MbmsDownloadServiceBase();
method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
@@ -2414,7 +2415,7 @@
method public void updateGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>);
}
- public class MbmsStreamingServiceBase extends android.os.Binder {
+ public class MbmsStreamingServiceBase extends android.os.Binder implements android.os.IInterface {
ctor public MbmsStreamingServiceBase();
method public android.os.IBinder asBinder();
method public void dispose(int) throws android.os.RemoteException;
diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc
index 469c964..3666d6a 100644
--- a/cmds/bootanimation/bootanim.rc
+++ b/cmds/bootanimation/bootanim.rc
@@ -2,6 +2,9 @@
class core animation
user graphics
group graphics audio
+ # bootanimation depends on libandroidicu in the Runtime APEX.
+ # TODO(b/124939955): Remove this dependency on libandroidicu
+ updatable
disabled
oneshot
writepid /dev/stune/top-app/tasks
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 78e994f..de42398 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -45,6 +45,7 @@
import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy.proto";
import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy_enums.proto";
import "frameworks/base/core/proto/android/stats/launcher/launcher.proto";
+import "frameworks/base/core/proto/android/stats/style/style_enums.proto";
import "frameworks/base/core/proto/android/telecomm/enums.proto";
import "frameworks/base/core/proto/android/telephony/enums.proto";
import "frameworks/base/core/proto/android/view/enums.proto";
@@ -247,6 +248,7 @@
AssistGestureProgressReported assist_gesture_progress_reported = 176;
TouchGestureClassified touch_gesture_classified = 177;
HiddenApiUsed hidden_api_used = 178 [(allow_from_any_uid) = true];
+ StyleUIChanged style_ui_changed = 179;
}
// Pulled events will start at field 10000.
@@ -2349,6 +2351,17 @@
optional bool is_swipe_up_enabled = 5;
}
+message StyleUIChanged {
+ optional android.stats.style.Action action = 1;
+ optional int32 color_package_hash = 2;
+ optional int32 font_package_hash = 3;
+ optional int32 shape_package_hash = 4;
+ optional int32 clock_package_hash = 5;
+ optional int32 launcher_grid = 6;
+ optional int32 wallpaper_category_hash = 7;
+ optional int32 wallpaper_id_hash = 8;
+}
+
/**
* Logs when Settings UI has changed.
*
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 8d1cf33..9de62a2 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -155,7 +155,7 @@
mCurrentBucketStartTimeNs = startTimeNs;
// Kicks off the puller immediately if condition is true and diff based.
if (mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
- pullAndMatchEventsLocked(startTimeNs);
+ pullAndMatchEventsLocked(startTimeNs, mCondition);
}
VLOG("value metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mTimeBaseNs);
@@ -174,13 +174,17 @@
}
void ValueMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
- flushIfNeededLocked(dropTimeNs);
StatsdStats::getInstance().noteBucketDropped(mMetricId);
- mPastBuckets.clear();
+ // We are going to flush the data without doing a pull first so we need to invalidte the data.
+ bool pullNeeded = mIsPulled && mCondition == ConditionState::kTrue;
+ if (pullNeeded) {
+ invalidateCurrentBucket();
+ }
+ flushIfNeededLocked(dropTimeNs);
+ clearPastBucketsLocked(dropTimeNs);
}
void ValueMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
- flushIfNeededLocked(dumpTimeNs);
mPastBuckets.clear();
mSkippedBuckets.clear();
}
@@ -192,7 +196,6 @@
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
VLOG("metric %lld dump report now...", (long long)mMetricId);
- flushIfNeededLocked(dumpTimeNs);
if (include_current_partial_bucket) {
// For pull metrics, we need to do a pull at bucket boundaries. If we do not do that the
// current bucket will have incomplete data and the next will have the wrong snapshot to do
@@ -205,10 +208,10 @@
invalidateCurrentBucket();
break;
case NO_TIME_CONSTRAINTS:
- pullAndMatchEventsLocked(dumpTimeNs);
+ pullAndMatchEventsLocked(dumpTimeNs, mCondition);
break;
}
- }
+ }
flushCurrentBucketLocked(dumpTimeNs, dumpTimeNs);
}
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
@@ -325,12 +328,16 @@
}
}
-void ValueMetricProducer::invalidateCurrentBucket() {
+void ValueMetricProducer::invalidateCurrentBucketWithoutResetBase() {
if (!mCurrentBucketIsInvalid) {
// Only report once per invalid bucket.
StatsdStats::getInstance().noteInvalidatedBucket(mMetricId);
}
mCurrentBucketIsInvalid = true;
+}
+
+void ValueMetricProducer::invalidateCurrentBucket() {
+ invalidateCurrentBucketWithoutResetBase();
resetBase();
}
@@ -345,86 +352,112 @@
void ValueMetricProducer::onConditionChangedLocked(const bool condition,
const int64_t eventTimeNs) {
- if (eventTimeNs < mCurrentBucketStartTimeNs) {
+ bool isEventTooLate = eventTimeNs < mCurrentBucketStartTimeNs;
+ if (!isEventTooLate) {
+ if (mCondition == ConditionState::kUnknown) {
+ // If the condition was unknown, we mark the bucket as invalid since the bucket will
+ // contain partial data. For instance, the condition change might happen close to the
+ // end of the bucket and we might miss lots of data.
+ //
+ // We still want to pull to set the base.
+ invalidateCurrentBucket();
+ }
+
+ // Pull on condition changes.
+ ConditionState newCondition = condition ? ConditionState::kTrue : ConditionState::kFalse;
+ bool conditionChanged =
+ (mCondition == ConditionState::kTrue && newCondition == ConditionState::kFalse)
+ || (mCondition == ConditionState::kFalse && newCondition == ConditionState::kTrue);
+ // We do not need to pull when we go from unknown to false.
+ //
+ // We also pull if the condition was already true in order to be able to flush the bucket at
+ // the end if needed.
+ //
+ // onConditionChangedLocked might happen on bucket boundaries if this is called before
+ // #onDataPulled.
+ if (mIsPulled && (conditionChanged || condition)) {
+ pullAndMatchEventsLocked(eventTimeNs, newCondition);
+ }
+
+ // When condition change from true to false, clear diff base but don't
+ // reset other counters as we may accumulate more value in the bucket.
+ if (mUseDiff && mCondition == ConditionState::kTrue
+ && newCondition == ConditionState::kFalse) {
+ resetBase();
+ }
+ mCondition = newCondition;
+
+ } else {
VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
(long long)mCurrentBucketStartTimeNs);
StatsdStats::getInstance().noteConditionChangeInNextBucket(mMetricId);
invalidateCurrentBucket();
- return;
+ // Something weird happened. If we received another event if the future, the condition might
+ // be wrong.
+ mCondition = ConditionState::kUnknown;
}
+ // This part should alway be called.
flushIfNeededLocked(eventTimeNs);
-
- if (mCondition != ConditionState::kUnknown) {
- // Pull on condition changes.
- bool conditionChanged = mCondition != condition;
- // We do not need to pull when we go from unknown to false.
- if (mIsPulled && conditionChanged) {
- pullAndMatchEventsLocked(eventTimeNs);
- }
-
- // when condition change from true to false, clear diff base but don't
- // reset other counters as we may accumulate more value in the bucket.
- if (mUseDiff && mCondition == ConditionState::kTrue && condition == ConditionState::kFalse) {
- resetBase();
- }
- } else {
- // If the condition was unknown, we mark the bucket as invalid since the bucket will contain
- // partial data. For instance, the condition change might happen close to the end of the
- // bucket and we might miss lots of data.
- invalidateCurrentBucket();
- }
- mCondition = condition ? ConditionState::kTrue : ConditionState::kFalse;
}
-void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
+void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs, ConditionState condition) {
vector<std::shared_ptr<LogEvent>> allData;
if (!mPullerManager->Pull(mPullTagId, &allData)) {
- ALOGE("Gauge Stats puller failed for tag: %d at %lld", mPullTagId, (long long)timestampNs);
+ ALOGE("Stats puller failed for tag: %d at %lld", mPullTagId, (long long)timestampNs);
invalidateCurrentBucket();
return;
}
- accumulateEvents(allData, timestampNs, timestampNs);
+ accumulateEvents(allData, timestampNs, timestampNs, condition);
}
int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTimeNs) {
return mTimeBaseNs + ((currentTimeNs - mTimeBaseNs) / mBucketSizeNs) * mBucketSizeNs;
}
+// By design, statsd pulls data at bucket boundaries using AlarmManager. These pulls are likely
+// to be delayed. Other events like condition changes or app upgrade which are not based on
+// AlarmManager might have arrived earlier and close the bucket.
void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData,
bool pullSuccess, int64_t originalPullTimeNs) {
std::lock_guard<std::mutex> lock(mMutex);
- if (mCondition == ConditionState::kTrue) {
- if (!pullSuccess) {
+ if (mCondition == ConditionState::kTrue) {
// If the pull failed, we won't be able to compute a diff.
- invalidateCurrentBucket();
- return;
+ if (!pullSuccess) {
+ invalidateCurrentBucket();
+ } else {
+ bool isEventLate = originalPullTimeNs < getCurrentBucketEndTimeNs();
+ if (isEventLate) {
+ // If the event is late, we are in the middle of a bucket. Just
+ // process the data without trying to snap the data to the nearest bucket.
+ accumulateEvents(allData, originalPullTimeNs, originalPullTimeNs, mCondition);
+ } else {
+ // For scheduled pulled data, the effective event time is snap to the nearest
+ // bucket end. In the case of waking up from a deep sleep state, we will
+ // attribute to the previous bucket end. If the sleep was long but not very
+ // long, we will be in the immediate next bucket. Previous bucket may get a
+ // larger number as we pull at a later time than real bucket end.
+ //
+ // If the sleep was very long, we skip more than one bucket before sleep. In
+ // this case, if the diff base will be cleared and this new data will serve as
+ // new diff base.
+ int64_t bucketEndTime = calcPreviousBucketEndTime(originalPullTimeNs) - 1;
+ StatsdStats::getInstance().noteBucketBoundaryDelayNs(
+ mMetricId, originalPullTimeNs - bucketEndTime);
+ accumulateEvents(allData, originalPullTimeNs, bucketEndTime, mCondition);
+ }
+ }
}
- // For scheduled pulled data, the effective event time is snap to the nearest
- // bucket end. In the case of waking up from a deep sleep state, we will
- // attribute to the previous bucket end. If the sleep was long but not very long, we
- // will be in the immediate next bucket. Previous bucket may get a larger number as
- // we pull at a later time than real bucket end.
- // If the sleep was very long, we skip more than one bucket before sleep. In this case,
- // if the diff base will be cleared and this new data will serve as new diff base.
- int64_t bucketEndTime = calcPreviousBucketEndTime(originalPullTimeNs) - 1;
- StatsdStats::getInstance().noteBucketBoundaryDelayNs(
- mMetricId, originalPullTimeNs - bucketEndTime);
- accumulateEvents(allData, originalPullTimeNs, bucketEndTime);
-
- // We can probably flush the bucket. Since we used bucketEndTime when calling
- // #onMatchedLogEventInternalLocked, the current bucket will not have been flushed.
- flushIfNeededLocked(originalPullTimeNs);
-
- } else {
- VLOG("No need to commit data on condition false.");
- }
+ // We can probably flush the bucket. Since we used bucketEndTime when calling
+ // #onMatchedLogEventInternalLocked, the current bucket will not have been flushed.
+ flushIfNeededLocked(originalPullTimeNs);
}
-void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
- int64_t originalPullTimeNs, int64_t eventElapsedTimeNs) {
+void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
+ int64_t originalPullTimeNs, int64_t eventElapsedTimeNs,
+ ConditionState condition) {
bool isEventLate = eventElapsedTimeNs < mCurrentBucketStartTimeNs;
if (isEventLate) {
VLOG("Skip bucket end pull due to late arrival: %lld vs %lld",
@@ -463,7 +496,7 @@
// If the new pulled data does not contains some keys we track in our intervals, we need to
// reset the base.
for (auto& slice : mCurrentSlicedBucket) {
- bool presentInPulledData = mMatchedMetricDimensionKeys.find(slice.first)
+ bool presentInPulledData = mMatchedMetricDimensionKeys.find(slice.first)
!= mMatchedMetricDimensionKeys.end();
if (!presentInPulledData) {
for (auto& interval : slice.second) {
@@ -587,7 +620,10 @@
}
mMatchedMetricDimensionKeys.insert(eventKey);
- flushIfNeededLocked(eventTimeNs);
+ if (!mIsPulled) {
+ // We cannot flush without doing a pull first.
+ flushIfNeededLocked(eventTimeNs);
+ }
// For pulled data, we already check condition when we decide to pull or
// in onDataPulled. So take all of them.
@@ -722,26 +758,26 @@
}
}
+// For pulled metrics, we always need to make sure we do a pull before flushing the bucket
+// if mCondition is true!
void ValueMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
int64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
-
if (eventTimeNs < currentBucketEndTimeNs) {
VLOG("eventTime is %lld, less than next bucket start time %lld", (long long)eventTimeNs,
(long long)(currentBucketEndTimeNs));
return;
}
-
- int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
+ int64_t numBucketsForward = calcBucketsForwardCount(eventTimeNs);
int64_t nextBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
flushCurrentBucketLocked(eventTimeNs, nextBucketStartTimeNs);
+}
- mCurrentBucketNum += numBucketsForward;
- if (numBucketsForward > 1) {
- VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
- StatsdStats::getInstance().noteSkippedForwardBuckets(mMetricId);
- // take base again in future good bucket.
- resetBase();
+int64_t ValueMetricProducer::calcBucketsForwardCount(const int64_t& eventTimeNs) const {
+ int64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
+ if (eventTimeNs < currentBucketEndTimeNs) {
+ return 0;
}
+ return 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
}
void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
@@ -750,6 +786,16 @@
StatsdStats::getInstance().noteBucketUnknownCondition(mMetricId);
}
+ int64_t numBucketsForward = calcBucketsForwardCount(eventTimeNs);
+ mCurrentBucketNum += numBucketsForward;
+ if (numBucketsForward > 1) {
+ VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
+ StatsdStats::getInstance().noteSkippedForwardBuckets(mMetricId);
+ // Something went wrong. Maybe the device was sleeping for a long time. It is better
+ // to mark the current bucket as invalid. The last pull might have been successful through.
+ invalidateCurrentBucketWithoutResetBase();
+ }
+
VLOG("finalizing bucket for %ld, dumping %d slices", (long)mCurrentBucketStartTimeNs,
(int)mCurrentSlicedBucket.size());
int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
@@ -773,12 +819,7 @@
if (!mCurrentBucketIsInvalid) {
appendToFullBucket(eventTimeNs, fullBucketEndTimeNs);
}
- StatsdStats::getInstance().noteBucketCount(mMetricId);
- initCurrentSlicedBucket();
- mCurrentBucketIsInvalid = false;
- mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
- VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
- (long long)mCurrentBucketStartTimeNs);
+ initCurrentSlicedBucket(nextBucketStartTimeNs);
}
ValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime,
@@ -805,7 +846,9 @@
return bucket;
}
-void ValueMetricProducer::initCurrentSlicedBucket() {
+void ValueMetricProducer::initCurrentSlicedBucket(int64_t nextBucketStartTimeNs) {
+ StatsdStats::getInstance().noteBucketCount(mMetricId);
+ // Cleanup data structure to aggregate values.
for (auto it = mCurrentSlicedBucket.begin(); it != mCurrentSlicedBucket.end();) {
bool obsolete = true;
for (auto& interval : it->second) {
@@ -823,6 +866,16 @@
it++;
}
}
+
+ mCurrentBucketIsInvalid = false;
+ // If we do not have a global base when the condition is true,
+ // we will have incomplete bucket for the next bucket.
+ if (mUseDiff && !mHasGlobalBase && mCondition) {
+ mCurrentBucketIsInvalid = false;
+ }
+ mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
+ VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
+ (long long)mCurrentBucketStartTimeNs);
}
void ValueMetricProducer::appendToFullBucket(int64_t eventTimeNs, int64_t fullBucketEndTimeNs) {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 24e14b1..f317c37 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -39,6 +39,13 @@
std::vector<Value> values;
};
+
+// Aggregates values within buckets.
+//
+// There are different events that might complete a bucket
+// - a condition change
+// - an app upgrade
+// - an alarm set to the end of the bucket
class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
public:
ValueMetricProducer(const ConfigKey& key, const ValueMetric& valueMetric,
@@ -61,9 +68,8 @@
if (!mSplitBucketForAppUpgrade) {
return;
}
- flushIfNeededLocked(eventTimeNs - 1);
if (mIsPulled && mCondition) {
- pullAndMatchEventsLocked(eventTimeNs - 1);
+ pullAndMatchEventsLocked(eventTimeNs, mCondition);
}
flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
};
@@ -94,9 +100,12 @@
void dumpStatesLocked(FILE* out, bool verbose) const override;
- // Util function to flush the old packet.
+ // For pulled metrics, this method should only be called if a pull has be done. Else we will
+ // not have complete data for the bucket.
void flushIfNeededLocked(const int64_t& eventTime) override;
+ // For pulled metrics, this method should only be called if a pulled have be done. Else we will
+ // not have complete data for the bucket.
void flushCurrentBucketLocked(const int64_t& eventTimeNs,
const int64_t& nextBucketStartTimeNs) override;
@@ -105,8 +114,12 @@
// Calculate previous bucket end time based on current time.
int64_t calcPreviousBucketEndTime(const int64_t currentTimeNs);
+ // Calculate how many buckets are present between the current bucket and eventTimeNs.
+ int64_t calcBucketsForwardCount(const int64_t& eventTimeNs) const;
+
// Mark the data as invalid.
void invalidateCurrentBucket();
+ void invalidateCurrentBucketWithoutResetBase();
const int mWhatMatcherIndex;
@@ -163,14 +176,15 @@
bool hitFullBucketGuardRailLocked(const MetricDimensionKey& newKey);
- void pullAndMatchEventsLocked(const int64_t timestampNs);
+ void pullAndMatchEventsLocked(const int64_t timestampNs, ConditionState condition);
void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
- int64_t originalPullTimeNs, int64_t eventElapsedTimeNs);
+ int64_t originalPullTimeNs, int64_t eventElapsedTimeNs,
+ ConditionState condition);
ValueBucket buildPartialBucket(int64_t bucketEndTime,
const std::vector<Interval>& intervals);
- void initCurrentSlicedBucket();
+ void initCurrentSlicedBucket(int64_t nextBucketStartTimeNs);
void appendToFullBucket(int64_t eventTimeNs, int64_t fullBucketEndTimeNs);
// Reset diff base and mHasGlobalBase
@@ -214,48 +228,54 @@
const bool mSplitBucketForAppUpgrade;
- FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsNoCondition);
- FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering);
- FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset);
- FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset);
- FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition);
- FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade);
- FRIEND_TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade);
- FRIEND_TEST(ValueMetricProducerTest, TestPartialBucketCreated);
- FRIEND_TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse);
- FRIEND_TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled);
- FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition);
- FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithCondition);
FRIEND_TEST(ValueMetricProducerTest, TestAnomalyDetection);
+ FRIEND_TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange);
+ FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundariesOnAppUpgrade);
+ FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange);
FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition);
FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition);
FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2);
- FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateMin);
- FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateMax);
- FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateAvg);
- FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateSum);
- FRIEND_TEST(ValueMetricProducerTest, TestFirstBucket);
+ FRIEND_TEST(ValueMetricProducerTest, TestBucketIncludingUnknownConditionIsInvalid);
+ FRIEND_TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet);
FRIEND_TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime);
- FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput);
- FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue);
- FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase);
- FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures);
- FRIEND_TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey);
- FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange);
- FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange);
- FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket);
- FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate);
- FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed);
+ FRIEND_TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged);
+ FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary);
+ FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged);
+ FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled);
+ FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition);
+ FRIEND_TEST(ValueMetricProducerTest, TestFirstBucket);
FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit);
FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed);
FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed);
- FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded);
- FRIEND_TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange);
- FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled);
- FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged);
- FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary);
+ FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed);
+ FRIEND_TEST(ValueMetricProducerTest, TestLateOnDataPulledWithDiff);
+ FRIEND_TEST(ValueMetricProducerTest, TestLateOnDataPulledWithoutDiff);
+ FRIEND_TEST(ValueMetricProducerTest, TestPartialBucketCreated);
FRIEND_TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries);
- FRIEND_TEST(ValueMetricProducerTest, TestBucketIncludingUnknownConditionIsInvalid);
+ FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsNoCondition);
+ FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset);
+ FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset);
+ FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering);
+ FRIEND_TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade);
+ FRIEND_TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse);
+ FRIEND_TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled);
+ FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateAvg);
+ FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateMax);
+ FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateMin);
+ FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateSum);
+ FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithCondition);
+ FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade);
+ FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition);
+ FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded);
+ FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange);
+ FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket);
+ FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange);
+ FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate);
+ FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput);
+ FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue);
+ FRIEND_TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey);
+ FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase);
+ FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures);
friend class ValueMetricProducerTestHelper;
};
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 28caede..e5e4534 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -52,10 +52,38 @@
const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs;
double epsilon = 0.001;
+static void assertPastBucketValuesSingleKey(
+ const std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>>& mPastBuckets,
+ const std::initializer_list<int>& expectedValuesList) {
+ std::vector<int> expectedValues(expectedValuesList);
+ if (expectedValues.size() == 0) {
+ ASSERT_EQ(0, mPastBuckets.size());
+ return;
+ }
+
+ ASSERT_EQ(1, mPastBuckets.size());
+ ASSERT_EQ(expectedValues.size(), mPastBuckets.begin()->second.size());
+
+ auto buckets = mPastBuckets.begin()->second;
+ for (int i = 0; i < expectedValues.size(); i++) {
+ EXPECT_EQ(expectedValues[i], buckets[i].values[0].long_value)
+ << "Values differ at index " << i;
+ }
+}
+
class ValueMetricProducerTestHelper {
public:
+ static shared_ptr<LogEvent> createEvent(int64_t eventTimeNs, int64_t value) {
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, eventTimeNs);
+ event->write(tagId);
+ event->write(value);
+ event->write(value);
+ event->init();
+ return event;
+ }
+
static sp<ValueMetricProducer> createValueProducerNoConditions(
sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric) {
UidMap uidMap;
@@ -541,7 +569,7 @@
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
event->write(tagId);
- event->write(120);
+ event->write(130);
event->init();
data->push_back(event);
return true;
@@ -569,6 +597,7 @@
event->init();
allData.push_back(event);
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10});
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
@@ -577,16 +606,15 @@
EXPECT_EQ(110, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(10, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
- EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10});
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasValue);
- EXPECT_EQ(10, curInterval.value.long_value);
+ EXPECT_EQ(20, curInterval.value.long_value);
EXPECT_EQ(false, curInterval.hasBase);
}
@@ -805,10 +833,8 @@
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(30, curInterval.value.long_value);
- valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(30, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+ valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {30});
}
TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
@@ -872,10 +898,8 @@
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(50, curInterval.value.long_value);
- valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(50, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+ valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {50});
}
TEST(ValueMetricProducerTest, TestAnomalyDetection) {
@@ -1006,8 +1030,7 @@
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(23, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
- EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12});
// pull 3 come late.
// The previous bucket gets closed with error. (Has start value 23, no ending)
@@ -1026,9 +1049,7 @@
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(36, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.begin()->second.size());
- EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12});
}
/*
@@ -1076,27 +1097,19 @@
// pull on bucket boundary come late, condition change happens before it
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
EXPECT_EQ(false, curInterval.hasBase);
- EXPECT_EQ(true, curInterval.hasValue);
- EXPECT_EQ(20, curInterval.value.long_value);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
// Now the alarm is delivered.
// since the condition turned to off before this pull finish, it has no effect
vector<shared_ptr<LogEvent>> allData;
- allData.clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 30);
- event->write(1);
- event->write(110);
- event->init();
- allData.push_back(event);
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 110));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(false, curInterval.hasBase);
- EXPECT_EQ(true, curInterval.hasValue);
- EXPECT_EQ(20, curInterval.value.long_value);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(false, curInterval.hasValue);
}
/*
@@ -1155,37 +1168,37 @@
// pull on bucket boundary come late, condition change happens before it
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(false, curInterval.hasBase);
- EXPECT_EQ(true, curInterval.hasValue);
- EXPECT_EQ(20, curInterval.value.long_value);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(false, curInterval.hasValue);
// condition changed to true again, before the pull alarm is delivered
valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(130, curInterval.base.long_value);
- EXPECT_EQ(true, curInterval.hasValue);
- EXPECT_EQ(20, curInterval.value.long_value);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(false, curInterval.hasValue);
- // Now the alarm is delivered, but it is considered late, the bucket is invalidated.
+ // Now the alarm is delivered, but it is considered late, the data will be used
+ // for the new bucket since it was just pulled.
vector<shared_ptr<LogEvent>> allData;
- allData.clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 50);
- event->write(1);
- event->write(110);
- event->init();
- allData.push_back(event);
- valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 50, 140));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 50);
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(false, curInterval.hasBase);
- EXPECT_EQ(130, curInterval.base.long_value);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(140, curInterval.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
- EXPECT_EQ(20, curInterval.value.long_value);
- EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(10, curInterval.value.long_value);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
+
+ allData.clear();
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs, 160));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20, 30});
}
TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
@@ -1227,10 +1240,8 @@
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(10, curInterval.value.long_value);
- valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+ valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10});
}
TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
@@ -1273,9 +1284,9 @@
EXPECT_EQ(20, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(20, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+ /* EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); */
+ /* EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); */
+ /* EXPECT_EQ(20, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value); */
}
TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
@@ -1320,7 +1331,7 @@
EXPECT_EQ(25, curInterval.value.long_value);
EXPECT_EQ(2, curInterval.sampleSize);
- valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
+ valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().values[0].double_value - 12.5) < epsilon);
@@ -1365,10 +1376,8 @@
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(25, curInterval.value.long_value);
- valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(25, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+ valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {25});
}
TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
@@ -1700,10 +1709,8 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(true, interval2.hasBase);
- EXPECT_EQ(4, interval2.base.long_value);
+ EXPECT_EQ(5, interval2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
- EXPECT_EQ(true, interval1.hasBase);
- EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
@@ -1721,14 +1728,16 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
- EXPECT_EQ(true, interval2.hasBase);
- EXPECT_EQ(5, interval2.base.long_value);
- EXPECT_EQ(false, interval2.hasValue);
- EXPECT_EQ(5, interval2.value.long_value);
- EXPECT_EQ(true, interval1.hasBase);
- EXPECT_EQ(13, interval1.base.long_value);
- EXPECT_EQ(false, interval1.hasValue);
- EXPECT_EQ(8, interval1.value.long_value);
+ auto it1 = std::next(valueProducer->mCurrentSlicedBucket.begin())->second[0];
+ EXPECT_EQ(true, it1.hasBase);
+ EXPECT_EQ(13, it1.base.long_value);
+ EXPECT_EQ(false, it1.hasValue);
+ EXPECT_EQ(8, it1.value.long_value);
+ auto it2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(true, it2.hasBase);
+ EXPECT_EQ(5, it2.base.long_value);
+ EXPECT_EQ(false, it2.hasValue);
+ EXPECT_EQ(5, it2.value.long_value);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
}
@@ -1785,8 +1794,7 @@
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(8, interval1.value.long_value);
EXPECT_FALSE(interval1.seenNewData);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
- EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8});
auto it = valueProducer->mCurrentSlicedBucket.begin();
for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
@@ -1801,7 +1809,7 @@
EXPECT_EQ(4, interval2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_FALSE(interval2.seenNewData);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8});
// next pull somehow did not happen, skip to end of bucket 3
allData.clear();
@@ -1811,7 +1819,6 @@
event1->init();
allData.push_back(event1);
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
-
// Only one interval left. One was trimmed.
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
@@ -1820,7 +1827,7 @@
EXPECT_EQ(5, interval2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_FALSE(interval2.seenNewData);
- EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8});
allData.clear();
event1 = make_shared<LogEvent>(tagId, bucket5StartTimeNs + 1);
@@ -1835,7 +1842,7 @@
EXPECT_EQ(14, interval2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_FALSE(interval2.seenNewData);
- EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
auto iterator = valueProducer->mPastBuckets.begin();
EXPECT_EQ(9, iterator->second[0].values[0].long_value);
iterator++;
@@ -2106,7 +2113,7 @@
// 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);
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
event->write(i);
event->write(i);
event->init();
@@ -2117,9 +2124,9 @@
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
-
valueProducer->mCondition = ConditionState::kFalse;
- valueProducer->onConditionChanged(true, bucket2StartTimeNs + 2);
+
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 2);
EXPECT_EQ(true, valueProducer->mCurrentBucketIsInvalid);
EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
}
@@ -2493,6 +2500,201 @@
EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
}
+TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // Second onConditionChanged.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 10, 5));
+ return true;
+ }))
+ // Third onConditionChanged.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs + 10, 7));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ valueProducer->mCondition = ConditionState::kUnknown;
+
+ valueProducer->onConditionChanged(false, bucketStartTimeNs);
+ ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+
+ // End of first bucket
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 1, 4));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 1);
+ ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+
+ valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10);
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(5, curInterval.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+
+ valueProducer->onConditionChanged(false, bucket3StartTimeNs + 10);
+
+ // Bucket should have been completed.
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2});
+}
+
+TEST(ValueMetricProducerTest, TestLateOnDataPulledWithoutDiff) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.set_use_diff(false);
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucketStartTimeNs + 30, 10));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + 30);
+
+ allData.clear();
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs, 20));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ // Bucket should have been completed.
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30});
+}
+
+TEST(ValueMetricProducerTest, TestLateOnDataPulledWithDiff) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // Initialization.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(bucketStartTimeNs, 1));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucketStartTimeNs + 30, 10));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + 30);
+
+ allData.clear();
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs, 20));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ // Bucket should have been completed.
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {19});
+}
+
+TEST(ValueMetricProducerTest, TestBucketBoundariesOnAppUpgrade) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // Initialization.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(bucketStartTimeNs, 1));
+ return true;
+ }))
+ // notifyAppUpgrade.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 2, 10));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
+
+ valueProducer->notifyAppUpgrade(bucket2StartTimeNs + 2, "com.foo", 10000, 1);
+
+ // Bucket should have been completed.
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9});
+}
+
+TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // First on condition changed.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(bucketStartTimeNs, 1));
+ return true;
+ }))
+ // Second on condition changed.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(bucketStartTimeNs, 3));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
+ valueProducer->onConditionChanged(false, bucketStartTimeNs + 10);
+ valueProducer->onConditionChanged(false, bucketStartTimeNs + 10);
+
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(2, curInterval.value.long_value);
+}
+
+TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // First condition change.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(bucketStartTimeNs, 1));
+ return true;
+ }))
+ // 2nd condition change.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs, 1));
+ return true;
+ }))
+ // 3rd condition change.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs, 1));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10);
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucketStartTimeNs + 3, 10));
+ valueProducer->onDataPulled(allData, /** succeed */ false, bucketStartTimeNs + 3);
+
+ allData.clear();
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs, 20));
+ valueProducer->onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
+
+ valueProducer->onConditionChanged(false, bucket2StartTimeNs + 8);
+ valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10);
+
+ allData.clear();
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs, 30));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ // There was not global base available so all buckets are invalid.
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {});
+}
+
static StatsLogReport outputStreamToProto(ProtoOutputStream* proto) {
vector<uint8_t> bytes;
bytes.resize(proto->size());
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index aaff76e..e25f463 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -2909,15 +2909,8 @@
Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->loge(Ljava/lang/String;)V
Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mAdnCache:Lcom/android/internal/telephony/uicc/AdnRecordCache;
Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mBaseHandler:Landroid/os/Handler;
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mCurrentApp:Lcom/android/internal/telephony/uicc/UiccCardApplication;
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mIs3gCard:Z
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mLock:Ljava/lang/Object;
Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mPhone:Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mRecords:Ljava/util/List;
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mRecordSize:[I
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mSuccess:Z
Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->updateEfForIccType(I)I
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->waitForResult(Ljava/util/concurrent/atomic/AtomicBoolean;)V
Lcom/android/internal/telephony/IccProvider;-><init>()V
Lcom/android/internal/telephony/IccProvider;->ADDRESS_BOOK_COLUMN_NAMES:[Ljava/lang/String;
Lcom/android/internal/telephony/IccProvider;->DBG:Z
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 91fc188..425f6d0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -127,7 +127,6 @@
import android.view.autofill.IAutofillWindowPresenter;
import android.view.contentcapture.ContentCaptureContext;
import android.view.contentcapture.ContentCaptureManager;
-import android.view.contentcapture.ContentCaptureSession;
import android.widget.AdapterView;
import android.widget.Toast;
import android.widget.Toolbar;
@@ -1038,15 +1037,11 @@
}
/** @hide */ private static final int CONTENT_CAPTURE_START = 1;
- /** @hide */ private static final int CONTENT_CAPTURE_PAUSE = 2;
- /** @hide */ private static final int CONTENT_CAPTURE_RESUME = 3;
- /** @hide */ private static final int CONTENT_CAPTURE_STOP = 4;
+ /** @hide */ private static final int CONTENT_CAPTURE_STOP = 2;
/** @hide */
@IntDef(prefix = { "CONTENT_CAPTURE_" }, value = {
CONTENT_CAPTURE_START,
- CONTENT_CAPTURE_PAUSE,
- CONTENT_CAPTURE_RESUME,
CONTENT_CAPTURE_STOP
})
@Retention(RetentionPolicy.SOURCE)
@@ -1056,10 +1051,6 @@
switch (type) {
case CONTENT_CAPTURE_START:
return "START";
- case CONTENT_CAPTURE_PAUSE:
- return "PAUSE";
- case CONTENT_CAPTURE_RESUME:
- return "RESUME";
case CONTENT_CAPTURE_STOP:
return "STOP";
default:
@@ -1088,12 +1079,6 @@
}
cm.onActivityStarted(mToken, getComponentName(), flags);
break;
- case CONTENT_CAPTURE_PAUSE:
- cm.flush(ContentCaptureSession.FLUSH_REASON_ACTIVITY_PAUSED);
- break;
- case CONTENT_CAPTURE_RESUME:
- cm.flush(ContentCaptureSession.FLUSH_REASON_ACTIVITY_RESUMED);
- break;
case CONTENT_CAPTURE_STOP:
cm.onActivityStopped();
break;
@@ -1781,7 +1766,6 @@
}
}
mCalled = true;
- notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_RESUME);
}
/**
@@ -2198,7 +2182,6 @@
}
}
mCalled = true;
- notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_PAUSE);
}
/**
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index dcef9d2..780dd63 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -489,4 +489,10 @@
/** Returns a file descriptor that'll be closed when the system server process dies. */
ParcelFileDescriptor getLifeMonitor();
+
+ /**
+ * Start user, if it us not already running, and bring it to foreground.
+ * unlockProgressListener can be null if monitoring progress is not necessary.
+ */
+ boolean startUserInForegroundWithListener(int userid, IProgressListener unlockProgressListener);
}
diff --git a/core/java/android/app/timezone/RulesState.java b/core/java/android/app/timezone/RulesState.java
index e86d348..38dd1eb 100644
--- a/core/java/android/app/timezone/RulesState.java
+++ b/core/java/android/app/timezone/RulesState.java
@@ -33,7 +33,7 @@
*
* <p>The following properties are included:
* <dl>
- * <dt>systemRulesVersion</dt>
+ * <dt>baseRulesVersion</dt>
* <dd>the IANA rules version that shipped with the OS. Always present. e.g. "2017a".</dd>
* <dt>distroFormatVersionSupported</dt>
* <dd>the distro format version supported by this device. Always present.</dd>
@@ -98,7 +98,7 @@
private static final byte BYTE_FALSE = 0;
private static final byte BYTE_TRUE = 1;
- private final String mSystemRulesVersion;
+ private final String mBaseRulesVersion;
private final DistroFormatVersion mDistroFormatVersionSupported;
private final boolean mOperationInProgress;
@StagedOperationType private final int mStagedOperationType;
@@ -106,13 +106,13 @@
@DistroStatus private final int mDistroStatus;
@Nullable private final DistroRulesVersion mInstalledDistroRulesVersion;
- public RulesState(String systemRulesVersion, DistroFormatVersion distroFormatVersionSupported,
+ public RulesState(String baseRulesVersion, DistroFormatVersion distroFormatVersionSupported,
boolean operationInProgress,
@StagedOperationType int stagedOperationType,
@Nullable DistroRulesVersion stagedDistroRulesVersion,
@DistroStatus int distroStatus,
@Nullable DistroRulesVersion installedDistroRulesVersion) {
- this.mSystemRulesVersion = validateRulesVersion("systemRulesVersion", systemRulesVersion);
+ this.mBaseRulesVersion = validateRulesVersion("baseRulesVersion", baseRulesVersion);
this.mDistroFormatVersionSupported =
validateNotNull("distroFormatVersionSupported", distroFormatVersionSupported);
this.mOperationInProgress = operationInProgress;
@@ -132,8 +132,8 @@
"installedDistroRulesVersion", installedDistroRulesVersion);
}
- public String getSystemRulesVersion() {
- return mSystemRulesVersion;
+ public String getBaseRulesVersion() {
+ return mBaseRulesVersion;
}
public boolean isOperationInProgress() {
@@ -172,14 +172,14 @@
}
/**
- * Returns true if the system image data files contain IANA rules data that are newer than the
+ * Returns true if the base data files contain IANA rules data that are newer than the
* distro IANA rules version supplied, i.e. true when the version specified would be "worse"
- * than the one that is in the system image. Returns false if the system image version is the
+ * than the one that is in the base data. Returns false if the base version is the
* same or older, i.e. false when the version specified would be "better" than the one that is
- * in the system image.
+ * in the base set.
*/
- public boolean isSystemVersionNewerThan(DistroRulesVersion distroRulesVersion) {
- return mSystemRulesVersion.compareTo(distroRulesVersion.getRulesVersion()) > 0;
+ public boolean isBaseVersionNewerThan(DistroRulesVersion distroRulesVersion) {
+ return mBaseRulesVersion.compareTo(distroRulesVersion.getRulesVersion()) > 0;
}
public static final Parcelable.Creator<RulesState> CREATOR =
@@ -194,14 +194,14 @@
};
private static RulesState createFromParcel(Parcel in) {
- String systemRulesVersion = in.readString();
+ String baseRulesVersion = in.readString();
DistroFormatVersion distroFormatVersionSupported = in.readParcelable(null);
boolean operationInProgress = in.readByte() == BYTE_TRUE;
int distroStagedState = in.readByte();
DistroRulesVersion stagedDistroRulesVersion = in.readParcelable(null);
int installedDistroStatus = in.readByte();
DistroRulesVersion installedDistroRulesVersion = in.readParcelable(null);
- return new RulesState(systemRulesVersion, distroFormatVersionSupported, operationInProgress,
+ return new RulesState(baseRulesVersion, distroFormatVersionSupported, operationInProgress,
distroStagedState, stagedDistroRulesVersion,
installedDistroStatus, installedDistroRulesVersion);
}
@@ -213,7 +213,7 @@
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeString(mSystemRulesVersion);
+ out.writeString(mBaseRulesVersion);
out.writeParcelable(mDistroFormatVersionSupported, 0);
out.writeByte(mOperationInProgress ? BYTE_TRUE : BYTE_FALSE);
out.writeByte((byte) mStagedOperationType);
@@ -242,7 +242,7 @@
if (mDistroStatus != that.mDistroStatus) {
return false;
}
- if (!mSystemRulesVersion.equals(that.mSystemRulesVersion)) {
+ if (!mBaseRulesVersion.equals(that.mBaseRulesVersion)) {
return false;
}
if (!mDistroFormatVersionSupported.equals(that.mDistroFormatVersionSupported)) {
@@ -259,7 +259,7 @@
@Override
public int hashCode() {
- int result = mSystemRulesVersion.hashCode();
+ int result = mBaseRulesVersion.hashCode();
result = 31 * result + mDistroFormatVersionSupported.hashCode();
result = 31 * result + (mOperationInProgress ? 1 : 0);
result = 31 * result + mStagedOperationType;
@@ -275,7 +275,7 @@
@Override
public String toString() {
return "RulesState{"
- + "mSystemRulesVersion='" + mSystemRulesVersion + '\''
+ + "mBaseRulesVersion='" + mBaseRulesVersion + '\''
+ ", mDistroFormatVersionSupported=" + mDistroFormatVersionSupported
+ ", mOperationInProgress=" + mOperationInProgress
+ ", mStagedOperationType=" + mStagedOperationType
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index c44520a..1e4b1e7 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -3159,6 +3159,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.CACHE_CONTENT)
public void putCache(@NonNull Uri key, @Nullable Bundle value) {
try {
getContentService().putCache(mContext.getPackageName(), key, value,
@@ -3178,6 +3179,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.CACHE_CONTENT)
public @Nullable Bundle getCache(@NonNull Uri key) {
try {
final Bundle bundle = getContentService().getCache(mContext.getPackageName(), key,
diff --git a/core/java/android/content/pm/AndroidTestBaseUpdater.java b/core/java/android/content/pm/AndroidTestBaseUpdater.java
index 2aaac02..6a1778c 100644
--- a/core/java/android/content/pm/AndroidTestBaseUpdater.java
+++ b/core/java/android/content/pm/AndroidTestBaseUpdater.java
@@ -19,11 +19,12 @@
import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
import android.content.pm.PackageParser.Package;
+import android.os.Build;
import com.android.internal.annotations.VisibleForTesting;
/**
- * Updates a package to ensure that if it targets < P that the android.test.base library is
+ * Updates a package to ensure that if it targets <= P that the android.test.base library is
* included by default.
*
* <p>This is separated out so that it can be conditionally included at build time depending on
@@ -37,12 +38,17 @@
@VisibleForTesting
public class AndroidTestBaseUpdater extends PackageSharedLibraryUpdater {
+ private static boolean apkTargetsApiLevelLessThanOrEqualToP(Package pkg) {
+ int targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
+ return targetSdkVersion <= Build.VERSION_CODES.P;
+ }
+
@Override
public void updatePackage(Package pkg) {
- // Packages targeted at <= O_MR1 expect the classes in the android.test.base library
+ // Packages targeted at <= P expect the classes in the android.test.base library
// to be accessible so this maintains backward compatibility by adding the
// android.test.base library to those packages.
- if (apkTargetsApiLevelLessThanOrEqualToOMR1(pkg)) {
+ if (apkTargetsApiLevelLessThanOrEqualToP(pkg)) {
prefixRequiredLibrary(pkg, ANDROID_TEST_BASE);
} else {
// If a package already depends on android.test.runner then add a dependency on
diff --git a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java b/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java
index 7790067..707443b 100644
--- a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java
+++ b/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java
@@ -18,6 +18,7 @@
import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
import android.content.pm.PackageParser.Package;
+import android.os.Build;
import com.android.internal.annotations.VisibleForTesting;
@@ -30,6 +31,11 @@
@VisibleForTesting
public class OrgApacheHttpLegacyUpdater extends PackageSharedLibraryUpdater {
+ private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(Package pkg) {
+ int targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
+ return targetSdkVersion < Build.VERSION_CODES.P;
+ }
+
@Override
public void updatePackage(Package pkg) {
// Packages targeted at <= O_MR1 expect the classes in the org.apache.http.legacy library
diff --git a/core/java/android/content/pm/PackageBackwardCompatibility.java b/core/java/android/content/pm/PackageBackwardCompatibility.java
index b19196a..4331bd4 100644
--- a/core/java/android/content/pm/PackageBackwardCompatibility.java
+++ b/core/java/android/content/pm/PackageBackwardCompatibility.java
@@ -116,7 +116,7 @@
private final PackageSharedLibraryUpdater[] mPackageUpdaters;
- public PackageBackwardCompatibility(
+ private PackageBackwardCompatibility(
boolean bootClassPathContainsATB, PackageSharedLibraryUpdater[] packageUpdaters) {
this.mBootClassPathContainsATB = bootClassPathContainsATB;
this.mPackageUpdaters = packageUpdaters;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 6302071..0304f19 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1743,11 +1743,11 @@
public int[] childSessionIds = NO_SESSIONS;
/** {@hide} */
- public boolean isSessionApplied;
+ public boolean isStagedSessionApplied;
/** {@hide} */
- public boolean isSessionReady;
+ public boolean isStagedSessionReady;
/** {@hide} */
- public boolean isSessionFailed;
+ public boolean isStagedSessionFailed;
private int mStagedSessionErrorCode;
private String mStagedSessionErrorMessage;
@@ -1786,9 +1786,9 @@
if (childSessionIds == null) {
childSessionIds = NO_SESSIONS;
}
- isSessionApplied = source.readBoolean();
- isSessionReady = source.readBoolean();
- isSessionFailed = source.readBoolean();
+ isStagedSessionApplied = source.readBoolean();
+ isStagedSessionReady = source.readBoolean();
+ isStagedSessionFailed = source.readBoolean();
mStagedSessionErrorCode = source.readInt();
mStagedSessionErrorMessage = source.readString();
}
@@ -2082,36 +2082,46 @@
return childSessionIds;
}
+ private void checkSessionIsStaged() {
+ if (!isStaged) {
+ throw new IllegalStateException("Session is not marked as staged.");
+ }
+ }
+
/**
* Whether the staged session has been applied successfully, meaning that all of its
* packages have been activated and no further action is required.
* Only meaningful if {@code isStaged} is true.
*/
- public boolean isSessionApplied() {
- return isSessionApplied;
+ public boolean isStagedSessionApplied() {
+ checkSessionIsStaged();
+ return isStagedSessionApplied;
}
/**
* Whether the staged session is ready to be applied at next reboot. Only meaningful if
* {@code isStaged} is true.
*/
- public boolean isSessionReady() {
- return isSessionReady;
+ public boolean isStagedSessionReady() {
+ checkSessionIsStaged();
+ return isStagedSessionReady;
}
/**
* Whether something went wrong and the staged session is declared as failed, meaning that
* it will be ignored at next reboot. Only meaningful if {@code isStaged} is true.
*/
- public boolean isSessionFailed() {
- return isSessionFailed;
+ public boolean isStagedSessionFailed() {
+ checkSessionIsStaged();
+ return isStagedSessionFailed;
}
/**
* If something went wrong with a staged session, clients can check this error code to
* understand which kind of failure happened. Only meaningful if {@code isStaged} is true.
*/
- public int getStagedSessionErrorCode() {
+ public @StagedSessionErrorCode int getStagedSessionErrorCode() {
+ checkSessionIsStaged();
return mStagedSessionErrorCode;
}
@@ -2120,6 +2130,7 @@
* empty string if no error was encountered.
*/
public String getStagedSessionErrorMessage() {
+ checkSessionIsStaged();
return mStagedSessionErrorMessage;
}
@@ -2162,9 +2173,9 @@
dest.writeBoolean(isStaged);
dest.writeInt(parentSessionId);
dest.writeIntArray(childSessionIds);
- dest.writeBoolean(isSessionApplied);
- dest.writeBoolean(isSessionReady);
- dest.writeBoolean(isSessionFailed);
+ dest.writeBoolean(isStagedSessionApplied);
+ dest.writeBoolean(isStagedSessionReady);
+ dest.writeBoolean(isStagedSessionFailed);
dest.writeInt(mStagedSessionErrorCode);
dest.writeString(mStagedSessionErrorMessage);
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5e70ecb..a5464c2 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2565,6 +2565,14 @@
public static final String FEATURE_PC = "android.hardware.type.pc";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: This is a foldable device. Properties such as
+ * the display size may change in response to being folded.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_FOLDABLE = "android.hardware.type.foldable";
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device supports printing.
*/
diff --git a/core/java/android/content/pm/PackageSharedLibraryUpdater.java b/core/java/android/content/pm/PackageSharedLibraryUpdater.java
index b14b321..1565d9c 100644
--- a/core/java/android/content/pm/PackageSharedLibraryUpdater.java
+++ b/core/java/android/content/pm/PackageSharedLibraryUpdater.java
@@ -17,7 +17,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.Build;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -60,11 +59,6 @@
|| ArrayUtils.contains(usesOptionalLibraries, apacheHttpLegacy);
}
- static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(PackageParser.Package pkg) {
- int targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
- return targetSdkVersion < Build.VERSION_CODES.P;
- }
-
/**
* Add an implicit dependency.
*
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index b155325..e674b8b 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.annotation.UserIdInt;
@@ -1482,6 +1483,7 @@
* @hide
*/
@Nullable
+ @SystemApi
public Person[] getPersons() {
return clonePersons(mPersons);
}
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 849fd03..bd327b0 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -644,6 +644,7 @@
* @return True if the package has any share target definitions, False otherwise.
* @hide
*/
+ @SystemApi
public boolean hasShareTargets(@NonNull String packageName) {
try {
return mService.hasShareTargets(mContext.getPackageName(), packageName,
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index 8c74ddc..ed8a97c 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -16,6 +16,7 @@
package android.hardware.display;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -93,7 +94,7 @@
*
*/
@Nullable
- public BrightnessCorrection getCorrectionByPackageName(String packageName) {
+ public BrightnessCorrection getCorrectionByPackageName(@NonNull String packageName) {
return mCorrectionsByPackageName.get(packageName);
}
@@ -106,7 +107,7 @@
* @return The matching brightness correction, or null.
*/
@Nullable
- public BrightnessCorrection getCorrectionByCategory(int category) {
+ public BrightnessCorrection getCorrectionByCategory(@ApplicationInfo.Category int category) {
return mCorrectionsByCategory.get(category);
}
@@ -238,7 +239,7 @@
*
* @hide
*/
- public void saveToXml(XmlSerializer serializer) throws IOException {
+ public void saveToXml(@NonNull XmlSerializer serializer) throws IOException {
serializer.startTag(null, TAG_BRIGHTNESS_CURVE);
if (mDescription != null) {
serializer.attribute(null, ATTR_DESCRIPTION, mDescription);
@@ -284,7 +285,7 @@
*
* @hide
*/
- public static BrightnessConfiguration loadFromXml(XmlPullParser parser)
+ public static BrightnessConfiguration loadFromXml(@NonNull XmlPullParser parser)
throws IOException, XmlPullParserException {
String description = null;
List<Float> luxList = new ArrayList<>();
@@ -443,8 +444,10 @@
* {@link #getMaxCorrectionsByPackageName}).
*
*/
- public Builder addCorrectionByPackageName(String packageName,
- BrightnessCorrection correction) {
+ public Builder addCorrectionByPackageName(@NonNull String packageName,
+ @NonNull BrightnessCorrection correction) {
+ Objects.requireNonNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(correction, "correction must not be null");
if (mCorrectionsByPackageName.size() >= getMaxCorrectionsByPackageName()) {
throw new IllegalArgumentException("Too many corrections by package name");
}
@@ -470,7 +473,8 @@
*
*/
public Builder addCorrectionByCategory(@ApplicationInfo.Category int category,
- BrightnessCorrection correction) {
+ @NonNull BrightnessCorrection correction) {
+ Objects.requireNonNull(correction, "correction must not be null");
if (mCorrectionsByCategory.size() >= getMaxCorrectionsByCategory()) {
throw new IllegalArgumentException("Too many corrections by category");
}
diff --git a/core/java/android/hardware/display/BrightnessCorrection.java b/core/java/android/hardware/display/BrightnessCorrection.java
index 6a073ff..ee8d846 100644
--- a/core/java/android/hardware/display/BrightnessCorrection.java
+++ b/core/java/android/hardware/display/BrightnessCorrection.java
@@ -16,6 +16,7 @@
package android.hardware.display;
+import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -59,15 +60,15 @@
/**
* Creates a BrightnessCorrection that given {@code brightness}, corrects it to be
- * {@code exp(scale * log(brightness) + translate)}.
+ * {@code exp(scale * ln(brightness) + translate)}.
*
* @param scale
- * How much to scale the log brightness.
+ * How much to scale the log (base e) brightness.
* @param translate
- * How much to translate the log brightness.
+ * How much to translate the log (base e) brightness.
*
* @return A BrightnessCorrection that given {@code brightness}, corrects it to be
- * {@code exp(scale * log(brightness) + translate)}.
+ * {@code exp(scale * ln(brightness) + translate)}.
*
* @throws IllegalArgumentException
* - scale or translate are NaN.
@@ -87,7 +88,8 @@
*
* @return The corrected brightness.
*/
- public float apply(float brightness) {
+ @FloatRange(from = 0.0)
+ public float apply(@FloatRange(from = 0.0) float brightness) {
return mImplementation.apply(brightness);
}
@@ -202,7 +204,7 @@
/**
* A BrightnessCorrection that given {@code brightness}, corrects it to be
- * {@code exp(scale * log(brightness) + translate)}.
+ * {@code exp(scale * ln(brightness) + translate)}.
*/
private static class ScaleAndTranslateLog implements BrightnessCorrectionImplementation {
private static final float MIN_SCALE = 0.5f;
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 27f7e22..684369a 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -59,7 +59,8 @@
BUGREPORT_ERROR_INVALID_INPUT,
BUGREPORT_ERROR_RUNTIME,
BUGREPORT_ERROR_USER_DENIED_CONSENT,
- BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT
+ BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT,
+ BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS
})
/** Possible error codes taking a bugreport can encounter */
@@ -81,6 +82,10 @@
public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT =
IDumpstateListener.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT;
+ /** There is currently a bugreport running. The caller should try again later. */
+ public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS =
+ IDumpstateListener.BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS;
+
/**
* Called when there is a progress update.
* @param progress the progress in [0.0, 100.0]
@@ -96,6 +101,9 @@
* <p>If {@code BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT} is passed, then the consent timed
* out, but the bugreport could be available in the internal directory of dumpstate for
* manual retrieval.
+ *
+ * <p> If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the
+ * caller should try later, as only one bugreport can be in progress at a time.
*/
public void onError(@BugreportErrorCode int errorCode) {}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 6bd1f2b..91ddf82 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1569,7 +1569,7 @@
@LocationPowerSaveMode
public int getLocationPowerSaveMode() {
final PowerSaveState powerSaveState = getPowerSaveState(ServiceType.LOCATION);
- if (!powerSaveState.globalBatterySaverEnabled) {
+ if (!powerSaveState.batterySaverEnabled) {
return LOCATION_MODE_NO_CHANGE;
}
return powerSaveState.locationMode;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1588718..4c4bd6c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11523,6 +11523,7 @@
* @hide
* @see com.android.server.power.batterysaver.BatterySaverPolicy
*/
+ @TestApi
public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants";
/**
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 1d0c987..cbd0cd9 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -71,6 +71,14 @@
*/
public static final int FLAG_COMPATIBILITY_MODE_REQUEST = 0x2;
+ // Private flags below start from the highest-significative bit (0x80000000)
+ /**
+ * Request was only triggered for augmented autofill.
+ *
+ * @hide
+ */
+ public static final int FLAG_AUGMENTED_AUTOFILL_REQUEST = 0x80000000;
+
/** @hide */
public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
@@ -115,7 +123,8 @@
/**
* Gets the flags associated with this request.
*
- * @see #FLAG_MANUAL_REQUEST
+ * @return any combination of {@link #FLAG_MANUAL_REQUEST} and
+ * {@link #FLAG_COMPATIBILITY_MODE_REQUEST}.
*/
public @RequestFlags int getFlags() {
return mFlags;
diff --git a/core/java/android/service/autofill/augmented/FillWindow.java b/core/java/android/service/autofill/augmented/FillWindow.java
index 6e06754..bd532a3 100644
--- a/core/java/android/service/autofill/augmented/FillWindow.java
+++ b/core/java/android/service/autofill/augmented/FillWindow.java
@@ -82,6 +82,8 @@
private Rect mBounds;
@GuardedBy("mLock")
+ private boolean mUpdateCalled;
+ @GuardedBy("mLock")
private boolean mDestroyed;
private AutofillProxy mProxy;
@@ -103,6 +105,7 @@
}
// TODO(b/123100712): add test case for null
Preconditions.checkNotNull(area);
+ Preconditions.checkNotNull(area.proxy);
Preconditions.checkNotNull(rootView);
// TODO(b/123100712): must check the area is a valid object returned by
// SmartSuggestionParams, throw IAE if not
@@ -149,6 +152,7 @@
if (DEBUG) {
Log.d(TAG, "Created FillWindow: params= " + smartSuggestion + " view=" + rootView);
}
+ mUpdateCalled = true;
mDestroyed = false;
mProxy.setFillWindow(this);
return true;
@@ -237,8 +241,10 @@
}
synchronized (mLock) {
if (mDestroyed) return;
- hide();
- mProxy.report(AutofillProxy.REPORT_EVENT_UI_DESTROYED);
+ if (mUpdateCalled) {
+ hide();
+ mProxy.report(AutofillProxy.REPORT_EVENT_UI_DESTROYED);
+ }
mDestroyed = true;
mCloseGuard.close();
}
@@ -266,6 +272,7 @@
public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
synchronized (this) {
pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed);
+ pw.print(prefix); pw.print("updateCalled: "); pw.println(mUpdateCalled);
if (mFillView != null) {
pw.print(prefix); pw.print("fill window: ");
pw.println(mShowing ? "shown" : "hidden");
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index d0194f9..a15a20a 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -922,7 +922,7 @@
if (mCanvas != null) {
throw new IllegalStateException("Surface was already locked!");
}
- mCanvas = mRenderNode.start(width, height);
+ mCanvas = mRenderNode.beginRecording(width, height);
return mCanvas;
}
@@ -931,7 +931,7 @@
throw new IllegalArgumentException("canvas object must be the same instance that "
+ "was previously returned by lockCanvas");
}
- mRenderNode.end(mCanvas);
+ mRenderNode.endRecording();
mCanvas = null;
nHwuiDraw(mHwuiRenderer);
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index aaf85af..ee91c85 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -88,7 +88,8 @@
private static native void nativeDisconnect(long nativeObject);
private static native GraphicBuffer nativeScreenshot(IBinder displayToken,
- Rect sourceCrop, int width, int height, boolean useIdentityTransform, int rotation);
+ Rect sourceCrop, int width, int height, boolean useIdentityTransform, int rotation,
+ boolean captureSecureLayers);
private static native GraphicBuffer nativeCaptureLayers(IBinder layerHandleToken,
Rect sourceCrop, float frameScale);
@@ -1853,7 +1854,29 @@
throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeScreenshot(display, sourceCrop, width, height, useIdentityTransform, rotation);
+ return nativeScreenshot(display, sourceCrop, width, height, useIdentityTransform, rotation,
+ false /* captureSecureLayers */);
+ }
+
+ /**
+ * Like screenshotToBuffer, but if the caller is AID_SYSTEM, allows
+ * for the capture of secure layers. This is used for the screen rotation
+ * animation where the system server takes screenshots but does
+ * not persist them or allow them to leave the server. However in other
+ * cases in the system server, we mostly want to omit secure layers
+ * like when we take a screenshot on behalf of the assistant.
+ *
+ * @hide
+ */
+ public static GraphicBuffer screenshotToBufferWithSecureLayersUnsafe(IBinder display,
+ Rect sourceCrop, int width, int height, boolean useIdentityTransform,
+ int rotation) {
+ if (display == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+
+ return nativeScreenshot(display, sourceCrop, width, height, useIdentityTransform, rotation,
+ true /* captureSecureLayers */);
}
private static void rotateCropForSF(Rect crop, int rot) {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 2097812..3d3d5dc 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -590,7 +590,7 @@
}
if (mRootNodeNeedsUpdate || !mRootNode.hasDisplayList()) {
- RecordingCanvas canvas = mRootNode.startRecording(mSurfaceWidth, mSurfaceHeight);
+ RecordingCanvas canvas = mRootNode.beginRecording(mSurfaceWidth, mSurfaceHeight);
try {
final int saveCount = canvas.save();
canvas.translate(mInsetLeft, mInsetTop);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 278b9ff..8b17ea6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -40,6 +40,7 @@
import android.annotation.TestApi;
import android.annotation.UiThread;
import android.annotation.UnsupportedAppUsage;
+import android.content.AutofillOptions;
import android.content.ClipData;
import android.content.Context;
import android.content.ContextWrapper;
@@ -9408,20 +9409,13 @@
}
setNotifiedContentCaptureAppeared();
- // TODO(b/123307965): instead of post, we should queue it on AttachInfo and then
- // dispatch on RootImpl, as we're doing with the removed ones (in that case, we should
- // merge the delayNotifyContentCaptureDisappeared() into a more generic method that
- // takes a session and a command, where the command is either view added or removed
-
- // The code below doesn't take much for a unique view, but it's called for all views
- // the first time the view hiearchy is laid off, which could acccumulative delay the
- // initial layout. Hence, we're postponing it to a later stage - it might still cost a
- // lost frame (or more), but that jank cost would only happen after the 1st layout.
- Choreographer.getInstance().postCallback(Choreographer.CALLBACK_COMMIT, () -> {
- final ViewStructure structure = session.newViewStructure(this);
- onProvideContentCaptureStructure(structure, /* flags= */ 0);
- session.notifyViewAppeared(structure);
- }, /* token= */ null);
+ if (ai != null) {
+ ai.delayNotifyContentCaptureEvent(session, this, appeared);
+ } else {
+ if (DEBUG_CONTENT_CAPTURE) {
+ Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this);
+ }
+ }
} else {
if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) == 0
|| (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0) {
@@ -9440,13 +9434,11 @@
mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED;
if (ai != null) {
- ai.delayNotifyContentCaptureDisappeared(session, getAutofillId());
+ ai.delayNotifyContentCaptureEvent(session, this, appeared);
} else {
if (DEBUG_CONTENT_CAPTURE) {
- Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on gone for " + this);
+ Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this);
}
- Choreographer.getInstance().postCallback(Choreographer.CALLBACK_COMMIT,
- () -> session.notifyViewDisappeared(getAutofillId()), /* token= */ null);
}
}
}
@@ -9533,8 +9525,22 @@
}
private boolean isAutofillable() {
- return getAutofillType() != AUTOFILL_TYPE_NONE && isImportantForAutofill()
- && getAutofillViewId() > LAST_APP_AUTOFILL_ID;
+ if (getAutofillType() == AUTOFILL_TYPE_NONE) return false;
+
+ if (!isImportantForAutofill()) {
+ // View is not important for "regular" autofill, so we must check if Augmented Autofill
+ // is enabled for the activity
+ final AutofillOptions options = mContext.getAutofillOptions();
+ if (options == null || !options.augmentedEnabled) {
+ // TODO(b/123100824): should also check if activity is whitelisted
+ return false;
+ }
+ final AutofillManager afm = getAutofillManager();
+ if (afm == null) return false;
+ afm.notifyViewEnteredForAugmentedAutofill(this);
+ }
+
+ return getAutofillViewId() > LAST_APP_AUTOFILL_ID;
}
/** @hide */
@@ -9703,13 +9709,19 @@
*
* @hide
*/
- public void dispatchInitialProvideContentCaptureStructure(@NonNull ContentCaptureManager ccm) {
+ public void dispatchInitialProvideContentCaptureStructure() {
AttachInfo ai = mAttachInfo;
if (ai == null) {
Log.w(CONTENT_CAPTURE_LOG_TAG,
"dispatchProvideContentCaptureStructure(): no AttachInfo for " + this);
return;
}
+ ContentCaptureManager ccm = ai.mContentCaptureManager;
+ if (ccm == null) {
+ Log.w(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): "
+ + "no ContentCaptureManager for " + this);
+ return;
+ }
// We must set it before checkign if the view itself is important, because it might
// initially not be (for example, if it's empty), although that might change later (for
@@ -16043,7 +16055,7 @@
@ViewDebug.ExportedProperty(category = "drawing")
@InspectableProperty
public float getRotation() {
- return mRenderNode.getRotation();
+ return mRenderNode.getRotationZ();
}
/**
@@ -16064,7 +16076,7 @@
if (rotation != getRotation()) {
// Double-invalidation is necessary to capture view's old and new areas
invalidateViewProperty(true, false);
- mRenderNode.setRotation(rotation);
+ mRenderNode.setRotationZ(rotation);
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
@@ -20578,7 +20590,7 @@
int height = mBottom - mTop;
int layerType = getLayerType();
- final RecordingCanvas canvas = renderNode.startRecording(width, height);
+ final RecordingCanvas canvas = renderNode.beginRecording(width, height);
try {
if (layerType == LAYER_TYPE_SOFTWARE) {
@@ -21233,7 +21245,7 @@
} else {
mClipBounds = null;
}
- mRenderNode.setClipBounds(mClipBounds);
+ mRenderNode.setClipRect(mClipBounds);
invalidateViewProperty(false, false);
}
@@ -21978,7 +21990,7 @@
final Rect bounds = drawable.getBounds();
final int width = bounds.width();
final int height = bounds.height();
- final RecordingCanvas canvas = renderNode.startRecording(width, height);
+ final RecordingCanvas canvas = renderNode.beginRecording(width, height);
// Reverse left/top translation done by drawable canvas, which will
// instead be applied by rendernode's LTRB bounds below. This way, the
@@ -28358,11 +28370,12 @@
boolean mReadyForContentCaptureUpdates;
/**
- * Map of ids (per session) that need to be notified after as gone the view hierchy is
- * traversed.
+ * Map(keyed by session) of content capture events that need to be notified after the view
+ * hierarchy is traversed: value is either the view itself for appearead events, or its
+ * autofill id for disappeared.
*/
// TODO(b/121197119): use SparseArray once session id becomes integer
- ArrayMap<String, ArrayList<AutofillId>> mContentCaptureRemovedIds;
+ ArrayMap<String, ArrayList<Object>> mContentCaptureEvents;
/**
* Cached reference to the {@link ContentCaptureManager}.
@@ -28388,24 +28401,24 @@
mTreeObserver = new ViewTreeObserver(context);
}
- private void delayNotifyContentCaptureDisappeared(@NonNull ContentCaptureSession session,
- @NonNull AutofillId id) {
- if (mContentCaptureRemovedIds == null) {
+ private void delayNotifyContentCaptureEvent(@NonNull ContentCaptureSession session,
+ @NonNull View view, boolean appeared) {
+ if (mContentCaptureEvents == null) {
// Most of the time there will be just one session, so intial capacity is 1
- mContentCaptureRemovedIds = new ArrayMap<>(1);
+ mContentCaptureEvents = new ArrayMap<>(1);
}
String sessionId = session.getId();
// TODO: life would be much easier if we provided a MultiMap implementation somwhere...
- ArrayList<AutofillId> ids = mContentCaptureRemovedIds.get(sessionId);
- if (ids == null) {
- ids = new ArrayList<>();
- mContentCaptureRemovedIds.put(sessionId, ids);
+ ArrayList<Object> events = mContentCaptureEvents.get(sessionId);
+ if (events == null) {
+ events = new ArrayList<>();
+ mContentCaptureEvents.put(sessionId, events);
}
- ids.add(id);
+ events.add(appeared ? view : view.getAutofillId());
}
@Nullable
- private ContentCaptureManager getContentCaptureManager(@NonNull Context context) {
+ ContentCaptureManager getContentCaptureManager(@NonNull Context context) {
if (mContentCaptureManager != null) {
return mContentCaptureManager;
}
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index bb29ed6..c030ac2 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -928,8 +928,8 @@
}
/**
- * If a MotionEvent has CLASSIFICATION_AMBIGUOUS_GESTURE set, then certain actions, such as
- * scrolling, will be inhibited.
+ * If a MotionEvent has {@link android.view.MotionEvent#CLASSIFICATION_AMBIGUOUS_GESTURE} set,
+ * then certain actions, such as scrolling, will be inhibited.
* However, to account for the possibility of incorrect classification,
* the default scrolling will only be inhibited if the pointer travels less than
* (getScaledTouchSlop() * this factor).
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 6f9ee4b..a390db2 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -611,11 +611,11 @@
}
if (view.isHardwareAccelerated()) {
- RecordingCanvas canvas = node.start(dm.widthPixels, dm.heightPixels);
+ RecordingCanvas canvas = node.beginRecording(dm.widthPixels, dm.heightPixels);
try {
return profileViewOperation(view, () -> view.draw(canvas));
} finally {
- node.end(canvas);
+ node.endRecording();
}
} else {
Bitmap bitmap = Bitmap.createBitmap(
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 68c0d9e..afee1e5 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -985,7 +985,7 @@
renderNode.setTranslationZ(value);
break;
case ROTATION:
- renderNode.setRotation(value);
+ renderNode.setRotationZ(value);
break;
case ROTATION_X:
renderNode.setRotationX(value);
@@ -1031,7 +1031,7 @@
case TRANSLATION_Z:
return node.getTranslationZ();
case ROTATION:
- return node.getRotation();
+ return node.getRotationZ();
case ROTATION_X:
return node.getRotationX();
case ROTATION_Y:
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index be6b56c..9115628 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -108,6 +108,7 @@
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.ContentCaptureSession;
import android.view.contentcapture.MainContentCaptureSession;
import android.view.inputmethod.InputMethodManager;
import android.widget.Scroller;
@@ -223,10 +224,25 @@
*/
static final int MAX_TRACKBALL_DELAY = 250;
+ /**
+ * Initial value for {@link #mContentCaptureEnabled}.
+ */
+ private static final int CONTENT_CAPTURE_ENABLED_NOT_CHECKED = 0;
+
+ /**
+ * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code true}.
+ */
+ private static final int CONTENT_CAPTURE_ENABLED_TRUE = 1;
+
+ /**
+ * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code false}.
+ */
+ private static final int CONTENT_CAPTURE_ENABLED_FALSE = 2;
+
@UnsupportedAppUsage
static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
- static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
+ static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<>();
static boolean sFirstDrawComplete = false;
/**
@@ -418,7 +434,11 @@
boolean mApplyInsetsRequested;
boolean mLayoutRequested;
boolean mFirst;
+
+ @Nullable
+ int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED;
boolean mPerformContentCapture;
+
boolean mReportNextDraw;
boolean mFullRedrawNeeded;
boolean mNewSurfaceNeeded;
@@ -2776,27 +2796,60 @@
}
}
- if (mAttachInfo.mContentCaptureRemovedIds != null) {
- MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
- .getMainContentCaptureSession();
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureViewsGone");
- try {
- for (int i = 0; i < mAttachInfo.mContentCaptureRemovedIds.size(); i++) {
- String sessionId = mAttachInfo.mContentCaptureRemovedIds
- .keyAt(i);
- ArrayList<AutofillId> ids = mAttachInfo.mContentCaptureRemovedIds
- .valueAt(i);
- mainSession.notifyViewsDisappeared(sessionId, ids);
- }
- mAttachInfo.mContentCaptureRemovedIds = null;
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
+ if (mAttachInfo.mContentCaptureEvents != null) {
+ notifyContentCatpureEvents();
}
mIsInTraversal = false;
}
+ private void notifyContentCatpureEvents() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents");
+ try {
+ MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
+ .getMainContentCaptureSession();
+ if (mainSession == null) {
+ Log.w(mTag, "no MainContentCaptureSession on AttachInfo");
+ return;
+ }
+ for (int i = 0; i < mAttachInfo.mContentCaptureEvents.size(); i++) {
+ String sessionId = mAttachInfo.mContentCaptureEvents
+ .keyAt(i);
+ mainSession.notifyViewHierarchyEvent(sessionId, /* started = */ true);
+ ArrayList<Object> events = mAttachInfo.mContentCaptureEvents
+ .valueAt(i);
+ for_each_event: for (int j = 0; j < events.size(); j++) {
+ Object event = events.get(j);
+ if (event instanceof AutofillId) {
+ mainSession.notifyViewDisappeared(sessionId, (AutofillId) event);
+ } else if (event instanceof View) {
+ View view = (View) event;
+ ContentCaptureSession session = view.getContentCaptureSession();
+ if (session == null) {
+ Log.w(mTag, "no content capture session on view: " + view);
+ continue for_each_event;
+ }
+ String actualId = session.getId().toString();
+ if (!actualId.equals(sessionId)) {
+ Log.w(mTag, "content capture session mismatch for view (" + view
+ + "): was " + sessionId + " before, it's " + actualId + " now");
+ continue for_each_event;
+ }
+ ViewStructure structure = session.newViewStructure(view);
+ view.onProvideContentCaptureStructure(structure, /* flags= */ 0);
+ session.notifyViewAppeared(structure);
+ } else {
+ Log.w(mTag, "invalid content capture event: " + event);
+ }
+ }
+ mainSession.notifyViewHierarchyEvent(sessionId, /* started = */ false);
+ }
+ mAttachInfo.mContentCaptureEvents = null;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ }
+
private void notifySurfaceDestroyed() {
mSurfaceHolder.ungetCallbacks();
SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
@@ -2927,6 +2980,13 @@
}
}
mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
+ // NOTE: there's no view visibility (appeared / disapparead) events when the windows focus
+ // is lost, so we don't need to to force a flush - there might be other events such as
+ // text changes, but these should be flushed independently.
+ if (hasWindowFocus) {
+ performContentCaptureFlushIfNecessary(
+ ContentCaptureSession.FLUSH_REASON_VIEW_ROOT_ENTERED);
+ }
}
private void fireAccessibilityFocusEventIfHasFocusedNode() {
@@ -3494,36 +3554,90 @@
}
}
if (mPerformContentCapture) {
- performContentCapture();
+ performContentCaptureInitialReport();
}
}
- private void performContentCapture() {
+ /**
+ * Checks (and caches) if content capture is enabled for this context.
+ */
+ private boolean isContentCaptureEnabled() {
+ switch (mContentCaptureEnabled) {
+ case CONTENT_CAPTURE_ENABLED_TRUE:
+ return true;
+ case CONTENT_CAPTURE_ENABLED_FALSE:
+ return false;
+ case CONTENT_CAPTURE_ENABLED_NOT_CHECKED:
+ final boolean reallyEnabled = isContentCaptureReallyEnabled();
+ mContentCaptureEnabled = reallyEnabled ? CONTENT_CAPTURE_ENABLED_TRUE
+ : CONTENT_CAPTURE_ENABLED_FALSE;
+ return reallyEnabled;
+ default:
+ Log.w(TAG, "isContentCaptureEnabled(): invalid state " + mContentCaptureEnabled);
+ return false;
+ }
+
+ }
+
+ /**
+ * Checks (without caching) if content capture is enabled for this context.
+ */
+ private boolean isContentCaptureReallyEnabled() {
+ // First check if context supports it, so it saves a service lookup when it doesn't
+ if (mContext.getContentCaptureOptions() == null) return false;
+
+ final ContentCaptureManager ccm = mAttachInfo.getContentCaptureManager(mContext);
+ // Then check if it's enabled in the contex itself.
+ if (ccm == null || !ccm.isContentCaptureEnabled()) return false;
+
+ return true;
+ }
+
+ private void performContentCaptureInitialReport() {
mPerformContentCapture = false; // One-time offer!
final View rootView = mView;
if (DEBUG_CONTENT_CAPTURE) {
- Log.v(mTag, "dispatchContentCapture() on " + rootView);
+ Log.v(mTag, "performContentCaptureInitialReport() on " + rootView);
}
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchContentCapture() for "
+ getClass().getSimpleName());
}
try {
- // First check if context supports it, so it saves a service lookup when it doesn't
- if (mContext.getContentCaptureOptions() == null) return;
-
- // Then check if it's enabled in the contex itself.
- final ContentCaptureManager ccm = mContext
- .getSystemService(ContentCaptureManager.class);
- if (ccm == null || !ccm.isContentCaptureEnabled()) return;
+ if (!isContentCaptureEnabled()) return;
// Content capture is a go!
- rootView.dispatchInitialProvideContentCaptureStructure(ccm);
+ rootView.dispatchInitialProvideContentCaptureStructure();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
+ private void performContentCaptureFlushIfNecessary(
+ @ContentCaptureSession.FlushReason int flushReason) {
+ if (DEBUG_CONTENT_CAPTURE) {
+ Log.v(mTag, "performContentCaptureFlushIfNecessary("
+ + ContentCaptureSession.getFlushReasonAsString(flushReason) + ")");
+ }
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "flushContentCapture for "
+ + getClass().getSimpleName());
+ }
+ try {
+ if (!isContentCaptureEnabled()) return;
+
+ final ContentCaptureManager ccm = mAttachInfo.mContentCaptureManager;
+ if (ccm == null) {
+ Log.w(TAG, "flush content capture: no ContentCapture on AttachInfo");
+ return;
+ }
+ ccm.flush(flushReason);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ }
+
+
private boolean draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;
if (!surface.isValid()) {
@@ -7093,7 +7207,7 @@
RenderNode renderNode = view.mRenderNode;
info[0]++;
if (renderNode != null) {
- info[1] += renderNode.computeApproximateMemoryUsage();
+ info[1] += (int) renderNode.computeApproximateMemoryUsage();
}
if (view instanceof ViewGroup) {
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 9dcbe05..046c4c0 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -16,6 +16,7 @@
package android.view.autofill;
+import static android.service.autofill.FillRequest.FLAG_AUGMENTED_AUTOFILL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.view.autofill.Helper.sDebug;
import static android.view.autofill.Helper.sVerbose;
@@ -467,6 +468,13 @@
@GuardedBy("mLock")
@Nullable private ArraySet<AutofillId> mEnteredIds;
+ /**
+ * Views that were otherwised not important for autofill but triggered a session because the
+ * context is whitelisted for augmented autofill.
+ */
+ @GuardedBy("mLock")
+ @Nullable private Set<AutofillId> mEnteredForAugmentedAutofillIds;
+
/** If set, session is commited when the field is clicked. */
@GuardedBy("mLock")
@Nullable private AutofillId mSaveTriggerId;
@@ -1626,6 +1634,11 @@
@GuardedBy("mLock")
private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds,
@NonNull AutofillValue value, int flags) {
+ if (mEnteredForAugmentedAutofillIds != null
+ && mEnteredForAugmentedAutofillIds.contains(id)) {
+ if (sVerbose) Log.v(TAG, "Starting session for augmented autofill on " + id);
+ flags |= FLAG_AUGMENTED_AUTOFILL_REQUEST;
+ }
if (sVerbose) {
Log.v(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
+ ", flags=" + flags + ", state=" + getStateAsStringLocked()
@@ -1861,6 +1874,25 @@
return set == null ? null : new ArrayList<T>(set);
}
+ /**
+ * Notifies that a non-autofillable view was entered because the activity is whitelisted for
+ * augmented autofill.
+ *
+ * <p>This method is necessary to set the right flag on start, so the server-side session
+ * doesn't trigger the standard autofill workflow, but the augmented's instead.
+ *
+ * @hide
+ */
+ public void notifyViewEnteredForAugmentedAutofill(@NonNull View view) {
+ final AutofillId id = view.getAutofillId();
+ synchronized (mLock) {
+ if (mEnteredForAugmentedAutofillIds == null) {
+ mEnteredForAugmentedAutofillIds = new ArraySet<>(1);
+ }
+ mEnteredForAugmentedAutofillIds.add(id);
+ }
+ }
+
private void requestShowFillUi(int sessionId, AutofillId id, int width, int height,
Rect anchorBounds, IAutofillWindowPresenter presenter) {
final View anchor = findView(id);
@@ -2360,6 +2392,10 @@
}
pw.print(pfx); pw.print("fillable ids: "); pw.println(mFillableIds);
pw.print(pfx); pw.print("entered ids: "); pw.println(mEnteredIds);
+ if (mEnteredForAugmentedAutofillIds != null) {
+ pw.print(pfx); pw.print("entered ids for augmented autofill: ");
+ pw.println(mEnteredForAugmentedAutofillIds);
+ }
pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId);
pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish);
if (mOptions != null) {
diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
index 13e8a65..03eef5e 100644
--- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
@@ -85,7 +85,7 @@
@Override
public void internalNotifyViewHierarchyEvent(boolean started) {
- getMainCaptureSession().notifyInitialViewHierarchyEvent(mId, started);
+ getMainCaptureSession().notifyViewHierarchyEvent(mId, started);
}
@Override
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index 9cdbefa..1dd1bee 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -72,23 +72,25 @@
public static final int TYPE_VIEW_TEXT_CHANGED = 3;
/**
- * Called before events (such as {@link #TYPE_VIEW_APPEARED}) representing the initial view
- * hierarchy are sent.
+ * Called before events (such as {@link #TYPE_VIEW_APPEARED} and/or
+ * {@link #TYPE_VIEW_DISAPPEARED}) representing a view hierarchy are sent.
*
* <p><b>NOTE</b>: there is no guarantee this event will be sent. For example, it's not sent
* if the initial view hierarchy doesn't initially have any view that's important for content
* capture.
*/
+ // TODO(b/125395044): change to TYPE_VIEW_TREE_APPEARING
public static final int TYPE_INITIAL_VIEW_TREE_APPEARING = 4;
/**
- * Called after events (such as {@link #TYPE_VIEW_APPEARED}) representing the initial view
- * hierarchy are sent.
+ * Called after events (such as {@link #TYPE_VIEW_APPEARED} and/or
+ * {@link #TYPE_VIEW_DISAPPEARED}) representing a view hierarchy were sent.
*
* <p><b>NOTE</b>: there is no guarantee this event will be sent. For example, it's not sent
* if the initial view hierarchy doesn't initially have any view that's important for content
* capture.
*/
+ // TODO(b/125395044): change to TYPE_VIEW_TREE_APPEARED
public static final int TYPE_INITIAL_VIEW_TREE_APPEARED = 5;
/**
@@ -418,9 +420,9 @@
case TYPE_VIEW_TEXT_CHANGED:
return "VIEW_TEXT_CHANGED";
case TYPE_INITIAL_VIEW_TREE_APPEARING:
- return "INITIAL_VIEW_HIERARCHY_STARTED";
+ return "VIEW_TREE_APPEARING";
case TYPE_INITIAL_VIEW_TREE_APPEARED:
- return "INITIAL_VIEW_HIERARCHY_FINISHED";
+ return "VIEW_TREE_APPEARED";
case TYPE_CONTEXT_UPDATED:
return "CONTEXT_UPDATED";
default:
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 336d997..cdd4f35 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -129,6 +129,14 @@
@TestApi
public static final String DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL = "logging_level";
+ /**
+ * Sets how long (in ms) the service is bound while idle.
+ *
+ * <p>Use {@code 0} to keep it permanently bound.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT = "idle_unbind_timeout";
/** @hide */
@TestApi
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 1e051a4..544a4f6 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -132,9 +132,7 @@
/** @hide */
public static final int FLUSH_REASON_FULL = 1;
/** @hide */
- public static final int FLUSH_REASON_ACTIVITY_PAUSED = 2;
- /** @hide */
- public static final int FLUSH_REASON_ACTIVITY_RESUMED = 3;
+ public static final int FLUSH_REASON_VIEW_ROOT_ENTERED = 2;
/** @hide */
public static final int FLUSH_REASON_SESSION_STARTED = 4;
/** @hide */
@@ -145,14 +143,13 @@
/** @hide */
@IntDef(prefix = { "FLUSH_REASON_" }, value = {
FLUSH_REASON_FULL,
- FLUSH_REASON_ACTIVITY_PAUSED,
- FLUSH_REASON_ACTIVITY_RESUMED,
FLUSH_REASON_SESSION_STARTED,
FLUSH_REASON_SESSION_FINISHED,
- FLUSH_REASON_IDLE_TIMEOUT
+ FLUSH_REASON_IDLE_TIMEOUT,
+ FLUSH_REASON_VIEW_ROOT_ENTERED,
})
@Retention(RetentionPolicy.SOURCE)
- @interface FlushReason{}
+ public @interface FlushReason{}
private final Object mLock = new Object();
@@ -500,20 +497,18 @@
/** @hide */
@NonNull
- static String getflushReasonAsString(@FlushReason int reason) {
+ public static String getFlushReasonAsString(@FlushReason int reason) {
switch (reason) {
case FLUSH_REASON_FULL:
return "FULL";
- case FLUSH_REASON_ACTIVITY_PAUSED:
- return "PAUSED";
- case FLUSH_REASON_ACTIVITY_RESUMED:
- return "RESUMED";
case FLUSH_REASON_SESSION_STARTED:
return "STARTED";
case FLUSH_REASON_SESSION_FINISHED:
return "FINISHED";
case FLUSH_REASON_IDLE_TIMEOUT:
return "IDLE";
+ case FLUSH_REASON_VIEW_ROOT_ENTERED:
+ return "ENTERED";
default:
return "UNKOWN-" + reason;
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 0abf689..14b2b28 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -126,7 +126,6 @@
@Nullable
private final LocalLog mFlushHistory;
- /** @hide */
protected MainContentCaptureSession(@NonNull Context context,
@NonNull ContentCaptureManager manager, @NonNull Handler handler,
@NonNull IContentCaptureManager systemServerInterface) {
@@ -153,8 +152,6 @@
/**
* Starts this session.
- *
- * @hide
*/
@UiThread
void start(@NonNull IBinder token, @NonNull ComponentName component,
@@ -451,7 +448,7 @@
}
final int numberEvents = mEvents.size();
- final String reasonString = getflushReasonAsString(reason);
+ final String reasonString = getFlushReasonAsString(reason);
if (sDebug) {
Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState(reason));
}
@@ -547,7 +544,7 @@
@Override
public void internalNotifyViewHierarchyEvent(boolean started) {
- notifyInitialViewHierarchyEvent(mId, started);
+ notifyViewHierarchyEvent(mId, started);
}
@Override
@@ -581,21 +578,9 @@
.setViewNode(node.mNode));
}
- void notifyViewDisappeared(@NonNull String sessionId, @NonNull AutofillId id) {
- sendEvent(
- new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED).setAutofillId(id));
- }
-
- /** @hide */
- public void notifyViewsDisappeared(@NonNull String sessionId,
- @NonNull ArrayList<AutofillId> ids) {
- final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED);
- if (ids.size() == 1) {
- event.setAutofillId(ids.get(0));
- } else {
- event.setAutofillIds(ids);
- }
- sendEvent(event);
+ /** Public because is also used by ViewRootImpl */
+ public void notifyViewDisappeared(@NonNull String sessionId, @NonNull AutofillId id) {
+ sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED).setAutofillId(id));
}
void notifyViewTextChanged(@NonNull String sessionId, @NonNull AutofillId id,
@@ -604,13 +589,11 @@
.setText(text));
}
- void notifyInitialViewHierarchyEvent(@NonNull String sessionId, boolean started) {
- if (started) {
- sendEvent(new ContentCaptureEvent(sessionId, TYPE_INITIAL_VIEW_TREE_APPEARING));
- } else {
- sendEvent(new ContentCaptureEvent(sessionId, TYPE_INITIAL_VIEW_TREE_APPEARED),
- FORCE_FLUSH);
- }
+ /** Public because is also used by ViewRootImpl */
+ public void notifyViewHierarchyEvent(@NonNull String sessionId, boolean started) {
+ final int type = started ? TYPE_INITIAL_VIEW_TREE_APPEARING
+ : TYPE_INITIAL_VIEW_TREE_APPEARED;
+ sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH);
}
void notifyContextUpdated(@NonNull String sessionId,
@@ -684,6 +667,6 @@
@NonNull
private String getDebugState(@FlushReason int reason) {
- return getDebugState() + ", reason=" + getflushReasonAsString(reason);
+ return getDebugState() + ", reason=" + getFlushReasonAsString(reason);
}
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index ded3be4e..b6ec5f9 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1947,7 +1947,7 @@
// Rebuild display list if it is invalid
if (blockDisplayListIsInvalid) {
- final RecordingCanvas recordingCanvas = blockDisplayList.start(
+ final RecordingCanvas recordingCanvas = blockDisplayList.beginRecording(
right - left, bottom - top);
try {
// drawText is always relative to TextView's origin, this translation
@@ -1958,7 +1958,7 @@
// No need to untranslate, previous context is popped after
// drawDisplayList
} finally {
- blockDisplayList.end(recordingCanvas);
+ blockDisplayList.endRecording();
// Same as drawDisplayList below, handled by our TextView's parent
blockDisplayList.setClipToBounds(false);
}
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 249f499..49c0123 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -859,7 +859,7 @@
);
setupOverlay();
- final RecordingCanvas canvas = mRenderer.getRootNode().start(width, height);
+ final RecordingCanvas canvas = mRenderer.getRootNode().beginRecording(width, height);
try {
canvas.insertReorderBarrier();
canvas.drawRenderNode(mBitmapRenderNode);
@@ -867,7 +867,7 @@
canvas.drawRenderNode(mOverlayRenderNode);
canvas.insertInorderBarrier();
} finally {
- mRenderer.getRootNode().end(canvas);
+ mRenderer.getRootNode().endRecording();
}
if (mCallback != null) {
mCurrentContent =
@@ -898,11 +898,12 @@
bitmapRenderNode.setClipToOutline(true);
// Create a dummy draw, which will be replaced later with real drawing.
- final RecordingCanvas canvas = bitmapRenderNode.start(mContentWidth, mContentHeight);
+ final RecordingCanvas canvas = bitmapRenderNode.beginRecording(
+ mContentWidth, mContentHeight);
try {
canvas.drawColor(0xFF00FF00);
} finally {
- bitmapRenderNode.end(canvas);
+ bitmapRenderNode.endRecording();
}
return bitmapRenderNode;
@@ -954,7 +955,7 @@
// Draw the drawable to the render node. This happens once during
// initialization and whenever the overlay drawable is invalidated.
final RecordingCanvas canvas =
- mOverlayRenderNode.startRecording(mContentWidth, mContentHeight);
+ mOverlayRenderNode.beginRecording(mContentWidth, mContentHeight);
try {
mOverlay.setBounds(0, 0, mContentWidth, mContentHeight);
mOverlay.draw(canvas);
@@ -1035,7 +1036,7 @@
}
final RecordingCanvas canvas =
- mBitmapRenderNode.start(mContentWidth, mContentHeight);
+ mBitmapRenderNode.beginRecording(mContentWidth, mContentHeight);
try {
final Rect srcRect = new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
final Rect dstRect = new Rect(0, 0, mContentWidth, mContentHeight);
@@ -1043,7 +1044,7 @@
paint.setFilterBitmap(true);
canvas.drawBitmap(mBitmap, srcRect, dstRect, paint);
} finally {
- mBitmapRenderNode.end(canvas);
+ mBitmapRenderNode.endRecording();
}
if (mPendingWindowPositionUpdate || mFirstDraw) {
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index 732553b..f4c904d 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -67,7 +67,7 @@
private static final int MSG_BIND = 1;
private static final int MSG_UNBIND = 2;
- protected static final long PERMANENT_BOUND_TIMEOUT_MS = 0;
+ public static final long PERMANENT_BOUND_TIMEOUT_MS = 0;
protected static final int LAST_PRIVATE_MSG = MSG_UNBIND;
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
index f4902d4..524a5cc 100644
--- a/core/java/com/android/internal/os/RoSystemProperties.java
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -61,17 +61,19 @@
SystemProperties.getBoolean("ro.fw.system_user_split", false);
// ------ ro.crypto.* -------- //
- public static final String CRYPTO_STATE = SystemProperties.get("ro.crypto.state");
- public static final String CRYPTO_TYPE = CryptoProperties.type().orElse("");
+ public static final CryptoProperties.state_values CRYPTO_STATE =
+ CryptoProperties.state().orElse(CryptoProperties.state_values.UNSUPPORTED);
+ public static final CryptoProperties.type_values CRYPTO_TYPE =
+ CryptoProperties.type().orElse(CryptoProperties.type_values.NONE);
// These are pseudo-properties
public static final boolean CRYPTO_ENCRYPTABLE =
- !CRYPTO_STATE.isEmpty() && !"unsupported".equals(CRYPTO_STATE);
+ CRYPTO_STATE != CryptoProperties.state_values.UNSUPPORTED;
public static final boolean CRYPTO_ENCRYPTED =
- "encrypted".equalsIgnoreCase(CRYPTO_STATE);
+ CRYPTO_STATE == CryptoProperties.state_values.ENCRYPTED;
public static final boolean CRYPTO_FILE_ENCRYPTED =
- "file".equalsIgnoreCase(CRYPTO_TYPE);
+ CRYPTO_TYPE == CryptoProperties.type_values.FILE;
public static final boolean CRYPTO_BLOCK_ENCRYPTED =
- "block".equalsIgnoreCase(CRYPTO_TYPE);
+ CRYPTO_TYPE == CryptoProperties.type_values.BLOCK;
public static final boolean CONTROL_PRIVAPP_PERMISSIONS_LOG =
"log".equalsIgnoreCase(CONTROL_PRIVAPP_PERMISSIONS);
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index cc958f4..fa73758 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -339,7 +339,7 @@
mFrameAndBackdropNode.setLeftTopRightBottom(left, top, left + width, top + height);
// Draw the caption and content backdrops in to our render node.
- RecordingCanvas canvas = mFrameAndBackdropNode.start(width, height);
+ RecordingCanvas canvas = mFrameAndBackdropNode.beginRecording(width, height);
final Drawable drawable = mUserCaptionBackgroundDrawable != null
? mUserCaptionBackgroundDrawable : mCaptionBackgroundDrawable;
@@ -353,7 +353,7 @@
mResizingBackgroundDrawable.setBounds(0, mLastCaptionHeight, left + width, top + height);
mResizingBackgroundDrawable.draw(canvas);
}
- mFrameAndBackdropNode.end(canvas);
+ mFrameAndBackdropNode.endRecording();
drawColorViews(left, top, width, height, fullscreen, systemInsets, stableInsets);
@@ -368,7 +368,7 @@
if (mSystemBarBackgroundNode == null) {
return;
}
- RecordingCanvas canvas = mSystemBarBackgroundNode.start(width, height);
+ RecordingCanvas canvas = mSystemBarBackgroundNode.beginRecording(width, height);
mSystemBarBackgroundNode.setLeftTopRightBottom(left, top, left + width, top + height);
final int topInset = DecorView.getColorViewTopInset(mStableInsets.top, mSystemInsets.top);
if (mStatusBarColor != null) {
@@ -384,7 +384,7 @@
mNavigationBarColor.setBounds(mTmpRect);
mNavigationBarColor.draw(canvas);
}
- mSystemBarBackgroundNode.end(canvas);
+ mSystemBarBackgroundNode.endRecording();
mRenderer.drawRenderNode(mSystemBarBackgroundNode);
}
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 15d1944..13b0598 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -35,8 +35,6 @@
#include <ui/ANativeObjectBase.h>
-static int initialized = 0;
-
static jclass egldisplayClass;
static jclass eglcontextClass;
static jclass eglsurfaceClass;
diff --git a/core/jni/android_opengl_EGL15.cpp b/core/jni/android_opengl_EGL15.cpp
index 2abd950..563f5db 100644
--- a/core/jni/android_opengl_EGL15.cpp
+++ b/core/jni/android_opengl_EGL15.cpp
@@ -27,8 +27,6 @@
#include <ui/ANativeObjectBase.h>
-static int initialized = 0;
-
// classes from EGL 1.4
static jclass egldisplayClass;
static jclass eglsurfaceClass;
@@ -171,8 +169,6 @@
*array = NULL;
return reinterpret_cast<void*>(pointer);
}
- eglimageGetHandleID = _env->GetMethodID(eglimageClass, "getNativeHandle", "()J");
- eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
diff --git a/core/jni/android_opengl_EGLExt.cpp b/core/jni/android_opengl_EGLExt.cpp
index 75a25fe..1eb1101 100644
--- a/core/jni/android_opengl_EGLExt.cpp
+++ b/core/jni/android_opengl_EGLExt.cpp
@@ -36,8 +36,6 @@
#include <ui/ANativeObjectBase.h>
-static int initialized = 0;
-
static jclass egldisplayClass;
static jclass eglcontextClass;
static jclass eglsurfaceClass;
diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp
index ee5b594..a4ab5db 100644
--- a/core/jni/android_opengl_GLES10.cpp
+++ b/core/jni/android_opengl_GLES10.cpp
@@ -29,8 +29,6 @@
#include <utils/misc.h>
#include <assert.h>
-static int initialized = 0;
-
static jclass nioAccessClass;
static jclass bufferClass;
static jmethodID getBasePointerID;
diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp
index da7d0f0..ee82fc7 100644
--- a/core/jni/android_opengl_GLES10Ext.cpp
+++ b/core/jni/android_opengl_GLES10Ext.cpp
@@ -29,8 +29,6 @@
#include <utils/misc.h>
#include <assert.h>
-static int initialized = 0;
-
static jclass nioAccessClass;
static jclass bufferClass;
static jmethodID getBasePointerID;
diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index 391ae53..be86a03 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -29,8 +29,6 @@
#include <utils/misc.h>
#include <assert.h>
-static int initialized = 0;
-
static jclass nioAccessClass;
static jclass bufferClass;
static jmethodID getBasePointerID;
diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp
index 09dce32..d28d9a3 100644
--- a/core/jni/android_opengl_GLES11Ext.cpp
+++ b/core/jni/android_opengl_GLES11Ext.cpp
@@ -29,8 +29,6 @@
#include <utils/misc.h>
#include <assert.h>
-static int initialized = 0;
-
static jclass nioAccessClass;
static jclass bufferClass;
static jmethodID getBasePointerID;
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index 99922cf..ff4536e 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -29,8 +29,6 @@
#include <utils/misc.h>
#include <assert.h>
-static int initialized = 0;
-
static jclass nioAccessClass;
static jclass bufferClass;
static jmethodID getBasePointerID;
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index adc635e..9aca866 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -29,8 +29,6 @@
#include <utils/misc.h>
#include <assert.h>
-static int initialized = 0;
-
static jclass nioAccessClass;
static jclass bufferClass;
static jmethodID getBasePointerID;
diff --git a/core/jni/android_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp
index 512f562..4c51e2d 100644
--- a/core/jni/android_opengl_GLES31.cpp
+++ b/core/jni/android_opengl_GLES31.cpp
@@ -27,8 +27,6 @@
#include <utils/misc.h>
#include <assert.h>
-static int initialized = 0;
-
static jclass nioAccessClass;
static jclass bufferClass;
static jmethodID getBasePointerID;
diff --git a/core/jni/android_opengl_GLES31Ext.cpp b/core/jni/android_opengl_GLES31Ext.cpp
index 5543fca..5b671c8 100644
--- a/core/jni/android_opengl_GLES31Ext.cpp
+++ b/core/jni/android_opengl_GLES31Ext.cpp
@@ -28,8 +28,6 @@
#include <utils/misc.h>
#include <assert.h>
-static int initialized = 0;
-
static jclass nioAccessClass;
static jclass bufferClass;
static jmethodID getBasePointerID;
diff --git a/core/jni/android_opengl_GLES32.cpp b/core/jni/android_opengl_GLES32.cpp
index 2f1e31e..d59d25c 100644
--- a/core/jni/android_opengl_GLES32.cpp
+++ b/core/jni/android_opengl_GLES32.cpp
@@ -27,8 +27,6 @@
#include <utils/misc.h>
#include <assert.h>
-static int initialized = 0;
-
static jclass nioAccessClass;
static jclass bufferClass;
static jmethodID getBasePointerID;
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index a212f47..af2d413 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -343,7 +343,9 @@
assetmanager->ForEachPackage([&](const std::string& this_package_name, uint8_t package_id) {
if (this_package_name == std_package_name) {
map = assetmanager->GetOverlayableMapForPackage(package_id);
+ return false;
}
+ return true;
});
if (map == nullptr) {
@@ -521,15 +523,16 @@
return nullptr;
}
- assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) {
+ assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) -> bool {
jstring jpackage_name = env->NewStringUTF(package_name.c_str());
if (jpackage_name == nullptr) {
// An exception is pending.
- return;
+ return false;
}
env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
jpackage_name);
+ return true;
});
return sparse_array;
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 003ee37..4069e95 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -205,7 +205,7 @@
static jobject nativeScreenshot(JNIEnv* env, jclass clazz,
jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
- bool useIdentityTransform, int rotation) {
+ bool useIdentityTransform, int rotation, bool captureSecureLayers) {
sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
if (displayToken == NULL) {
return NULL;
@@ -213,9 +213,9 @@
Rect sourceCrop = rectFromObj(env, sourceCropObj);
sp<GraphicBuffer> buffer;
status_t res = ScreenshotClient::capture(displayToken, ui::Dataspace::V0_SRGB,
- ui::PixelFormat::RGBA_8888,
- sourceCrop, width, height,
- useIdentityTransform, rotation, &buffer);
+ ui::PixelFormat::RGBA_8888,
+ sourceCrop, width, height,
+ useIdentityTransform, rotation, captureSecureLayers, &buffer);
if (res != NO_ERROR) {
return NULL;
}
@@ -1232,7 +1232,7 @@
(void*)nativeSetOverrideScalingMode },
{"nativeGetHandle", "(J)Landroid/os/IBinder;",
(void*)nativeGetHandle },
- {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIZI)Landroid/graphics/GraphicBuffer;",
+ {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIZIZ)Landroid/graphics/GraphicBuffer;",
(void*)nativeScreenshot },
{"nativeCaptureLayers", "(Landroid/os/IBinder;Landroid/graphics/Rect;F)Landroid/graphics/GraphicBuffer;",
(void*)nativeCaptureLayers },
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index 40ff7e4..ee14a89 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -65,8 +65,6 @@
GLsizei stride, const GLvoid *pointer, GLsizei count);
}
-static int initialized = 0;
-
static jclass nioAccessClass;
static jclass bufferClass;
static jclass G11ImplClass;
diff --git a/core/proto/android/stats/style/Android.bp b/core/proto/android/stats/style/Android.bp
new file mode 100644
index 0000000..f085a52
--- /dev/null
+++ b/core/proto/android/stats/style/Android.bp
@@ -0,0 +1,27 @@
+// 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.
+
+java_library {
+ name: "styleprotosnano",
+ proto: {
+ type: "nano",
+ output_params: ["store_unknown_fields=true"],
+ include_dirs: ["external/protobuf/src"],
+ },
+
+ sdk_version: "current",
+ srcs: [
+ "*.proto",
+ ],
+}
diff --git a/core/proto/android/stats/style/style_enums.proto b/core/proto/android/stats/style/style_enums.proto
new file mode 100644
index 0000000..b0e4391
--- /dev/null
+++ b/core/proto/android/stats/style/style_enums.proto
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.stats.style;
+option java_multiple_files = true;
+
+enum Action {
+ DEFAULT_ACTION = 0;
+ ONRESUME = 1;
+ ONSTOP = 2;
+ PICKER_SELECT = 3;
+ PICKER_APPLIED = 4;
+ WALLPAPER_OPEN_CATEGORY = 5;
+ WALLPAPER_SELECT = 6;
+ WALLPAPER_APPLIED = 7;
+ WALLPAPER_EXPLORE = 8;
+ WALLPAPER_DOWNLOAD = 9;
+ WALLPAPER_REMOVE = 10;
+}
+
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index eb69535..489ceb7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3363,6 +3363,10 @@
<!-- True if home app should be pinned via Pinner Service -->
<bool name="config_pinnerHomeApp">false</bool>
+ <!-- List of files pinned by the Pinner Service with the apex boot image b/119800099 -->
+ <string-array translatable="false" name="config_apexBootImagePinnerServiceFiles">
+ </string-array>
+
<!-- Number of days preloaded file cache should be preserved on a device before it can be
deleted -->
<integer name="config_keepPreloadsMinDays">7</integer>
diff --git a/core/res/res/values/styles_car.xml b/core/res/res/values/styles_car.xml
index f6ff1b6..2129734 100644
--- a/core/res/res/values/styles_car.xml
+++ b/core/res/res/values/styles_car.xml
@@ -59,7 +59,7 @@
<style name="CarAction1">
<item name="textStyle">bold</item>
<item name="textSize">@dimen/car_action1_size</item>
- <item name="textColor">@color/car_highlight</item>
+ <item name="textColor">@color/control_default_material</item>
</style>
<style name="CarAction1.Dark">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8df0e19..1f73dda 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3047,6 +3047,7 @@
<java-symbol type="array" name="config_defaultPinnerServiceFiles" />
<java-symbol type="bool" name="config_pinnerCameraApp" />
<java-symbol type="bool" name="config_pinnerHomeApp" />
+ <java-symbol type="array" name="config_apexBootImagePinnerServiceFiles" />
<java-symbol type="string" name="config_doubleTouchGestureEnableFile" />
diff --git a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
index bb535b6..30cc7ff 100644
--- a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
+++ b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
@@ -46,11 +46,11 @@
RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 2));
assertEqualsContract(one, two);
- RulesState differentSystemRules = new RulesState(
+ RulesState differentBaseRules = new RulesState(
"2016b", formatVersion(1, 2), false /* operationInProgress */,
RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 3),
RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 2));
- assertFalse(one.equals(differentSystemRules));
+ assertFalse(one.equals(differentBaseRules));
RulesState differentFormatVersion = new RulesState(
"2016a", formatVersion(1, 1), false /* operationInProgress */,
@@ -121,14 +121,14 @@
}
@Test
- public void isSystemVersionNewerThan() {
+ public void isBaseVersionNewerThan() {
RulesState rulesState = new RulesState(
"2016b", formatVersion(1, 1), false /* operationInProgress */,
RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 3));
- assertTrue(rulesState.isSystemVersionNewerThan(rulesVersion("2016a", 1)));
- assertFalse(rulesState.isSystemVersionNewerThan(rulesVersion("2016b", 1)));
- assertFalse(rulesState.isSystemVersionNewerThan(rulesVersion("2016c", 1)));
+ assertTrue(rulesState.isBaseVersionNewerThan(rulesVersion("2016a", 1)));
+ assertFalse(rulesState.isBaseVersionNewerThan(rulesVersion("2016b", 1)));
+ assertFalse(rulesState.isBaseVersionNewerThan(rulesVersion("2016c", 1)));
}
private static void assertEqualsContract(RulesState one, RulesState two) {
diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
index 0ed76dc..125b9ff 100644
--- a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
@@ -37,37 +37,37 @@
private static final String OTHER_LIBRARY = "other.library";
@Test
- public void targeted_at_O() {
+ public void targeted_at_P() {
PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O);
+ .targetSdkVersion(Build.VERSION_CODES.P);
// Should add org.apache.http.legacy.
PackageBuilder after = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
+ .targetSdkVersion(Build.VERSION_CODES.P)
.requiredLibraries(ANDROID_TEST_BASE);
checkBackwardsCompatibility(before, after);
}
@Test
- public void targeted_at_O_not_empty_usesLibraries() {
+ public void targeted_at_P_not_empty_usesLibraries() {
PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
+ .targetSdkVersion(Build.VERSION_CODES.P)
.requiredLibraries(OTHER_LIBRARY);
// The org.apache.http.legacy jar should be added at the start of the list because it
// is not on the bootclasspath and the package targets pre-P.
PackageBuilder after = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
+ .targetSdkVersion(Build.VERSION_CODES.P)
.requiredLibraries(ANDROID_TEST_BASE, OTHER_LIBRARY);
checkBackwardsCompatibility(before, after);
}
@Test
- public void targeted_at_O_in_usesLibraries() {
+ public void targeted_at_P_in_usesLibraries() {
PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
+ .targetSdkVersion(Build.VERSION_CODES.P)
.requiredLibraries(ANDROID_TEST_BASE);
// No change is required because although org.apache.http.legacy has been removed from
@@ -76,9 +76,9 @@
}
@Test
- public void targeted_at_O_in_usesOptionalLibraries() {
+ public void targeted_at_P_in_usesOptionalLibraries() {
PackageBuilder before = builder()
- .targetSdkVersion(Build.VERSION_CODES.O)
+ .targetSdkVersion(Build.VERSION_CODES.P)
.optionalLibraries(ANDROID_TEST_BASE);
// No change is required because although org.apache.http.legacy has been removed from
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 8d3bac8..60ce595 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1270,7 +1270,7 @@
node.setLeftTopRightBottom(0, 0, width, height);
node.setClipToBounds(false);
node.setForceDarkAllowed(false);
- final RecordingCanvas canvas = node.startRecording(width, height);
+ final RecordingCanvas canvas = node.beginRecording(width, height);
if (source.getWidth() != width || source.getHeight() != height) {
canvas.scale(width / (float) source.getWidth(),
height / (float) source.getHeight());
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index b020556..e623354 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -258,7 +258,7 @@
* and the renderer will draw nothing.
*/
public void setContentRoot(@Nullable RenderNode content) {
- RecordingCanvas canvas = mRootNode.startRecording();
+ RecordingCanvas canvas = mRootNode.beginRecording();
if (content != null) {
canvas.drawRenderNode(content);
}
diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java
index 515532f..30466e1 100644
--- a/graphics/java/android/graphics/RecordingCanvas.java
+++ b/graphics/java/android/graphics/RecordingCanvas.java
@@ -31,7 +31,7 @@
* Bitmap objects that it draws, preventing the backing memory of Bitmaps from being released while
* the RecordingCanvas is still holding a native reference to the memory.
*
- * This is obtained by calling {@link RenderNode#startRecording()} and is valid until the matching
+ * This is obtained by calling {@link RenderNode#beginRecording()} and is valid until the matching
* {@link RenderNode#endRecording()} is called. It must not be retained beyond that as it is
* internally reused.
*/
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 09b18b7..e98879d 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -16,6 +16,9 @@
package android.graphics;
+import android.annotation.BytesLong;
+import android.annotation.ColorInt;
+import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -59,7 +62,7 @@
* <pre class="prettyprint">
* RenderNode renderNode = RenderNode.create("myRenderNode");
* renderNode.setLeftTopRightBottom(0, 0, 50, 50); // Set the size to 50x50
- * RecordingCanvas canvas = renderNode.startRecording();
+ * RecordingCanvas canvas = renderNode.beginRecording();
* try {
* // Draw with the canvas
* canvas.drawRect(...);
@@ -71,14 +74,13 @@
* <h3>Drawing a RenderNode in a View</h3>
* <pre class="prettyprint">
* protected void onDraw(Canvas canvas) {
- * if (canvas instanceof RecordingCanvas) {
- * RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
+ * if (canvas.isHardwareAccelerated()) {
* // Check that the RenderNode has a display list, re-recording it if it does not.
* if (!myRenderNode.hasDisplayList()) {
* updateDisplayList(myRenderNode);
* }
* // Draw the RenderNode into this canvas.
- * recordingCanvas.drawRenderNode(myRenderNode);
+ * canvas.drawRenderNode(myRenderNode);
* }
* }
* </pre>
@@ -95,7 +97,7 @@
*
* <h3>Properties</h3>
* <p>In addition, a RenderNode offers several properties, such as
- * {@link #setScaleX(float)} or {@link #setLeft(int)}, that can be used to affect all
+ * {@link #setScaleX(float)} or {@link #setTranslationX(float)}, that can be used to affect all
* the drawing commands recorded within. For instance, these properties can be used
* to move around a large number of images without re-issuing all the individual
* <code>canvas.drawBitmap()</code> calls.</p>
@@ -104,7 +106,7 @@
* private void createDisplayList() {
* mRenderNode = RenderNode.create("MyRenderNode");
* mRenderNode.setLeftTopRightBottom(0, 0, width, height);
- * RecordingCanvas canvas = mRenderNode.startRecording();
+ * RecordingCanvas canvas = mRenderNode.beginRecording();
* try {
* for (Bitmap b : mBitmaps) {
* canvas.drawBitmap(b, 0.0f, 0.0f, null);
@@ -116,9 +118,8 @@
* }
*
* protected void onDraw(Canvas canvas) {
- * if (canvas instanceof RecordingCanvas) {
- * RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
- * recordingCanvas.drawRenderNode(mRenderNode);
+ * if (canvas.isHardwareAccelerated())
+ * canvas.drawRenderNode(mRenderNode);
* }
* }
*
@@ -263,19 +264,20 @@
* stored in this display list.
*
* {@link #endRecording()} must be called when the recording is finished in order to apply
- * the updated display list.
+ * the updated display list. Failing to call {@link #endRecording()} will result in an
+ * {@link IllegalStateException} if {@link #beginRecording(int, int)} is called again.
*
* @param width The width of the recording viewport. This will not alter the width of the
- * RenderNode itself, that must be set with {@link #setLeft(int)} and
- * {@link #setRight(int)}
+ * RenderNode itself, that must be set with {@link #setPosition(Rect)}.
* @param height The height of the recording viewport. This will not alter the height of the
- * RenderNode itself, that must be set with {@link #setTop(int)} and
- * {@link #setBottom(int)}.
+ * RenderNode itself, that must be set with {@link #setPosition(Rect)}.
* @return A canvas to record drawing operations.
+ * @throws IllegalStateException If a recording is already in progress. That is, the previous
+ * call to {@link #beginRecording(int, int)} did not call {@link #endRecording()}.
* @see #endRecording()
* @see #hasDisplayList()
*/
- public RecordingCanvas startRecording(int width, int height) {
+ public RecordingCanvas beginRecording(int width, int height) {
if (mCurrentRecordingCanvas != null) {
throw new IllegalStateException(
"Recording currently in progress - missing #endRecording() call?");
@@ -285,21 +287,18 @@
}
/**
- * Same as {@link #startRecording(int, int)} with the width & height set
+ * Same as {@link #beginRecording(int, int)} with the width & height set
* to the RenderNode's own width & height. The RenderNode's width & height may be set
- * with {@link #setLeftTopRightBottom(int, int, int, int)}.
+ * with {@link #setPosition(int, int, int, int)}.
+ *
+ * @return A canvas to record drawing operations.
+ * @throws IllegalStateException If a recording is already in progress. That is, the previous
+ * call to {@link #beginRecording(int, int)} did not call {@link #endRecording()}.
+ * @see #endRecording()
+ * @see #hasDisplayList()
*/
- public RecordingCanvas startRecording() {
- return startRecording(nGetWidth(mNativeRenderNode), nGetHeight(mNativeRenderNode));
- }
-
- /**
- * @hide
- * @deprecated use {@link #startRecording(int, int)} instead
- */
- @Deprecated
- public RecordingCanvas start(int width, int height) {
- return startRecording(width, height);
+ public RecordingCanvas beginRecording() {
+ return beginRecording(nGetWidth(mNativeRenderNode), nGetHeight(mNativeRenderNode));
}
/**
@@ -307,13 +306,13 @@
* Ends the recording for this display list. Calling this method marks
* the display list valid and {@link #hasDisplayList()} will return true.
*
- * @see #startRecording(int, int)
+ * @see #beginRecording(int, int)
* @see #hasDisplayList()
*/
public void endRecording() {
if (mCurrentRecordingCanvas == null) {
throw new IllegalStateException(
- "No recording in progress, forgot to call #startRecording()?");
+ "No recording in progress, forgot to call #beginRecording()?");
}
RecordingCanvas canvas = mCurrentRecordingCanvas;
mCurrentRecordingCanvas = null;
@@ -324,13 +323,21 @@
/**
* @hide
+ * @deprecated use {@link #beginRecording(int, int)} instead
+ */
+ @Deprecated
+ public RecordingCanvas start(int width, int height) {
+ return beginRecording(width, height);
+ }
+
+ /**
+ * @hide
* @deprecated use {@link #endRecording()} instead
*/
@Deprecated
public void end(RecordingCanvas canvas) {
- if (mCurrentRecordingCanvas != canvas) {
- throw new IllegalArgumentException(
- "Canvas given isn't the one that was returned from #startRecording");
+ if (canvas != mCurrentRecordingCanvas) {
+ throw new IllegalArgumentException("Wrong canvas");
}
endRecording();
}
@@ -346,7 +353,7 @@
/**
* Returns whether the RenderNode has a display list. If this returns false, the RenderNode
- * should be re-recorded with {@link #startRecording()} and {@link #endRecording()}.
+ * should be re-recorded with {@link #beginRecording()} and {@link #endRecording()}.
*
* A RenderNode without a display list may still be drawn, however it will have no impact
* on the rendering content until its display list is updated.
@@ -425,18 +432,21 @@
* for performance or required for the current combination of {@link #setAlpha(float)} and
* {@link #setHasOverlappingRendering(boolean)}.
*
- * The usage of this is instead to allow for either overriding of the internal behavior
+ * <p>The usage of this is instead to allow for either overriding of the internal behavior
* if it's measured to be necessary for the particular rendering content in question or, more
* usefully, to add a composition effect to the RenderNode via the optional paint parameter.
*
- * Note: When a RenderNode is using a compositing layer it will also result in
+ * <p>Note: When a RenderNode is using a compositing layer it will also result in
* clipToBounds=true behavior.
*
* @param forceToLayer if true this forces the RenderNode to use an intermediate buffer.
* Default & generally recommended value is false.
* @param paint The blend mode, alpha, and ColorFilter to apply to the compositing layer.
- * Only applies if forceToLayer is true.
- * @return true if anything changed, false otherwise
+ * Only applies if forceToLayer is true. The paint's alpha is multiplied
+ * with {@link #getAlpha()} to resolve the final alpha of the RenderNode.
+ * If null then no additional composition effects are applied on top of the
+ * composition layer.
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setUseCompositingLayer(boolean forceToLayer, @Nullable Paint paint) {
boolean didChange = nSetLayerType(mNativeRenderNode, forceToLayer ? 2 : 0);
@@ -457,15 +467,22 @@
}
/**
- * Sets the clip bounds of the RenderNode. If null, the clip bounds is removed from the
- * RenderNode. If non-null, the RenderNode will be clipped to this rect. If
+ * Sets an additional clip on the RenderNode. If null, the extra clip is removed from the
+ * RenderNode. If non-null, the RenderNode will be clipped to this rect. In addition if
* {@link #setClipToBounds(boolean)} is true, then the RenderNode will be clipped to the
- * intersection of this rectangle and the bounds of the render node.
+ * intersection of this rectangle and the bounds of the render node, which is set with
+ * {@link #setPosition(Rect)}.
*
- * @param rect the bounds to clip to. If null, the clip bounds are reset
- * @return True if the clip bounds changed, false otherwise
+ * <p>This is equivalent to do a {@link Canvas#clipRect(Rect)} at the start of this
+ * RenderNode's display list. However, as this is a property of the RenderNode instead
+ * of part of the display list it can be more easily animated for transient additional
+ * clipping. An example usage of this would be the {@link android.transition.ChangeBounds}
+ * transition animation with the resizeClip=true option.
+ *
+ * @param rect the bounds to clip to. If null, the additional clip is removed.
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
- public boolean setClipBounds(@Nullable Rect rect) {
+ public boolean setClipRect(@Nullable Rect rect) {
if (rect == null) {
return nSetClipBoundsEmpty(mNativeRenderNode);
} else {
@@ -477,11 +494,12 @@
* Set whether the Render node should clip itself to its bounds. This defaults to true,
* and is useful to the renderer in enable quick-rejection of chunks of the tree as well as
* better partial invalidation support. Clipping can be further restricted or controlled
- * through the combination of this property as well as {@link #setClipBounds(Rect)}, which
+ * through the combination of this property as well as {@link #setClipRect(Rect)}, which
* allows for a different clipping rectangle to be used in addition to or instead of the
- * {@link #setLeftTopRightBottom(int, int, int, int)} or the RenderNode.
+ * {@link #setPosition(int, int, int, int)} or the RenderNode.
*
* @param clipToBounds true if the display list should clip to its bounds, false otherwise.
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setClipToBounds(boolean clipToBounds) {
return nSetClipToBounds(mNativeRenderNode, clipToBounds);
@@ -489,7 +507,7 @@
/**
* Returns whether or not the RenderNode is clipping to its bounds. See
- * {@link #setClipToBounds(boolean)} and {@link #setLeftTopRightBottom(int, int, int, int)}
+ * {@link #setClipToBounds(boolean)} and {@link #setPosition(int, int, int, int)}
*
* @return true if the render node clips to its bounds, false otherwise.
*/
@@ -498,20 +516,58 @@
}
/**
- * Sets whether the RenderNode should be drawn immediately after the
+ * <p>Sets whether the RenderNode should be drawn immediately after the
* closest ancestor RenderNode containing a projection receiver.
*
+ * <p>The default is false, and the rendering of this node happens in the typical draw order.
+ *
+ * <p>If true, then at rendering time this rendernode will not be drawn in order with the
+ * {@link Canvas#drawRenderNode(RenderNode)} command that drew this RenderNode, but instead
+ * it will be re-positioned in the RenderNode tree to be drawn on the closet ancestor with a
+ * child rendernode that has {@link #setProjectionReceiver(boolean)} as true.
+ *
+ * <p>The typical usage of this is to allow a child RenderNode to draw on a parent's background,
+ * such as the platform's usage with {@link android.graphics.drawable.RippleDrawable}. Consider
+ * the following structure, built out of which RenderNode called drawRenderNode on a different
+ * RenderNode:
+ *
+ * <pre>
+ * +-------------+
+ * |RenderNode: P|
+ * +-+----------++
+ * | |
+ * v v
+ * +-------+-----+ +-+--------------+
+ * |RenderNode: C| |RenderNode: P'BG|
+ * +-------+-----+ +----------------+
+ * |
+ * |
+ * +--------+-------+
+ * |RenderNode: C'BG|
+ * +----------------+
+ * </pre>
+ *
+ * If P'BG is a projection receiver, and C'BG is set to project backwards then C'BG will
+ * behave as if it was drawn directly by P'BG instead of by C. This includes inheriting P'BG's
+ * clip instead of C's clip.
+ *
* @param shouldProject true if the display list should be projected onto a
- * containing volume.
+ * containing volume. Default is false.
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setProjectBackwards(boolean shouldProject) {
return nSetProjectBackwards(mNativeRenderNode, shouldProject);
}
/**
- * Sets whether the RenderNode is a projection receiver - that its parent
- * RenderNode should draw any descendent RenderNodes with
- * ProjectBackwards=true directly on top of it. Default value is false.
+ * Sets whether the RenderNode is a projection receiver. If true then this RenderNode's parent
+ * should draw any descendant RenderNodes with ProjectBackwards=true directly on top of it.
+ * Default value is false. See
+ * {@link #setProjectBackwards(boolean)} for a description of what this entails.
+ *
+ * @param shouldRecieve True if this RenderNode is a projection receiver, false otherwise.
+ * Default is false.
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setProjectionReceiver(boolean shouldRecieve) {
return nSetProjectionReceiver(mNativeRenderNode, shouldRecieve);
@@ -526,6 +582,7 @@
* outline for those changes to be applied.
*
* @param outline The outline to use for this RenderNode.
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setOutline(@Nullable Outline outline) {
if (outline == null) {
@@ -572,8 +629,9 @@
* {@link android.R.attr#spotShadowAlpha} theme attribute
*
* @param color The color this RenderNode will cast for its elevation spot shadow.
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
- public boolean setSpotShadowColor(int color) {
+ public boolean setSpotShadowColor(@ColorInt int color) {
return nSetSpotShadowColor(mNativeRenderNode, color);
}
@@ -581,7 +639,7 @@
* @return The shadow color set by {@link #setSpotShadowColor(int)}, or black if nothing
* was set
*/
- public int getSpotShadowColor() {
+ public @ColorInt int getSpotShadowColor() {
return nGetSpotShadowColor(mNativeRenderNode);
}
@@ -597,8 +655,9 @@
* {@link android.R.attr#ambientShadowAlpha} theme attribute.
*
* @param color The color this RenderNode will cast for its elevation shadow.
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
- public boolean setAmbientShadowColor(int color) {
+ public boolean setAmbientShadowColor(@ColorInt int color) {
return nSetAmbientShadowColor(mNativeRenderNode, color);
}
@@ -606,7 +665,7 @@
* @return The shadow color set by {@link #setAmbientShadowColor(int)}, or black if
* nothing was set
*/
- public int getAmbientShadowColor() {
+ public @ColorInt int getAmbientShadowColor() {
return nGetAmbientShadowColor(mNativeRenderNode);
}
@@ -614,6 +673,8 @@
* Enables or disables clipping to the outline.
*
* @param clipToOutline true if clipping to the outline.
+ * @return True if the clipToOutline value changed, false if previous value matched the new
+ * value.
*/
public boolean setClipToOutline(boolean clipToOutline) {
return nSetClipToOutline(mNativeRenderNode, clipToOutline);
@@ -640,7 +701,7 @@
/**
* Set the static matrix on the display list. The specified matrix is combined with other
- * transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.)
+ * transforms (such as {@link #setScaleX(float)}, {@link #setRotationZ(float)}, etc.)
*
* @param matrix A transform matrix to apply to this display list
* @hide TODO Do we want this?
@@ -669,6 +730,7 @@
* @param alpha The translucency of the display list, must be a value between 0.0f and 1.0f
* @see View#setAlpha(float)
* @see #getAlpha()
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setAlpha(float alpha) {
return nSetAlpha(mNativeRenderNode, alpha);
@@ -742,7 +804,7 @@
* Sets the base elevation of this RenderNode in pixels
*
* @param lift the elevation in pixels
- * @return true if the elevation changed, false if it was the same
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setElevation(float lift) {
return nSetElevation(mNativeRenderNode, lift);
@@ -763,6 +825,7 @@
* @param translationX The X axis translation value of the display list, in pixels
* @see View#setTranslationX(float)
* @see #getTranslationX()
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setTranslationX(float translationX) {
return nSetTranslationX(mNativeRenderNode, translationX);
@@ -783,6 +846,7 @@
* @param translationY The Y axis translation value of the display list, in pixels
* @see View#setTranslationY(float)
* @see #getTranslationY()
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setTranslationY(float translationY) {
return nSetTranslationY(mNativeRenderNode, translationY);
@@ -802,6 +866,7 @@
*
* @see View#setTranslationZ(float)
* @see #getTranslationZ()
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setTranslationZ(float translationZ) {
return nSetTranslationZ(mNativeRenderNode, translationZ);
@@ -820,19 +885,20 @@
* Sets the rotation value for the display list around the Z axis.
*
* @param rotation The rotation value of the display list, in degrees
- * @see View#setRotation(float)
- * @see #getRotation()
+ * @see View#setRotationZ(float)
+ * @see #getRotationZ()
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
- public boolean setRotation(float rotation) {
+ public boolean setRotationZ(float rotation) {
return nSetRotation(mNativeRenderNode, rotation);
}
/**
* Returns the rotation value for this display list around the Z axis, in degrees.
*
- * @see #setRotation(float)
+ * @see #setRotationZ(float)
*/
- public float getRotation() {
+ public float getRotationZ() {
return nGetRotation(mNativeRenderNode);
}
@@ -842,6 +908,7 @@
* @param rotationX The rotation value of the display list, in degrees
* @see View#setRotationX(float)
* @see #getRotationX()
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setRotationX(float rotationX) {
return nSetRotationX(mNativeRenderNode, rotationX);
@@ -862,6 +929,7 @@
* @param rotationY The rotation value of the display list, in degrees
* @see View#setRotationY(float)
* @see #getRotationY()
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setRotationY(float rotationY) {
return nSetRotationY(mNativeRenderNode, rotationY);
@@ -882,6 +950,7 @@
* @param scaleX The scale value of the display list
* @see View#setScaleX(float)
* @see #getScaleX()
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setScaleX(float scaleX) {
return nSetScaleX(mNativeRenderNode, scaleX);
@@ -902,6 +971,7 @@
* @param scaleY The scale value of the display list
* @see View#setScaleY(float)
* @see #getScaleY()
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setScaleY(float scaleY) {
return nSetScaleY(mNativeRenderNode, scaleY);
@@ -922,6 +992,7 @@
* @param pivotX The pivot value of the display list on the X axis, in pixels
* @see View#setPivotX(float)
* @see #getPivotX()
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setPivotX(float pivotX) {
return nSetPivotX(mNativeRenderNode, pivotX);
@@ -942,6 +1013,7 @@
* @param pivotY The pivot value of the display list on the Y axis, in pixels
* @see View#setPivotY(float)
* @see #getPivotY()
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setPivotY(float pivotY) {
return nSetPivotY(mNativeRenderNode, pivotY);
@@ -969,6 +1041,8 @@
* Clears any pivot previously set by a call to {@link #setPivotX(float)} or
* {@link #setPivotY(float)}. After calling this {@link #isPivotExplicitlySet()} will be false
* and the pivot used for rotation will return to default of being centered on the view.
+ *
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean resetPivot() {
return nResetPivot(mNativeRenderNode);
@@ -997,8 +1071,10 @@
* @param distance The distance in pixels, must always be positive
* @see #setRotationX(float)
* @see #setRotationY(float)
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
- public boolean setCameraDistance(float distance) {
+ public boolean setCameraDistance(
+ @FloatRange(from = 0.0f, to = Float.MAX_VALUE) float distance) {
if (!Float.isFinite(distance) || distance < 0.0f) {
throw new IllegalArgumentException("distance must be finite & positive, given="
+ distance);
@@ -1013,7 +1089,7 @@
* @return the distance along the Z axis in pixels.
* @see #setCameraDistance(float)
*/
- public float getCameraDistance() {
+ public @FloatRange(from = 0.0f, to = Float.MAX_VALUE) float getCameraDistance() {
return -nGetCameraDistance(mNativeRenderNode);
}
@@ -1022,6 +1098,7 @@
*
* @param left The left position, in pixels, of the RenderNode
* @return true if the value changed, false otherwise
+ * @hide
*/
public boolean setLeft(int left) {
return nSetLeft(mNativeRenderNode, left);
@@ -1032,6 +1109,7 @@
*
* @param top The top position, in pixels, of the RenderNode
* @return true if the value changed, false otherwise.
+ * @hide
*/
public boolean setTop(int top) {
return nSetTop(mNativeRenderNode, top);
@@ -1042,6 +1120,7 @@
*
* @param right The right position, in pixels, of the RenderNode
* @return true if the value changed, false otherwise.
+ * @hide
*/
public boolean setRight(int right) {
return nSetRight(mNativeRenderNode, right);
@@ -1052,6 +1131,7 @@
*
* @param bottom The bottom position, in pixels, of the RenderNode
* @return true if the value changed, false otherwise.
+ * @hide
*/
public boolean setBottom(int bottom) {
return nSetBottom(mNativeRenderNode, bottom);
@@ -1060,8 +1140,6 @@
/**
* Gets the left position for the RenderNode.
*
- * See {@link #setLeft(int)}
- *
* @return the left position in pixels
*/
public int getLeft() {
@@ -1071,8 +1149,6 @@
/**
* Gets the top position for the RenderNode.
*
- * See {@link #setTop(int)}
- *
* @return the top position in pixels
*/
public int getTop() {
@@ -1082,8 +1158,6 @@
/**
* Gets the right position for the RenderNode.
*
- * See {@link #setRight(int)}
- *
* @return the right position in pixels
*/
public int getRight() {
@@ -1093,8 +1167,6 @@
/**
* Gets the bottom position for the RenderNode.
*
- * See {@link #setBottom(int)}
- *
* @return the bottom position in pixels
*/
public int getBottom() {
@@ -1127,20 +1199,41 @@
* @param right The right position of the RenderNode, in pixels
* @param bottom The bottom position of the RenderNode, in pixels
* @return true if any values changed, false otherwise.
- * @see #setLeft(int)
- * @see #setTop(int)
- * @see #setRight(int)
- * @see #setBottom(int)
+ * @hide
*/
public boolean setLeftTopRightBottom(int left, int top, int right, int bottom) {
return nSetLeftTopRightBottom(mNativeRenderNode, left, top, right, bottom);
}
/**
+ * Sets the position of the RenderNode.
+ *
+ * @param left The left position of the RenderNode, in pixels
+ * @param top The top position of the RenderNode, in pixels
+ * @param right The right position of the RenderNode, in pixels
+ * @param bottom The bottom position of the RenderNode, in pixels
+ * @return True if the value changed, false if the new value was the same as the previous value.
+ */
+ public boolean setPosition(int left, int top, int right, int bottom) {
+ return nSetLeftTopRightBottom(mNativeRenderNode, left, top, right, bottom);
+ }
+
+ /**
+ * Sets the position of the RenderNode.
+ *
+ * @param position The position rectangle in pixels
+ * @return True if the value changed, false if the new value was the same as the previous value.
+ */
+ public boolean setPosition(Rect position) {
+ return nSetLeftTopRightBottom(mNativeRenderNode,
+ position.left, position.top, position.right, position.bottom);
+ }
+
+ /**
* Offsets the left and right positions for the RenderNode
*
* @param offset The amount that the left and right positions are offset in pixels
- * @return true if any values changed, false otherwise.
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean offsetLeftAndRight(int offset) {
return nOffsetLeftAndRight(mNativeRenderNode, offset);
@@ -1150,7 +1243,7 @@
* Offsets the top and bottom values for the RenderNode
*
* @param offset The amount that the left and right positions are offset in pixels
- * @return true if any values changed, false otherwise.
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean offsetTopAndBottom(int offset) {
return nOffsetTopAndBottom(mNativeRenderNode, offset);
@@ -1170,8 +1263,10 @@
* Gets the approximate memory usage of the RenderNode for debug purposes. Does not include
* the memory usage of any child RenderNodes nor any bitmaps, only the memory usage of
* this RenderNode and any data it owns.
+ *
+ * @return Approximate memory usage in bytes.
*/
- public int computeApproximateMemoryUsage() {
+ public @BytesLong long computeApproximateMemoryUsage() {
return nGetDebugSize(mNativeRenderNode);
}
@@ -1186,7 +1281,7 @@
* it prevent any 'false' in any of its children.
*
* @param allow Whether or not to allow force dark.
- * @return true If the value has changed, false otherwise.
+ * @return True if the value changed, false if the new value was the same as the previous value.
*/
public boolean setForceDarkAllowed(boolean allow) {
return nSetAllowForceDark(mNativeRenderNode, allow);
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 66d8542..d7b84ff 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -356,6 +356,7 @@
ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
bool /*stop_at_first_match*/,
+ bool ignore_configuration,
FindEntryResult* out_entry) const {
// Might use this if density_override != 0.
ResTable_config density_override_config;
@@ -399,7 +400,7 @@
// If desired_config is the same as the set configuration, then we can use our filtered list
// and we don't need to match the configurations, since they already matched.
- const bool use_fast_path = desired_config == &configuration_;
+ const bool use_fast_path = !ignore_configuration && desired_config == &configuration_;
for (size_t pi = 0; pi < package_count; pi++) {
const ConfiguredPackage& loaded_package_impl = package_group.packages_[pi];
@@ -475,21 +476,23 @@
// ResTable_config, we must copy it.
const auto iter_end = type_spec->types + type_spec->type_count;
for (auto iter = type_spec->types; iter != iter_end; ++iter) {
- ResTable_config this_config;
- this_config.copyFromDtoH((*iter)->config);
+ ResTable_config this_config{};
- if (!this_config.match(*desired_config)) {
- continue;
- }
+ if (!ignore_configuration) {
+ this_config.copyFromDtoH((*iter)->config);
+ if (!this_config.match(*desired_config)) {
+ continue;
+ }
- if (best_config == nullptr) {
- resolution_type = Resolution::Step::Type::INITIAL;
- } else if (this_config.isBetterThan(*best_config, desired_config)) {
- resolution_type = Resolution::Step::Type::BETTER_MATCH;
- } else if (package_is_overlay && this_config.compare(*best_config) == 0) {
- resolution_type = Resolution::Step::Type::OVERLAID;
- } else {
- continue;
+ if (best_config == nullptr) {
+ resolution_type = Resolution::Step::Type::INITIAL;
+ } else if (this_config.isBetterThan(*best_config, desired_config)) {
+ resolution_type = Resolution::Step::Type::BETTER_MATCH;
+ } else if (package_is_overlay && this_config.compare(*best_config) == 0) {
+ resolution_type = Resolution::Step::Type::OVERLAID;
+ } else {
+ continue;
+ }
}
// The configuration matches and is better than the previous selection.
@@ -506,6 +509,11 @@
best_config = &best_config_copy;
best_offset = offset;
+ if (ignore_configuration) {
+ // Any configuration will suffice, so break.
+ break;
+ }
+
if (resource_resolution_logging_enabled_) {
resolution_steps.push_back(Resolution::Step{resolution_type,
this_config.toString(),
@@ -622,8 +630,9 @@
bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const {
FindEntryResult entry;
- ApkAssetsCookie cookie =
- FindEntry(resid, 0u /* density_override */, true /* stop_at_first_match */, &entry);
+ ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+ true /* stop_at_first_match */,
+ true /* ignore_configuration */, &entry);
if (cookie == kInvalidCookie) {
return false;
}
@@ -652,13 +661,14 @@
bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const {
FindEntryResult entry;
- ApkAssetsCookie cookie =
- FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry);
+ ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+ false /* stop_at_first_match */,
+ true /* ignore_configuration */, &entry);
if (cookie != kInvalidCookie) {
*out_flags = entry.type_flags;
- return cookie;
+ return true;
}
- return kInvalidCookie;
+ return false;
}
ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
@@ -666,8 +676,8 @@
ResTable_config* out_selected_config,
uint32_t* out_flags) const {
FindEntryResult entry;
- ApkAssetsCookie cookie =
- FindEntry(resid, density_override, false /* stop_at_first_match */, &entry);
+ ApkAssetsCookie cookie = FindEntry(resid, density_override, false /* stop_at_first_match */,
+ false /* ignore_configuration */, &entry);
if (cookie == kInvalidCookie) {
return kInvalidCookie;
}
@@ -759,8 +769,10 @@
}
FindEntryResult entry;
- ApkAssetsCookie cookie =
- FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry);
+ ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+ false /* stop_at_first_match */,
+ false /* ignore_configuration */,
+ &entry);
if (cookie == kInvalidCookie) {
return nullptr;
}
@@ -1387,7 +1399,9 @@
// Find the cookie of the attribute resource id
FindEntryResult attribute_entry_result;
ApkAssetsCookie attribute_cookie =
- o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ , false,
+ o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ ,
+ true /* stop_at_first_match */,
+ true /* ignore_configuration */,
&attribute_entry_result);
// Determine the package id of the attribute in the destination AssetManager
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index fc5aa9c7..1e2b36c 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -257,11 +257,12 @@
// Creates a new Theme from this AssetManager.
std::unique_ptr<Theme> NewTheme();
- template <typename Func>
- void ForEachPackage(Func func) const {
+ void ForEachPackage(const std::function<bool(const std::string&, uint8_t)> func) const {
for (const PackageGroup& package_group : package_groups_) {
- func(package_group.packages_.front().loaded_package_->GetPackageName(),
- package_group.dynamic_ref_table.mAssignedPackageId);
+ if (!func(package_group.packages_.front().loaded_package_->GetPackageName(),
+ package_group.dynamic_ref_table.mAssignedPackageId)) {
+ return;
+ }
}
}
@@ -282,10 +283,13 @@
// care about the value. In this case, the value of `FindEntryResult::type_flags` is incomplete
// and should not be used.
//
+ // When `ignore_configuration` is true, FindEntry will return always select the first entry in
+ // for the type seen regardless of its configuration.
+ //
// NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly
// bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds.
ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match,
- FindEntryResult* out_entry) const;
+ bool ignore_configuration, FindEntryResult* out_entry) const;
// Assigns package IDs to all shared library ApkAssets.
// Should be called whenever the ApkAssets are changed.
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index e4d356b..08ce9fc 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -2645,6 +2645,7 @@
*/
private synchronized void setSubtitleAnchor() {
if ((mSubtitleController == null) && (ActivityThread.currentApplication() != null)) {
+ getMediaTimeProvider();
final HandlerThread thread = new HandlerThread("SetSubtitleAnchorThread");
thread.start();
Handler handler = new Handler(thread.getLooper());
@@ -2660,7 +2661,7 @@
@Override
public Looper getSubtitleLooper() {
- return Looper.getMainLooper();
+ return mTimeProvider.mEventHandler.getLooper();
}
});
thread.getLooper().quitSafely();
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index b700bf3..5f1f26d 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -28,6 +28,7 @@
static_libs: [
"netd_aidl_interface-java",
"networkstack-aidl-interfaces-java",
+ "datastallprotosnano",
]
}
@@ -43,4 +44,4 @@
jarjar_rules: "jarjar-rules-shared.txt",
manifest: "AndroidManifest.xml",
required: ["NetworkStackPermissionStub"],
-}
\ No newline at end of file
+}
diff --git a/packages/NetworkStack/src/android/net/metrics/DataStallDetectionStats.java b/packages/NetworkStack/src/android/net/metrics/DataStallDetectionStats.java
new file mode 100644
index 0000000..6ea1e3d
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/metrics/DataStallDetectionStats.java
@@ -0,0 +1,209 @@
+/*
+ * 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.metrics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.util.NetworkStackUtils;
+import android.net.wifi.WifiInfo;
+
+import com.android.internal.util.HexDump;
+import com.android.server.connectivity.nano.CellularData;
+import com.android.server.connectivity.nano.DataStallEventProto;
+import com.android.server.connectivity.nano.DnsEvent;
+import com.android.server.connectivity.nano.WifiData;
+
+import com.google.protobuf.nano.MessageNano;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class to record the stats of detection level information for data stall.
+ *
+ * @hide
+ */
+public final class DataStallDetectionStats {
+ private static final int UNKNOWN_SIGNAL_STRENGTH = -1;
+ @NonNull
+ final byte[] mCellularInfo;
+ @NonNull
+ final byte[] mWifiInfo;
+ @NonNull
+ final byte[] mDns;
+ final int mEvaluationType;
+ final int mNetworkType;
+
+ public DataStallDetectionStats(@Nullable byte[] cell, @Nullable byte[] wifi,
+ @NonNull int[] returnCode, @NonNull long[] dnsTime, int evalType, int netType) {
+ mCellularInfo = emptyCellDataIfNull(cell);
+ mWifiInfo = emptyWifiInfoIfNull(wifi);
+
+ DnsEvent dns = new DnsEvent();
+ dns.dnsReturnCode = returnCode;
+ dns.dnsTime = dnsTime;
+ mDns = MessageNano.toByteArray(dns);
+ mEvaluationType = evalType;
+ mNetworkType = netType;
+ }
+
+ private byte[] emptyCellDataIfNull(@Nullable byte[] cell) {
+ if (cell != null) return cell;
+
+ CellularData data = new CellularData();
+ data.ratType = DataStallEventProto.RADIO_TECHNOLOGY_UNKNOWN;
+ data.networkMccmnc = "";
+ data.simMccmnc = "";
+ data.signalStrength = UNKNOWN_SIGNAL_STRENGTH;
+ return MessageNano.toByteArray(data);
+ }
+
+ private byte[] emptyWifiInfoIfNull(@Nullable byte[] wifi) {
+ if (wifi != null) return wifi;
+
+ WifiData data = new WifiData();
+ data.wifiBand = DataStallEventProto.AP_BAND_UNKNOWN;
+ data.signalStrength = UNKNOWN_SIGNAL_STRENGTH;
+ return MessageNano.toByteArray(data);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("type: ").append(mNetworkType)
+ .append(", evaluation type: ")
+ .append(mEvaluationType)
+ .append(", wifi info: ")
+ .append(HexDump.toHexString(mWifiInfo))
+ .append(", cell info: ")
+ .append(HexDump.toHexString(mCellularInfo))
+ .append(", dns: ")
+ .append(HexDump.toHexString(mDns));
+ return sb.toString();
+ }
+
+ /**
+ * Utility to create an instance of {@Link DataStallDetectionStats}
+ *
+ * @hide
+ */
+ public static class Builder {
+ @Nullable
+ private byte[] mCellularInfo;
+ @Nullable
+ private byte[] mWifiInfo;
+ @NonNull
+ private final List<Integer> mDnsReturnCode = new ArrayList<Integer>();
+ @NonNull
+ private final List<Long> mDnsTimeStamp = new ArrayList<Long>();
+ private int mEvaluationType;
+ private int mNetworkType;
+
+ /**
+ * Add a dns event into Builder.
+ *
+ * @param code the return code of the dns event.
+ * @param timeMs the elapsedRealtime in ms that the the dns event was received from netd.
+ * @return {@code this} {@link Builder} instance.
+ */
+ public Builder addDnsEvent(int code, long timeMs) {
+ mDnsReturnCode.add(code);
+ mDnsTimeStamp.add(timeMs);
+ return this;
+ }
+
+ /**
+ * Set the dns evaluation type into Builder.
+ *
+ * @param type the return code of the dns event.
+ * @return {@code this} {@link Builder} instance.
+ */
+ public Builder setEvaluationType(int type) {
+ mEvaluationType = type;
+ return this;
+ }
+
+ /**
+ * Set the network type into Builder.
+ *
+ * @param type the network type of the logged network.
+ * @return {@code this} {@link Builder} instance.
+ */
+ public Builder setNetworkType(int type) {
+ mNetworkType = type;
+ return this;
+ }
+
+ /**
+ * Set the wifi data into Builder.
+ *
+ * @param info a {@link WifiInfo} of the connected wifi network.
+ * @return {@code this} {@link Builder} instance.
+ */
+ public Builder setWiFiData(@Nullable final WifiInfo info) {
+ WifiData data = new WifiData();
+ data.wifiBand = getWifiBand(info);
+ data.signalStrength = (info != null) ? info.getRssi() : UNKNOWN_SIGNAL_STRENGTH;
+ mWifiInfo = MessageNano.toByteArray(data);
+ return this;
+ }
+
+ private static int getWifiBand(@Nullable final WifiInfo info) {
+ if (info != null) {
+ int freq = info.getFrequency();
+ // Refer to ScanResult.is5GHz() and ScanResult.is24GHz().
+ if (freq > 4900 && freq < 5900) {
+ return DataStallEventProto.AP_BAND_5GHZ;
+ } else if (freq > 2400 && freq < 2500) {
+ return DataStallEventProto.AP_BAND_2GHZ;
+ }
+ }
+ return DataStallEventProto.AP_BAND_UNKNOWN;
+ }
+
+ /**
+ * Set the cellular data into Builder.
+ *
+ * @param radioType the radio technology of the logged cellular network.
+ * @param roaming a boolean indicates if logged cellular network is roaming or not.
+ * @param networkMccmnc the mccmnc of the camped network.
+ * @param simMccmnc the mccmnc of the sim.
+ * @return {@code this} {@link Builder} instance.
+ */
+ public Builder setCellData(int radioType, boolean roaming,
+ @NonNull String networkMccmnc, @NonNull String simMccmnc, int ss) {
+ CellularData data = new CellularData();
+ data.ratType = radioType;
+ data.isRoaming = roaming;
+ data.networkMccmnc = networkMccmnc;
+ data.simMccmnc = simMccmnc;
+ data.signalStrength = ss;
+ mCellularInfo = MessageNano.toByteArray(data);
+ return this;
+ }
+
+ /**
+ * Create a new {@Link DataStallDetectionStats}.
+ */
+ public DataStallDetectionStats build() {
+ return new DataStallDetectionStats(mCellularInfo, mWifiInfo,
+ NetworkStackUtils.convertToIntArray(mDnsReturnCode),
+ NetworkStackUtils.convertToLongArray(mDnsTimeStamp),
+ mEvaluationType, mNetworkType);
+ }
+ }
+}
diff --git a/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java b/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java
new file mode 100644
index 0000000..17a36ad
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java
@@ -0,0 +1,66 @@
+/*
+ * 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.metrics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.captiveportal.CaptivePortalProbeResult;
+import android.util.Log;
+
+import com.android.internal.util.HexDump;
+import com.android.server.connectivity.nano.DataStallEventProto;
+
+/**
+ * Collection of utilities for data stall metrics.
+ *
+ * To see if the logs are properly sent to statsd, execute following command.
+ *
+ * $ adb shell cmd stats print-logs
+ * $ adb logcat | grep statsd OR $ adb logcat -b stats
+ *
+ * @hide
+ */
+public class DataStallStatsUtils {
+ private static final String TAG = DataStallStatsUtils.class.getSimpleName();
+ private static final boolean DBG = false;
+
+ private static int probeResultToEnum(@Nullable final CaptivePortalProbeResult result) {
+ if (result == null) return DataStallEventProto.INVALID;
+
+ // TODO: Add partial connectivity support.
+ if (result.isSuccessful()) {
+ return DataStallEventProto.VALID;
+ } else if (result.isPortal()) {
+ return DataStallEventProto.PORTAL;
+ } else {
+ return DataStallEventProto.INVALID;
+ }
+ }
+
+ /**
+ * Write the metric to {@link StatsLog}.
+ */
+ public static void write(@NonNull final DataStallDetectionStats stats,
+ @NonNull final CaptivePortalProbeResult result) {
+ int validationResult = probeResultToEnum(result);
+ if (DBG) {
+ Log.d(TAG, "write: " + stats + " with result: " + validationResult
+ + ", dns: " + HexDump.toHexString(stats.mDns));
+ }
+ // TODO(b/124613085): Send to Statsd once the public StatsLog API is ready.
+ }
+}
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
index 98123a5..481dbda 100644
--- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -16,8 +16,11 @@
package android.net.util;
+import android.annotation.NonNull;
+
import java.io.FileDescriptor;
import java.io.IOException;
+import java.util.List;
/**
* Collection of utilities for the network stack.
@@ -40,4 +43,26 @@
} catch (IOException ignored) {
}
}
+
+ /**
+ * Returns an int array from the given Integer list.
+ */
+ public static int[] convertToIntArray(@NonNull List<Integer> list) {
+ int[] array = new int[list.size()];
+ for (int i = 0; i < list.size(); i++) {
+ array[i] = list.get(i);
+ }
+ return array;
+ }
+
+ /**
+ * Returns a long array from the given long list.
+ */
+ public static long[] convertToLongArray(@NonNull List<Long> list) {
+ long[] array = new long[list.size()];
+ for (int i = 0; i < list.size(); i++) {
+ array[i] = list.get(i);
+ }
+ return array;
+ }
}
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 4b846b0..3c129ce 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -33,6 +33,7 @@
import static android.net.metrics.ValidationProbeEvent.PROBE_PRIVDNS;
import static android.net.util.NetworkStackUtils.isEmpty;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -50,6 +51,8 @@
import android.net.Uri;
import android.net.captiveportal.CaptivePortalProbeResult;
import android.net.captiveportal.CaptivePortalProbeSpec;
+import android.net.metrics.DataStallDetectionStats;
+import android.net.metrics.DataStallStatsUtils;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
import android.net.metrics.ValidationProbeEvent;
@@ -66,8 +69,10 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.AccessNetworkConstants;
+import android.telephony.CellSignalStrength;
import android.telephony.NetworkRegistrationState;
import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -126,6 +131,9 @@
private static final int DATA_STALL_EVALUATION_TYPE_DNS = 1;
private static final int DEFAULT_DATA_STALL_EVALUATION_TYPES =
(1 << DATA_STALL_EVALUATION_TYPE_DNS);
+ // Reevaluate it as intending to increase the number. Larger log size may cause statsd
+ // log buffer bust and have stats log lost.
+ private static final int DEFAULT_DNS_LOG_SIZE = 20;
enum EvaluationResult {
VALIDATED(true),
@@ -244,6 +252,7 @@
private final ConnectivityManager mCm;
private final IpConnectivityLog mMetricsLog;
private final Dependencies mDependencies;
+ private final DataStallStatsUtils mDetectionStatsUtils;
// Configuration values for captive portal detection probes.
private final String mCaptivePortalUserAgent;
@@ -302,17 +311,19 @@
private final int mDataStallEvaluationType;
private final DnsStallDetector mDnsStallDetector;
private long mLastProbeTime;
+ // Set to true if data stall is suspected and reset to false after metrics are sent to statsd.
+ private boolean mCollectDataStallMetrics = false;
public NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network,
SharedLog validationLog) {
this(context, cb, network, new IpConnectivityLog(), validationLog,
- Dependencies.DEFAULT);
+ Dependencies.DEFAULT, new DataStallStatsUtils());
}
@VisibleForTesting
protected NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network,
IpConnectivityLog logger, SharedLog validationLogs,
- Dependencies deps) {
+ Dependencies deps, DataStallStatsUtils detectionStatsUtils) {
// Add suffix indicating which NetworkMonitor we're talking about.
super(TAG + "/" + network.toString());
@@ -325,6 +336,7 @@
mValidationLogs = validationLogs;
mCallback = cb;
mDependencies = deps;
+ mDetectionStatsUtils = detectionStatsUtils;
mNonPrivateDnsBypassNetwork = network;
mNetwork = deps.getPrivateDnsBypassNetwork(network);
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
@@ -656,6 +668,7 @@
case EVENT_DNS_NOTIFICATION:
mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1);
if (isDataStall()) {
+ mCollectDataStallMetrics = true;
validationLog("Suspecting data stall, reevaluate");
transitionTo(mEvaluatingState);
}
@@ -667,6 +680,65 @@
}
}
+ private void writeDataStallStats(@NonNull final CaptivePortalProbeResult result) {
+ /*
+ * Collect data stall detection level information for each transport type. Collect type
+ * specific information for cellular and wifi only currently. Generate
+ * DataStallDetectionStats for each transport type. E.g., if a network supports both
+ * TRANSPORT_WIFI and TRANSPORT_VPN, two DataStallDetectionStats will be generated.
+ */
+ final int[] transports = mNetworkCapabilities.getTransportTypes();
+
+ for (int i = 0; i < transports.length; i++) {
+ DataStallStatsUtils.write(buildDataStallDetectionStats(transports[i]), result);
+ }
+ mCollectDataStallMetrics = false;
+ }
+
+ @VisibleForTesting
+ protected DataStallDetectionStats buildDataStallDetectionStats(int transport) {
+ final DataStallDetectionStats.Builder stats = new DataStallDetectionStats.Builder();
+ if (VDBG_STALL) log("collectDataStallMetrics: type=" + transport);
+ stats.setEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS);
+ stats.setNetworkType(transport);
+ switch (transport) {
+ case NetworkCapabilities.TRANSPORT_WIFI:
+ // TODO: Update it if status query in dual wifi is supported.
+ final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+ stats.setWiFiData(wifiInfo);
+ break;
+ case NetworkCapabilities.TRANSPORT_CELLULAR:
+ final boolean isRoaming = !mNetworkCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
+ final SignalStrength ss = mTelephonyManager.getSignalStrength();
+ // TODO(b/120452078): Support multi-sim.
+ stats.setCellData(
+ mTelephonyManager.getDataNetworkType(),
+ isRoaming,
+ mTelephonyManager.getNetworkOperator(),
+ mTelephonyManager.getSimOperator(),
+ (ss != null)
+ ? ss.getLevel() : CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
+ break;
+ default:
+ // No transport type specific information for the other types.
+ break;
+ }
+ addDnsEvents(stats);
+
+ return stats.build();
+ }
+
+ private void addDnsEvents(@NonNull final DataStallDetectionStats.Builder stats) {
+ final int size = mDnsStallDetector.mResultIndices.size();
+ for (int i = 1; i <= DEFAULT_DNS_LOG_SIZE && i <= size; i++) {
+ final int index = mDnsStallDetector.mResultIndices.indexOf(size - i);
+ stats.addDnsEvent(mDnsStallDetector.mDnsEvents[index].mReturnCode,
+ mDnsStallDetector.mDnsEvents[index].mTimeStamp);
+ }
+ }
+
+
// Being in the MaybeNotifyState State indicates the user may have been notified that sign-in
// is required. This State takes care to clear the notification upon exit from the State.
private class MaybeNotifyState extends State {
@@ -972,6 +1044,11 @@
final CaptivePortalProbeResult probeResult =
(CaptivePortalProbeResult) message.obj;
mLastProbeTime = SystemClock.elapsedRealtime();
+
+ if (mCollectDataStallMetrics) {
+ writeDataStallStats(probeResult);
+ }
+
if (probeResult.isSuccessful()) {
// Transit EvaluatingPrivateDnsState to get to Validated
// state (even if no Private DNS validation required).
@@ -1617,7 +1694,6 @@
*/
@VisibleForTesting
protected class DnsStallDetector {
- private static final int DEFAULT_DNS_LOG_SIZE = 50;
private int mConsecutiveTimeoutCount = 0;
private int mSize;
final DnsResult[] mDnsEvents;
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 9a16bb7..beb975d 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -30,6 +30,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyObject;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
@@ -48,6 +49,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.captiveportal.CaptivePortalProbeResult;
+import android.net.metrics.DataStallStatsUtils;
import android.net.metrics.IpConnectivityLog;
import android.net.util.SharedLog;
import android.net.wifi.WifiManager;
@@ -98,6 +100,7 @@
private @Mock NetworkMonitor.Dependencies mDependencies;
private @Mock INetworkMonitorCallbacks mCallbacks;
private @Spy Network mNetwork = new Network(TEST_NETID);
+ private @Mock DataStallStatsUtils mDataStallStatsUtils;
private static final int TEST_NETID = 4242;
@@ -186,9 +189,9 @@
private long mProbeTime = 0;
WrappedNetworkMonitor(Context context, Network network, IpConnectivityLog logger,
- Dependencies deps) {
+ Dependencies deps, DataStallStatsUtils statsUtils) {
super(context, mCallbacks, network, logger,
- new SharedLog("test_nm"), deps);
+ new SharedLog("test_nm"), deps, statsUtils);
}
@Override
@@ -203,7 +206,7 @@
private WrappedNetworkMonitor makeMeteredWrappedNetworkMonitor() {
final WrappedNetworkMonitor nm = new WrappedNetworkMonitor(
- mContext, mNetwork, mLogger, mDependencies);
+ mContext, mNetwork, mLogger, mDependencies, mDataStallStatsUtils);
when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES);
nm.start();
waitForIdle(nm.getHandler());
@@ -212,7 +215,7 @@
private WrappedNetworkMonitor makeNotMeteredWrappedNetworkMonitor() {
final WrappedNetworkMonitor nm = new WrappedNetworkMonitor(
- mContext, mNetwork, mLogger, mDependencies);
+ mContext, mNetwork, mLogger, mDependencies, mDataStallStatsUtils);
when(mCm.getNetworkCapabilities(any())).thenReturn(NOT_METERED_CAPABILITIES);
nm.start();
waitForIdle(nm.getHandler());
@@ -222,7 +225,7 @@
private NetworkMonitor makeMonitor() {
final NetworkMonitor nm = new NetworkMonitor(
mContext, mCallbacks, mNetwork, mLogger, mValidationLogger,
- mDependencies);
+ mDependencies, mDataStallStatsUtils);
nm.start();
waitForIdle(nm.getHandler());
return nm;
@@ -505,6 +508,23 @@
.notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
}
+ @Test
+ public void testDataStall_StallSuspectedAndSendMetrics() throws IOException {
+ WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
+ wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
+ makeDnsTimeoutEvent(wrappedMonitor, 5);
+ assertTrue(wrappedMonitor.isDataStall());
+ verify(mDataStallStatsUtils, times(1)).write(eq(anyObject()), eq(anyObject()));
+ }
+
+ @Test
+ public void testDataStall_NoStallSuspectedAndSendMetrics() throws IOException {
+ WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
+ wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
+ makeDnsTimeoutEvent(wrappedMonitor, 3);
+ assertFalse(wrappedMonitor.isDataStall());
+ verify(mDataStallStatsUtils, times(0)).write(eq(anyObject()), eq(anyObject()));
+ }
private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
for (int i = 0; i < count; i++) {
wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index a7ad223..ceafbfa 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1379,8 +1379,8 @@
}
}
if (enableOverride) {
- if (Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
- final Setting overridden = getLocationProvidersAllowedSetting(owningUserId);
+ if (Secure.LOCATION_MODE.equals(name)) {
+ final Setting overridden = getLocationModeSetting(owningUserId);
if (overridden != null) {
return overridden;
}
@@ -1475,7 +1475,7 @@
return null;
}
- private Setting getLocationProvidersAllowedSetting(int owningUserId) {
+ private Setting getLocationModeSetting(int owningUserId) {
synchronized (mLock) {
final Setting setting = getGlobalSetting(
Global.LOCATION_GLOBAL_KILL_SWITCH);
@@ -1486,7 +1486,7 @@
final SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
SETTINGS_TYPE_SECURE, owningUserId);
return settingsState.new Setting(
- Secure.LOCATION_PROVIDERS_ALLOWED,
+ Secure.LOCATION_MODE,
"", // value
"", // tag
"", // default value
@@ -1497,7 +1497,7 @@
@Override
public boolean update(String value, boolean setDefault, String packageName,
String tag, boolean forceNonSystemPackage) {
- Slog.wtf(LOG_TAG, "update shoudln't be called on this instance.");
+ Slog.wtf(LOG_TAG, "update shouldn't be called on this instance.");
return false;
}
};
@@ -3115,7 +3115,7 @@
final int key = makeKey(SETTINGS_TYPE_SECURE, userId);
mGenerationRegistry.incrementGeneration(key);
- final Uri uri = getNotificationUriFor(key, Secure.LOCATION_PROVIDERS_ALLOWED);
+ final Uri uri = getNotificationUriFor(key, Secure.LOCATION_MODE);
mHandler.obtainMessage(MyHandler.MSG_NOTIFY_URI_CHANGED,
userId, 0, uri).sendToTarget();
}
diff --git a/packages/SystemUI/res/drawable/ic_tune_black_16dp.xml b/packages/SystemUI/res/drawable/ic_tune_black_16dp.xml
new file mode 100644
index 0000000..339cb70
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_tune_black_16dp.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="16dp"
+ android:height="16dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M3,17v2h6v-2L3,17zM3,5v2h10L13,5L3,5zM13,21v-2h8v-2h-8v-2h-2v6h2zM7,9v2L3,11v2h4v2h2L9,9L7,9zM21,13v-2L11,11v2h10zM15,9h2L17,7h4L21,5h-4L17,3h-2v6z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_customize_tile_decoration.xml b/packages/SystemUI/res/drawable/qs_customize_tile_decoration.xml
new file mode 100644
index 0000000..f086cec
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_customize_tile_decoration.xml
@@ -0,0 +1,17 @@
+<!--
+ 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.
+-->
+<color xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/qs_customize_decoration"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml b/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml
index abe1429..215dee4 100644
--- a/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml
+++ b/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml
@@ -15,7 +15,7 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape>
- <solid android:color="?android:attr/colorPrimary"/>
+ <solid android:color="@color/qs_customize_background"/>
<corners android:radius="?android:attr/dialogCornerRadius" />
</shape>
</inset>
diff --git a/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml b/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml
index 557cae1..648d45b 100644
--- a/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml
+++ b/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml
@@ -15,7 +15,7 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape>
- <solid android:color="?android:attr/colorSecondary"/>
+ <solid android:color="@color/qs_customize_background"/>
<corners
android:topLeftRadius="?android:attr/dialogCornerRadius"
android:topRightRadius="?android:attr/dialogCornerRadius" />
diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml
index 5b9816d..66c0c5c 100644
--- a/packages/SystemUI/res/layout/keyguard_status_bar.xml
+++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml
@@ -71,7 +71,7 @@
android:gravity="center_vertical"
android:ellipsize="marquee"
android:textDirection="locale"
- android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
android:textColor="?attr/wallpaperTextColorSecondary"
android:singleLine="true"
systemui:showMissingSim="true"
diff --git a/packages/SystemUI/res/layout/qs_customize_divider.xml b/packages/SystemUI/res/layout/qs_customize_divider.xml
index 6fcfa8d..d6664fe 100644
--- a/packages/SystemUI/res/layout/qs_customize_divider.xml
+++ b/packages/SystemUI/res/layout/qs_customize_divider.xml
@@ -24,5 +24,4 @@
android:paddingTop="20dp"
android:paddingBottom="13dp"
android:textAppearance="@style/TextAppearance.QSEdit.Headers"
- android:textColor="?android:attr/colorAccent"
android:text="@string/drag_to_add_tiles" />
diff --git a/packages/SystemUI/res/layout/qs_customize_header.xml b/packages/SystemUI/res/layout/qs_customize_header.xml
index d54dfee..58066a3 100644
--- a/packages/SystemUI/res/layout/qs_customize_header.xml
+++ b/packages/SystemUI/res/layout/qs_customize_header.xml
@@ -24,5 +24,4 @@
android:gravity="center"
android:minHeight="@dimen/qs_customize_header_min_height"
android:textAppearance="@style/TextAppearance.QSEdit.Headers"
- android:textColor="?android:attr/colorAccent"
android:text="@string/drag_to_rearrange_tiles" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_customize_panel_content.xml b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
index 87b4551..09f512f 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel_content.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
@@ -37,7 +37,8 @@
android:layout_height="wrap_content"
android:background="@drawable/qs_customizer_toolbar"
android:navigationContentDescription="@*android:string/action_bar_up_description"
- style="?android:attr/toolbarStyle" />
+ style="@style/QSCustomizeToolbar"
+ />
<androidx.recyclerview.widget.RecyclerView
android:id="@android:id/list"
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index e67bb60..ca34c23 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -87,7 +87,7 @@
android:background="@drawable/rounded_bg_bottom_background">
<com.android.keyguard.AlphaOptimizedImageButton
android:id="@+id/settings"
- android:src="@drawable/ic_settings_16dp"
+ android:src="@drawable/ic_tune_black_16dp"
android:layout_width="@dimen/volume_dialog_tap_target_size"
android:layout_height="@dimen/volume_dialog_tap_target_size"
android:layout_gravity="center"
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 2c5120d..5803bf1 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -41,4 +41,10 @@
<!-- The color of the text inside a notification -->
<color name="notification_primary_text_color">@*android:color/notification_primary_text_color_dark</color>
+
+ <!-- The color of the background in the top part of QSCustomizer -->
+ <color name="qs_customize_background">@color/GM2_grey_900</color>
+
+ <!-- The color of the background in the bottom part of QSCustomizer -->
+ <color name="qs_customize_decoration">@color/GM2_grey_800</color>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index d5f29ba..0e4ffee 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -35,6 +35,8 @@
<color name="status_bar_clock_color">#FFFFFFFF</color>
<color name="qs_user_detail_icon_muted">#FFFFFFFF</color> <!-- not so muted after all -->
<color name="qs_tile_disabled_color">#9E9E9E</color> <!-- 38% black -->
+ <color name="qs_customize_background">@color/GM2_grey_50</color>
+ <color name="qs_customize_decoration">@color/GM2_grey_100</color>
<!-- Tint color for the content on the notification overflow card. -->
<color name="keyguard_overflow_content_color">#ff686868</color>
@@ -72,7 +74,7 @@
<color name="notification_primary_text_color">@*android:color/notification_primary_text_color_light</color>
<!-- The "inside" of a notification, reached via longpress -->
- <color name="notification_guts_bg_color">#f8f9fa</color>
+ <color name="notification_guts_bg_color">@color/GM2_grey_50</color>
<color name="assist_orb_color">#ffffff</color>
@@ -123,7 +125,7 @@
<color name="zen_introduction">#ffffffff</color>
- <color name="smart_reply_button_text">#5F6368</color>
+ <color name="smart_reply_button_text">@color/GM2_grey_700</color>
<color name="smart_reply_button_text_dark_bg">@*android:color/notification_primary_text_color_dark</color>
<color name="smart_reply_button_background">#ffffffff</color>
<color name="smart_reply_button_stroke">#ffdadce0</color>
@@ -134,4 +136,17 @@
<!-- Logout button -->
<color name="logout_button_bg_color">#ccffffff</color>
+
+ <!-- GM2 colors -->
+ <color name="GM2_grey_50">#F8F9FA</color>
+ <color name="GM2_grey_100">#F1F3F4</color>
+ <color name="GM2_grey_200">#E8EAED</color>
+ <color name="GM2_grey_300">#DADCE0</color>
+ <color name="GM2_grey_400">#BDC1C6</color>
+ <color name="GM2_grey_500">#9AA0A6</color>
+ <color name="GM2_grey_600">#80868B</color>
+ <color name="GM2_grey_650">#70757A</color>
+ <color name="GM2_grey_700">#5F6368</color>
+ <color name="GM2_grey_800">#3C4043</color>
+ <color name="GM2_grey_900">#202124</color>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 96cdbd3..1e411cf 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -458,8 +458,15 @@
</style>
<style name="TextAppearance.QSEdit.Headers"
- parent="@*android:style/TextAppearance.Material.Body2">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ parent="@*android:style/TextAppearance.DeviceDefault.Body2">
+ <item name="android:textSize">11sp</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textAllCaps">true</item>
+ </style>
+
+ <style name="QSCustomizeToolbar" parent="@*android:style/Widget.DeviceDefault.Toolbar">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:elevation">10dp</item>
</style>
<style name="edit_theme" parent="qs_theme">
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/StatsLogCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/StatsLogCompat.java
index 5bc1f25..d17725f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/StatsLogCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/StatsLogCompat.java
@@ -32,4 +32,17 @@
StatsLog.write(19, action, srcState, dstState, extension,
swipeUpEnabled);
}
+
+ /**
+ * StatsLog.write(StatsLog.STYLE_EVENT, action, colorPackageHash,
+ * fontPackageHash, shapePackageHash, clockPackageHash,
+ * launcherGrid, wallpaperCategoryHash, wallpaperIdHash);
+ */
+ public static void write(int action, int colorPackageHash,
+ int fontPackageHash, int shapePackageHash, int clockPackageHash,
+ int launcherGrid, int wallpaperCategoryHash, int wallpaperIdHash) {
+ StatsLog.write(179, action, colorPackageHash,
+ fontPackageHash, shapePackageHash, clockPackageHash,
+ launcherGrid, wallpaperCategoryHash, wallpaperIdHash);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 5672073..87f004f 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -61,7 +61,6 @@
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.NotificationRowBinder;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -266,7 +265,6 @@
@Inject Lazy<NotificationListener> mNotificationListener;
@Inject Lazy<NotificationLogger> mNotificationLogger;
@Inject Lazy<NotificationViewHierarchyManager> mNotificationViewHierarchyManager;
- @Inject Lazy<NotificationRowBinder> mNotificationRowBinder;
@Inject Lazy<NotificationFilter> mNotificationFilter;
@Inject Lazy<NotificationInterruptionStateProvider> mNotificationInterruptionStateProvider;
@Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil;
@@ -440,7 +438,6 @@
mProviders.put(NotificationLogger.class, mNotificationLogger::get);
mProviders.put(NotificationViewHierarchyManager.class,
mNotificationViewHierarchyManager::get);
- mProviders.put(NotificationRowBinder.class, mNotificationRowBinder::get);
mProviders.put(NotificationFilter.class, mNotificationFilter::get);
mProviders.put(NotificationInterruptionStateProvider.class,
mNotificationInterruptionStateProvider::get);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 64ad95c..c209b31 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -38,7 +38,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
-import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QS;
@@ -103,10 +102,6 @@
mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
mContext.getString(com.android.internal.R.string.reset));
mToolbar.setTitle(R.string.qs_edit);
- int accentColor = Utils.getColorAttrDefaultColor(context, android.R.attr.colorAccent);
- mToolbar.setTitleTextColor(accentColor);
- mToolbar.getNavigationIcon().setTint(accentColor);
- mToolbar.getOverflowIcon().setTint(accentColor);
mRecyclerView = findViewById(android.R.id.list);
mTransparentView = findViewById(R.id.customizer_transparent_view);
mTileAdapter = new TileAdapter(getContext());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index a29e93a..608f646 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -19,9 +19,8 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.res.TypedArray;
import android.graphics.Canvas;
-import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
@@ -505,13 +504,10 @@
};
private class TileItemDecoration extends ItemDecoration {
- private final ColorDrawable mDrawable;
+ private final Drawable mDrawable;
private TileItemDecoration(Context context) {
- TypedArray ta =
- context.obtainStyledAttributes(new int[]{android.R.attr.colorSecondary});
- mDrawable = new ColorDrawable(ta.getColor(0, 0));
- ta.recycle();
+ mDrawable = context.getDrawable(R.drawable.qs_customize_tile_decoration);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 52a8814..3e40cfc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -22,6 +22,7 @@
import android.content.res.Resources;
import android.provider.Settings;
import android.service.quicksettings.Tile;
+import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -208,6 +209,9 @@
if (wifiConnected) {
minimalContentDescription.append(cb.wifiSignalContentDescription).append(",");
minimalContentDescription.append(removeDoubleQuotes(cb.ssid));
+ if (!TextUtils.isEmpty(state.secondaryLabel)) {
+ minimalContentDescription.append(",").append(state.secondaryLabel);
+ }
}
}
state.contentDescription = minimalContentDescription.toString();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
index 22d1d5b..d427260 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
@@ -32,6 +32,8 @@
*/
public class FlingAnimationUtils {
+ private static final String TAG = "FlingAnimationUtils";
+
private static final float LINEAR_OUT_SLOW_IN_X2 = 0.35f;
private static final float LINEAR_OUT_SLOW_IN_X2_MAX = 0.68f;
private static final float LINEAR_OUT_FASTER_IN_X2 = 0.5f;
@@ -195,6 +197,10 @@
}
private Interpolator getInterpolator(float startGradient, float velocityFactor) {
+ if (Float.isNaN(velocityFactor)) {
+ Log.e(TAG, "Invalid velocity factor", new Throwable());
+ return Interpolators.LINEAR_OUT_SLOW_IN;
+ }
if (startGradient != mCachedStartGradient
|| velocityFactor != mCachedVelocityFactor) {
float speedup = mSpeedUpFactor * (1.0f - velocityFactor);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index c945afd..f34b912 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -15,7 +15,6 @@
*/
package com.android.systemui.statusbar;
-import com.android.systemui.statusbar.notification.NotificationRowBinder;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -27,8 +26,7 @@
* want to perform some action before doing so).
*/
public interface NotificationPresenter extends ExpandableNotificationRow.OnExpandClickListener,
- ActivatableNotificationView.OnActivatedListener,
- NotificationRowBinder.BindRowCallback {
+ ActivatableNotificationView.OnActivatedListener {
/**
* Returns true if the presenter is not visible. For example, it may not be necessary to do
* animations if this returns true.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 3fbc641..4ed9ae4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -35,6 +35,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
@@ -124,16 +125,7 @@
return mRemoteInputManager;
}
- private NotificationRowBinder getRowBinder() {
- if (mNotificationRowBinder == null) {
- mNotificationRowBinder = Dependency.get(NotificationRowBinder.class);
- }
- return mNotificationRowBinder;
- }
-
- // TODO: Remove this once we can always use a mocked row binder in our tests
- @VisibleForTesting
- void setRowBinder(NotificationRowBinder notificationRowBinder) {
+ public void setRowBinder(NotificationRowBinder notificationRowBinder) {
mNotificationRowBinder = notificationRowBinder;
}
@@ -345,7 +337,7 @@
Dependency.get(LeakDetector.class).trackInstance(entry);
// Construct the expanded view.
- getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification));
+ requireBinder().inflateViews(entry, () -> performRemoveNotification(notification));
abortExistingInflation(key);
@@ -386,7 +378,7 @@
listener.onPreEntryUpdated(entry);
}
- getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification));
+ requireBinder().inflateViews(entry, () -> performRemoveNotification(notification));
updateNotifications();
if (DEBUG) {
@@ -440,7 +432,7 @@
// By comparing the old and new UI adjustments, reinflate the view accordingly.
for (NotificationEntry entry : entries) {
- getRowBinder().onNotificationRankingUpdated(
+ requireBinder().onNotificationRankingUpdated(
entry,
oldImportances.get(entry.key),
oldAdjustments.get(entry.key),
@@ -486,4 +478,12 @@
activeExtender.setShouldManageLifetime(entry, false);
}
}
+
+ private NotificationRowBinder requireBinder() {
+ if (mNotificationRowBinder == null) {
+ throw new RuntimeException("You must initialize NotificationEntryManager by calling"
+ + "setRowBinder() before using.");
+ }
+ return mNotificationRowBinder;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinder.java
new file mode 100644
index 0000000..7504e86
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinder.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import android.annotation.Nullable;
+
+import com.android.systemui.statusbar.NotificationUiAdjustment;
+import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+
+/**
+ * Used by the {@link NotificationEntryManager}. When notifications are added or updated, the binder
+ * is asked to (re)inflate and prepare their views. This inflation must occur off the main thread.
+ */
+public interface NotificationRowBinder {
+ /**
+ * Called when a notification has been added or updated. The binder must asynchronously inflate
+ * and bind the views associated with the notification.
+ *
+ * TODO: The caller is notified when the inflation completes, but this is currently a very
+ * roundabout business. Add an explicit completion/failure callback to this method.
+ */
+ void inflateViews(
+ NotificationEntry entry,
+ Runnable onDismissRunnable)
+ throws InflationException;
+
+ /**
+ * Called when the ranking has been updated (but not add or remove has been done). The binder
+ * should inspect the old and new adjustments and re-inflate the entry's views if necessary
+ * (e.g. if something important changed).
+ */
+ void onNotificationRankingUpdated(
+ NotificationEntry entry,
+ @Nullable Integer oldImportance,
+ NotificationUiAdjustment oldAdjustment,
+ NotificationUiAdjustment newAdjustment);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
index 6f5baf9..b91cdaf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification;
+package com.android.systemui.statusbar.notification.collection;
import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT;
import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_HEADS_UP;
@@ -39,7 +38,9 @@
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationUiAdjustment;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.NotificationClicker;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
@@ -50,13 +51,8 @@
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
/** Handles inflating and updating views for notifications. */
-@Singleton
-public class NotificationRowBinder {
+public class NotificationRowBinderImpl implements NotificationRowBinder {
private static final String TAG = "NotificationViewManager";
@@ -84,9 +80,7 @@
private NotificationClicker mNotificationClicker;
private final NotificationLogger mNotificationLogger = Dependency.get(NotificationLogger.class);
- @Inject
- public NotificationRowBinder(Context context,
- @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress) {
+ public NotificationRowBinderImpl(Context context, boolean allowLongPress) {
mContext = context;
mMessagingUtil = new NotificationMessagingUtil(context);
mAllowLongPress = allowLongPress;
@@ -122,6 +116,7 @@
/**
* Inflates the views for the given entry (possibly asynchronously).
*/
+ @Override
public void inflateViews(
NotificationEntry entry,
Runnable onDismissRunnable)
@@ -192,6 +187,7 @@
* Updates the views bound to an entry when the entry's ranking changes, either in-place or by
* reinflating them.
*/
+ @Override
public void onNotificationRankingUpdated(
NotificationEntry entry,
@Nullable Integer oldImportance,
@@ -264,7 +260,7 @@
}
private void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
- mNotificationLogger.onExpansionChanged(key, userAction, expanded);
+ mNotificationLogger.onExpansionChanged(key, userAction, expanded);
}
/** Callback for when a row is bound to an entry. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 13d4489..41580f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -195,9 +195,9 @@
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationListController;
-import com.android.systemui.statusbar.notification.NotificationRowBinder;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -390,7 +390,6 @@
protected NotificationEntryManager mEntryManager;
private NotificationListController mNotificationListController;
private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
- private NotificationRowBinder mNotificationRowBinder;
protected NotificationViewHierarchyManager mViewHierarchyManager;
protected ForegroundServiceController mForegroundServiceController;
protected AppOpsController mAppOpsController;
@@ -620,7 +619,6 @@
mEntryManager = Dependency.get(NotificationEntryManager.class);
mNotificationInterruptionStateProvider =
Dependency.get(NotificationInterruptionStateProvider.class);
- mNotificationRowBinder = Dependency.get(NotificationRowBinder.class);
mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class);
mForegroundServiceController = Dependency.get(ForegroundServiceController.class);
mAppOpsController = Dependency.get(AppOpsController.class);
@@ -1032,10 +1030,15 @@
mStatusBarWindow, this, mNotificationPanel,
(NotificationListContainer) mStackScroller);
+ final NotificationRowBinderImpl rowBinder =
+ new NotificationRowBinderImpl(
+ mContext,
+ SystemUIFactory.getInstance().provideAllowNotificationLongPress());
+
mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
mScrimController, mActivityLaunchAnimator, mStatusBarKeyguardViewManager,
- mNotificationAlertingManager);
+ mNotificationAlertingManager, rowBinder);
mNotificationListController =
new NotificationListController(
@@ -1051,7 +1054,9 @@
mNotificationActivityStarter = new StatusBarNotificationActivityStarter(
mContext, mNotificationPanel, mPresenter, mHeadsUpManager, mActivityLaunchAnimator);
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
- mNotificationRowBinder.setNotificationClicker(new NotificationClicker(
+
+ mEntryManager.setRowBinder(rowBinder);
+ rowBinder.setNotificationClicker(new NotificationClicker(
this, Dependency.get(BubbleController.class), mNotificationActivityStarter));
mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 3ce66c5..6fe8964 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -64,9 +64,9 @@
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.NotificationRowBinder;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -79,7 +79,8 @@
import java.util.ArrayList;
public class StatusBarNotificationPresenter implements NotificationPresenter,
- ConfigurationController.ConfigurationListener {
+ ConfigurationController.ConfigurationListener,
+ NotificationRowBinderImpl.BindRowCallback {
private final LockscreenGestureLogger mLockscreenGestureLogger =
Dependency.get(LockscreenGestureLogger.class);
@@ -97,8 +98,6 @@
(SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
private final NotificationEntryManager mEntryManager =
Dependency.get(NotificationEntryManager.class);
- private final NotificationRowBinder mNotificationRowBinder =
- Dependency.get(NotificationRowBinder.class);
private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
Dependency.get(NotificationInterruptionStateProvider.class);
private final NotificationMediaManager mMediaManager =
@@ -140,7 +139,8 @@
ScrimController scrimController,
ActivityLaunchAnimator activityLaunchAnimator,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
- NotificationAlertingManager notificationAlertingManager) {
+ NotificationAlertingManager notificationAlertingManager,
+ NotificationRowBinderImpl notificationRowBinder) {
mContext = context;
mNotificationPanel = panel;
mHeadsUpManager = headsUp;
@@ -217,7 +217,7 @@
mEntryManager.addNotificationLifetimeExtender(mGutsManager);
mEntryManager.addNotificationLifetimeExtenders(
remoteInputManager.getLifetimeExtenders());
- mNotificationRowBinder.setUpWithPresenter(this, notifListContainer, mHeadsUpManager,
+ notificationRowBinder.setUpWithPresenter(this, notifListContainer, mHeadsUpManager,
mEntryManager, this);
mNotificationInterruptionStateProvider.setUpWithPresenter(
this, mHeadsUpManager, this::canHeadsUp);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 617b191..f56727f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -431,8 +431,7 @@
if (mSettingsIcon != null) {
mSettingsIcon.setOnClickListener(v -> {
Events.writeEvent(mContext, Events.EVENT_SETTINGS_CLICK);
- Intent intent = new Intent(Settings.ACTION_SOUND_SETTINGS);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ Intent intent = new Intent(Settings.Panel.ACTION_VOLUME);
dismissH(DISMISS_REASON_SETTINGS_CLICKED);
Dependency.get(ActivityStarter.class).startActivity(intent,
true /* dismissShade */);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 04e7cab..0d4328f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -67,6 +67,8 @@
import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -102,10 +104,8 @@
@Mock private KeyguardEnvironment mEnvironment;
@Mock private ExpandableNotificationRow mRow;
@Mock private NotificationListContainer mListContainer;
- @Mock
- private NotificationEntryListener mEntryListener;
- @Mock
- private NotificationRowBinder.BindRowCallback mBindCallback;
+ @Mock private NotificationEntryListener mEntryListener;
+ @Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback;
@Mock private HeadsUpManager mHeadsUpManager;
@Mock private NotificationListenerService.RankingMap mRankingMap;
@Mock private RemoteInputController mRemoteInputController;
@@ -235,10 +235,12 @@
mEntryManager.setUpWithPresenter(mPresenter, mListContainer, mHeadsUpManager);
mEntryManager.addNotificationEntryListener(mEntryListener);
- NotificationRowBinder notificationRowBinder = Dependency.get(NotificationRowBinder.class);
+ NotificationRowBinderImpl notificationRowBinder =
+ new NotificationRowBinderImpl(mContext, true /* allowLongPress */);
notificationRowBinder.setUpWithPresenter(
mPresenter, mListContainer, mHeadsUpManager, mEntryManager, mBindCallback);
notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class));
+ mEntryManager.setRowBinder(notificationRowBinder);
setUserSentiment(mEntry.key, NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 12cb9957..d2b0f7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -41,6 +41,7 @@
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -74,7 +75,8 @@
statusBarWindowView, mock(NotificationListContainerViewGroup.class),
mock(DozeScrimController.class), mock(ScrimController.class),
mock(ActivityLaunchAnimator.class), mock(StatusBarKeyguardViewManager.class),
- mock(NotificationAlertingManager.class));
+ mock(NotificationAlertingManager.class),
+ mock(NotificationRowBinderImpl.class));
}
@Test
diff --git a/proto/Android.bp b/proto/Android.bp
index 7f826b3..7b119a7 100644
--- a/proto/Android.bp
+++ b/proto/Android.bp
@@ -28,14 +28,4 @@
srcs: ["src/metrics_constants/metrics_constants.proto"],
no_framework_libs: true,
sdk_version: "system_current",
- // Pin java_version until jarjar is certified to support later versions. http://b/72703434
- java_version: "1.8",
- target: {
- android: {
- jarjar_rules: "jarjar-rules.txt",
- },
- host: {
- static_libs: ["libprotobuf-java-nano"],
- },
- },
}
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index ee3777d..5fa7766 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -521,6 +521,9 @@
// Total number of saved networks with mac randomization enabled.
optional int32 num_saved_networks_with_mac_randomization = 138;
+
+ // Link Probe metrics
+ optional LinkProbeStats link_probe_stats = 139;
}
// Information that gets logged for every WiFi connection.
@@ -1959,7 +1962,6 @@
// The total duration elapsed while in this mobility state, in ms
optional int64 total_duration_ms = 3;
-
// the total duration elapsed while in this mobility state with PNO scans running, in ms
optional int64 pno_duration_ms = 4;
}
@@ -2211,3 +2213,76 @@
optional int32 count = 3;
}
}
+
+// Histogram bucket counting with int32. Range is [start, end)
+message HistogramBucketInt32 {
+ // lower range of the bucket (inclusive)
+ optional int32 start = 1;
+
+ // upper range of the bucket (exclusive)
+ optional int32 end = 2;
+
+ // number of samples in the bucket
+ optional int32 count = 3;
+}
+
+// Single entry in a map from int32 => int32
+message MapEntryInt32Int32 {
+ // the key
+ optional int32 key = 1;
+
+ // the value
+ optional int32 value = 2;
+}
+
+message LinkProbeStats {
+ enum LinkProbeFailureReason {
+ // unknown reason
+ LINK_PROBE_FAILURE_REASON_UNKNOWN = 0;
+
+ // Specified MCS rate when it is unsupported by the driver.
+ LINK_PROBE_FAILURE_REASON_MCS_UNSUPPORTED = 1;
+
+ // Driver reported that no ACK was received for the transmitted probe.
+ LINK_PROBE_FAILURE_REASON_NO_ACK = 2;
+
+ // Driver failed to report on the status of the transmitted probe within the timeout.
+ LINK_PROBE_FAILURE_REASON_TIMEOUT = 3;
+
+ // An existing link probe is in progress.
+ LINK_PROBE_FAILURE_REASON_ALREADY_STARTED = 4;
+ }
+
+ // Counts the number of failures for each failure reason.
+ message LinkProbeFailureReasonCount {
+ // The failure reason.
+ optional LinkProbeFailureReason failure_reason = 1;
+
+ // The number of occurrences for this failure reason.
+ optional int32 count = 2;
+ }
+
+ // Counts the occurrences of RSSI values when a link probe succeeds.
+ repeated MapEntryInt32Int32 success_rssi_counts = 1;
+
+ // Counts the occurrences of RSSI values when a link probe fails.
+ repeated MapEntryInt32Int32 failure_rssi_counts = 2;
+
+ // Counts the occurrences of Link Speed values when a link probe succeeds.
+ repeated MapEntryInt32Int32 success_link_speed_counts = 3;
+
+ // Counts the occurrences of Link Speed values when a link probe fails.
+ repeated MapEntryInt32Int32 failure_link_speed_counts = 4;
+
+ // Histogram for the number of seconds since the last TX success when a link probe succeeds.
+ repeated HistogramBucketInt32 success_seconds_since_last_tx_success_histogram = 5;
+
+ // Histogram for the number of seconds since the last TX success when a link probe fails.
+ repeated HistogramBucketInt32 failure_seconds_since_last_tx_success_histogram = 6;
+
+ // Histogram for the elapsed time of successful link probes, in ms.
+ repeated HistogramBucketInt32 success_elapsed_time_ms_histogram = 7;
+
+ // Counts the occurrences of error codes for failed link probes.
+ repeated LinkProbeFailureReasonCount failure_reason_counts = 8;
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 2e99654..b6d5b3d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -1097,14 +1097,17 @@
* Called when the {@link #mAugmentedAutofillResolver} changed (among other places).
*/
private void updateRemoteAugmentedAutofillService(@Nullable String serviceName) {
- if (serviceName == null) {
- if (sVerbose) Slog.v(TAG, "updateRemoteAugmentedAutofillService(): time's up!");
- synchronized (mLock) {
- if (mRemoteAugmentedAutofillService != null) {
- mRemoteAugmentedAutofillService.destroy();
- mRemoteAugmentedAutofillService = null;
+ synchronized (mLock) {
+ if (mRemoteAugmentedAutofillService != null) {
+ if (sVerbose) {
+ Slog.v(TAG, "updateRemoteAugmentedAutofillService(): "
+ + "destroying old remote service");
}
+ mRemoteAugmentedAutofillService.destroy();
+ mRemoteAugmentedAutofillService = null;
}
+
+ mRemoteAugmentedAutofillService = getRemoteAugmentedAutofillServiceLocked();
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 848f249..2b94d10d6 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -17,6 +17,7 @@
package com.android.server.autofill;
import static android.service.autofill.AutofillFieldClassificationService.EXTRA_SCORES;
+import static android.service.autofill.FillRequest.FLAG_AUGMENTED_AUTOFILL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
@@ -527,6 +528,16 @@
*/
@GuardedBy("mLock")
private void requestNewFillResponseLocked(int flags) {
+
+ if ((flags & FLAG_AUGMENTED_AUTOFILL_REQUEST) != 0) {
+ // TODO(b/122858578): log metrics
+ if (sVerbose) {
+ Slog.v(TAG, "requestNewFillResponse(): triggering augmented autofill instead");
+ }
+ triggerAugmentedAutofillLocked();
+ return;
+ }
+
int requestId;
do {
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index d5713a1..a8fd59a 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -52,6 +52,7 @@
import android.view.contentcapture.UserDataRemovalRequest;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AbstractRemoteService;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
@@ -103,11 +104,12 @@
private boolean mDisabledByDeviceConfig;
// Device-config settings that are cached and passed back to apps
- public int mDevCfgLoggingLevel;
- public int mDevCfgMaxBufferSize;
- public int mDevCfgIdleFlushingFrequencyMs;
- public int mDevCfgTextChangeFlushingFrequencyMs;
- public int mDevCfgLogHistorySize;
+ int mDevCfgLoggingLevel;
+ int mDevCfgMaxBufferSize;
+ int mDevCfgIdleFlushingFrequencyMs;
+ int mDevCfgTextChangeFlushingFrequencyMs;
+ int mDevCfgLogHistorySize;
+ int mDevCfgIdleUnbindTimeoutMs;
public ContentCaptureManagerService(@NonNull Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
@@ -238,6 +240,7 @@
case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY:
case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE:
case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY:
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT:
setFineTuneParamsFromDeviceConfig();
return;
default:
@@ -257,11 +260,15 @@
ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS);
mDevCfgLogHistorySize = ContentCaptureHelper.getIntDeviceConfigProperty(
ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE, 20);
+ mDevCfgIdleUnbindTimeoutMs = ContentCaptureHelper.getIntDeviceConfigProperty(
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT,
+ (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS);
if (verbose) {
Slog.v(mTag, "setFineTuneParamsFromDeviceConfig(): bufferSize=" + mDevCfgMaxBufferSize
+ ", idleFlush=" + mDevCfgIdleFlushingFrequencyMs
+ ", textFluxh=" + mDevCfgTextChangeFlushingFrequencyMs
- + ", logHistory=" + mDevCfgLogHistorySize);
+ + ", logHistory=" + mDevCfgLogHistorySize
+ + ", idleUnbindTimeoutMs=" + mDevCfgIdleUnbindTimeoutMs);
}
}
@@ -472,6 +479,8 @@
pw.print(prefix2); pw.print("textChangeFlushingFrequencyMs: ");
pw.println(mDevCfgTextChangeFlushingFrequencyMs);
pw.print(prefix2); pw.print("logHistorySize: "); pw.println(mDevCfgLogHistorySize);
+ pw.print(prefix2); pw.print("idleUnbindTimeoutMs: ");
+ pw.println(mDevCfgIdleUnbindTimeoutMs);
}
final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 5b48046..b33259d 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -126,7 +126,7 @@
mRemoteService = new RemoteContentCaptureService(mMaster.getContext(),
ContentCaptureService.SERVICE_INTERFACE, serviceComponentName,
mRemoteServiceCallback, mUserId, this, mMaster.isBindInstantServiceAllowed(),
- mMaster.verbose);
+ mMaster.verbose, mMaster.mDevCfgIdleUnbindTimeoutMs);
}
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index f9fda64..dc07c0a 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -38,14 +38,16 @@
IContentCaptureService> {
private final IBinder mServerCallback;
+ private final int mIdleUnbindTimeoutMs;
RemoteContentCaptureService(Context context, String serviceInterface,
ComponentName serviceComponentName, IContentCaptureServiceCallback callback, int userId,
ContentCaptureServiceCallbacks callbacks, boolean bindInstantServiceAllowed,
- boolean verbose) {
+ boolean verbose, int idleUnbindTimeoutMs) {
super(context, serviceInterface, serviceComponentName, userId, callbacks,
bindInstantServiceAllowed, verbose, /* initialCapacity= */ 2);
mServerCallback = callback.asBinder();
+ mIdleUnbindTimeoutMs = idleUnbindTimeoutMs;
// Bind right away, which will trigger a onConnected() on service's
scheduleBind();
@@ -58,8 +60,7 @@
@Override // from AbstractRemoteService
protected long getTimeoutIdleBindMillis() {
- // TODO(b/111276913): read from Settings so it can be changed in the field
- return PERMANENT_BOUND_TIMEOUT_MS;
+ return mIdleUnbindTimeoutMs;
}
@Override // from RemoteService
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index ed459db..c37a805 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2375,6 +2375,11 @@
pw.decreaseIndent();
}
+
+ pw.println();
+ pw.println("NetworkStackClient logs:");
+ pw.increaseIndent();
+ NetworkStackClient.getInstance().dump(pw);
}
private void dumpNetworks(IndentingPrintWriter pw) {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 5989a46..d8b96e4 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1972,7 +1972,7 @@
continue;
}
- // requests that ignore location settings will never provider notifications
+ // requests that ignore location settings will never provide notifications
if (isSettingsExemptLocked(record)) {
continue;
}
@@ -2010,19 +2010,22 @@
WorkSource worksource = new WorkSource();
ProviderRequest providerRequest = new ProviderRequest();
- long backgroundThrottleInterval;
-
- long identity = Binder.clearCallingIdentity();
- try {
- backgroundThrottleInterval = Settings.Global.getLong(
- mContext.getContentResolver(),
- Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
- DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
if (records != null && !records.isEmpty()) {
+ long backgroundThrottleInterval;
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ backgroundThrottleInterval = Settings.Global.getLong(
+ mContext.getContentResolver(),
+ Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
+ DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ final boolean isForegroundOnlyMode =
+ mPowerManager.getLocationPowerSaveMode()
+ == PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
// initialize the low power mode to true and set to false if any of the records requires
providerRequest.lowPowerMode = true;
for (UpdateRecord record : records) {
@@ -2037,7 +2040,9 @@
record.mReceiver.mAllowedResolutionLevel)) {
continue;
}
- if (!provider.isUseableLocked()) {
+ final boolean isBatterySaverDisablingLocation =
+ isForegroundOnlyMode && !record.mIsForegroundUid;
+ if (!provider.isUseableLocked() || isBatterySaverDisablingLocation) {
if (isSettingsExemptLocked(record)) {
providerRequest.locationSettingsIgnored = true;
providerRequest.lowPowerMode = false;
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 526aebe..097a7d6 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -42,6 +42,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.MediaStore;
@@ -235,9 +236,17 @@
* Handler for on start pinning message
*/
private void handlePinOnStart() {
- // Files to pin come from the overlay and can be specified per-device config
- String[] filesToPin = mContext.getResources().getStringArray(
- com.android.internal.R.array.config_defaultPinnerServiceFiles);
+ final String bootImage = SystemProperties.get("dalvik.vm.boot-image", "");
+ String[] filesToPin = null;
+ if (bootImage.endsWith("apex.art")) {
+ // Use the files listed for that specific boot image
+ filesToPin = mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_apexBootImagePinnerServiceFiles);
+ } else {
+ // Files to pin come from the overlay and can be specified per-device config
+ filesToPin = mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_defaultPinnerServiceFiles);
+ }
// Continue trying to pin each file even if we fail to pin some of them
for (String fileToPin : filesToPin) {
PinnedFile pf = pinFile(fileToPin,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 375c5c4..8f45df1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17110,6 +17110,13 @@
}
@Override
+ public boolean startUserInForegroundWithListener(final int userId,
+ @Nullable IProgressListener unlockListener) {
+ // Permission check done inside UserController.
+ return mUserController.startUser(userId, /* foreground */ true, unlockListener);
+ }
+
+ @Override
public boolean unlockUser(int userId, byte[] token, byte[] secret, IProgressListener listener) {
return mUserController.unlockUser(userId, token, secret, listener);
}
diff --git a/services/core/java/com/android/server/biometrics/ClientMonitor.java b/services/core/java/com/android/server/biometrics/ClientMonitor.java
index e80b39b..89fa2de 100644
--- a/services/core/java/com/android/server/biometrics/ClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/ClientMonitor.java
@@ -209,11 +209,7 @@
public void binderDied() {
// If the current client dies we should cancel the current operation.
Slog.e(getLogTag(), "Binder died, cancelling client");
- try {
- getDaemonWrapper().cancel();
- } catch (RemoteException e) {
- Slog.e(getLogTag(), "Remote exception", e);
- }
+ stop(false /* initiatedByClient */);
mToken = null;
mListener = null;
}
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 420b23e..d84a4d2 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -19,10 +19,11 @@
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.INTERNET;
import static android.Manifest.permission.NETWORK_STACK;
-import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
-import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
@@ -32,23 +33,31 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
-import android.net.Uri;
+import android.net.INetd;
+import android.net.util.NetdService;
import android.os.Build;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
+import android.util.Slog;
+import android.util.SparseIntArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.LocalServices;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map.Entry;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
/**
@@ -75,6 +84,59 @@
// Keys are App IDs. Values are true for SYSTEM permission and false for NETWORK permission.
private final Map<Integer, Boolean> mApps = new HashMap<>();
+ // Keys are App packageNames, Values are app uids. . We need to keep track of this information
+ // because PackageListObserver#onPackageRemoved does not pass the UID.
+ @GuardedBy("mPackageNameUidMap")
+ private final Map<String, Integer> mPackageNameUidMap = new HashMap<>();
+
+ private class PackageListObserver implements PackageManagerInternal.PackageListObserver {
+ @Override
+ public void onPackageAdded(String packageName) {
+ final PackageInfo app = getPackageInfo(packageName);
+ if (app == null) {
+ Slog.wtf(TAG, "Failed to get information of installed package: " + packageName);
+ return;
+ }
+ int uid = (app.applicationInfo != null) ? app.applicationInfo.uid : INVALID_UID;
+ if (uid == INVALID_UID) {
+ Slog.wtf(TAG, "Failed to get the uid of installed package: " + packageName
+ + "uid: " + uid);
+ return;
+ }
+ if (app.requestedPermissions == null) {
+ return;
+ }
+ sendPackagePermissionsForUid(uid,
+ filterPermission(Arrays.asList(app.requestedPermissions)));
+ synchronized (mPackageNameUidMap) {
+ mPackageNameUidMap.put(packageName, uid);
+ }
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName) {
+ int uid;
+ synchronized (mPackageNameUidMap) {
+ if (!mPackageNameUidMap.containsKey(packageName)) {
+ return;
+ }
+ uid = mPackageNameUidMap.get(packageName);
+ mPackageNameUidMap.remove(packageName);
+ }
+ int permission = 0;
+ String[] packages = mPackageManager.getPackagesForUid(uid);
+ if (packages != null && packages.length > 0) {
+ for (String name : packages) {
+ final PackageInfo app = getPackageInfo(name);
+ if (app != null && app.requestedPermissions != null) {
+ permission |= filterPermission(Arrays.asList(app.requestedPermissions));
+ }
+ }
+ }
+ sendPackagePermissionsForUid(uid, permission);
+ }
+ }
+
public PermissionMonitor(Context context, INetworkManagementService netd) {
mContext = context;
mPackageManager = context.getPackageManager();
@@ -87,12 +149,21 @@
public synchronized void startMonitoring() {
log("Monitoring");
- List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS);
+ PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ if (pmi != null) {
+ pmi.getPackageList(new PackageListObserver());
+ } else {
+ loge("failed to get the PackageManagerInternal service");
+ }
+ List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
+ | MATCH_ANY_USER);
if (apps == null) {
loge("No apps");
return;
}
+ SparseIntArray netdPermsUids = new SparseIntArray();
+
for (PackageInfo app : apps) {
int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
if (uid < 0) {
@@ -110,6 +181,17 @@
mApps.put(uid, hasRestrictedPermission);
}
}
+
+ //TODO: unify the management of the permissions into one codepath.
+ if (app.requestedPermissions != null) {
+ int otherNetdPerms = filterPermission(Arrays.asList(app.requestedPermissions));
+ if (otherNetdPerms != 0) {
+ netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
+ synchronized (mPackageNameUidMap) {
+ mPackageNameUidMap.put(app.applicationInfo.packageName, uid);
+ }
+ }
+ }
}
List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users
@@ -121,6 +203,7 @@
log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
update(mUsers, mApps, true);
+ sendPackagePermissionsToNetd(netdPermsUids);
}
@VisibleForTesting
@@ -339,6 +422,107 @@
}
}
+ private static int filterPermission(List<String> requestedPermissions) {
+ int permissions = 0;
+ if (requestedPermissions.contains(INTERNET)) {
+ permissions |= INetd.PERMISSION_INTERNET;
+ }
+ if (requestedPermissions.contains(UPDATE_DEVICE_STATS)) {
+ permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
+ }
+ return permissions;
+ }
+
+ private PackageInfo getPackageInfo(String packageName) {
+ try {
+ PackageInfo app = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS
+ | MATCH_ANY_USER);
+ return app;
+ } catch (NameNotFoundException e) {
+ // App not found.
+ loge("NameNotFoundException " + packageName);
+ return null;
+ }
+ }
+
+ /**
+ * Called by PackageListObserver when a package is installed/uninstalled. Send the updated
+ * permission information to netd.
+ *
+ * @param uid the app uid of the package installed
+ * @param permissions the permissions the app requested and netd cares about.
+ *
+ * @hide
+ */
+ private void sendPackagePermissionsForUid(int uid, int permissions) {
+ SparseIntArray netdPermissionsAppIds = new SparseIntArray();
+ netdPermissionsAppIds.put(uid, permissions);
+ sendPackagePermissionsToNetd(netdPermissionsAppIds);
+ }
+
+ /**
+ * Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET
+ * and/or UPDATE_DEVICE_STATS permission of the uids in array.
+ *
+ * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the
+ * permission is 0, revoke all permissions of that uid.
+ *
+ * @hide
+ */
+ private void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
+ INetd netdService = NetdService.getInstance();
+ if (netdService == null) {
+ Log.e(TAG, "Failed to get the netd service");
+ return;
+ }
+ ArrayList<Integer> allPermissionAppIds = new ArrayList<>();
+ ArrayList<Integer> internetPermissionAppIds = new ArrayList<>();
+ ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
+ ArrayList<Integer> uninstalledAppIds = new ArrayList<>();
+ for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
+ int permissions = netdPermissionsAppIds.valueAt(i);
+ switch(permissions) {
+ case (INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS):
+ allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ case INetd.PERMISSION_INTERNET:
+ internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ case INetd.PERMISSION_UPDATE_DEVICE_STATS:
+ updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ case INetd.NO_PERMISSIONS:
+ uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ default:
+ Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
+ + netdPermissionsAppIds.keyAt(i));
+ }
+ }
+ try {
+ // TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
+ if (allPermissionAppIds.size() != 0) {
+ netdService.trafficSetNetPermForUids(
+ INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ ArrayUtils.convertToIntArray(allPermissionAppIds));
+ }
+ if (internetPermissionAppIds.size() != 0) {
+ netdService.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
+ ArrayUtils.convertToIntArray(internetPermissionAppIds));
+ }
+ if (updateStatsPermissionAppIds.size() != 0) {
+ netdService.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
+ }
+ if (uninstalledAppIds.size() != 0) {
+ netdService.trafficSetNetPermForUids(INetd.NO_PERMISSIONS,
+ ArrayUtils.convertToIntArray(uninstalledAppIds));
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Pass appId list of special permission failed." + e);
+ }
+ }
+
private static void log(String s) {
if (DBG) {
Log.d(TAG, s);
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index bfa7f9d..4e4b15f 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.accounts.Account;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
@@ -1174,6 +1175,7 @@
}
@Override
+ @RequiresPermission(android.Manifest.permission.CACHE_CONTENT)
public void putCache(String packageName, Uri key, Bundle value, int userId) {
Bundle.setDefusable(value, true);
enforceCrossUserPermission(userId, TAG);
@@ -1196,6 +1198,7 @@
}
@Override
+ @RequiresPermission(android.Manifest.permission.CACHE_CONTENT)
public Bundle getCache(String packageName, Uri key, int userId) {
enforceCrossUserPermission(userId, TAG);
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index b020997..01d19c0 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -37,7 +37,9 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
import android.graphics.Point;
+import android.graphics.Rect;
import android.hardware.SensorManager;
import android.hardware.display.AmbientBrightnessDayStats;
import android.hardware.display.BrightnessChangeEvent;
@@ -1277,7 +1279,14 @@
if (token == null) {
return false;
}
- SurfaceControl.screenshot(token, outSurface);
+ final GraphicBuffer gb = SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(
+ token, new Rect(), 0 /* width */, 0 /* height */, false /* useIdentityTransform */,
+ 0 /* rotation */);
+ try {
+ outSurface.attachAndQueueBuffer(gb);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failed to take screenshot - " + e.getMessage());
+ }
return true;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 6710986..6a4ccf2 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -248,12 +248,8 @@
}
if (mService.getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) {
mCecMessageCache.flushAll();
- } else {
- if (connected) {
- launchDeviceDiscovery();
- } else {
- // TODO(amyjojo): remove device from mDeviceInfo
- }
+ } else if (!connected){
+ // TODO(amyjojo): remove device from mDeviceInfo
}
}
@@ -996,6 +992,17 @@
}
// Wake up device
mService.wakeUp();
+ // If Audio device is the active source or is on the active path,
+ // enable system audio mode without querying TV's support on sam.
+ // This is per HDMI spec 1.4b CEC 13.15.4.2.
+ if (mService.pathToPortId(getActiveSource().physicalAddress)
+ != Constants.INVALID_PORT_ID) {
+ setSystemAudioMode(true);
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildSetSystemAudioMode(
+ mAddress, Constants.ADDR_BROADCAST, true));
+ return;
+ }
// Check if TV supports System Audio Control.
// Handle broadcasting setSystemAudioMode on or aborting message on callback.
queryTvSystemAudioModeSupport(new TvSystemAudioModeSupportedCallback() {
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 2bfb31f..d2ccfcc 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -133,7 +133,8 @@
* {@link com.android.internal.infra.AbstractRemoteService} instances, or
* {@code null} when the service doesn't bind to remote services.
* @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that
- * disables the service.
+ * disables the service. <b>NOTE: </b> you'll also need to add it to
+ * {@code UserRestrictionsUtils.USER_RESTRICTIONS}.
*/
protected AbstractMasterSystemService(@NonNull Context context,
@Nullable ServiceNameResolver serviceNameResolver,
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 243b6fe..28fdd95 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -527,6 +527,7 @@
mPowerManager.getPowerSaveState(ServiceType.LOCATION);
switch (result.locationMode) {
case PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
+ case PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF:
// If we are in battery saver mode and the screen is off, disable GPS.
disableGps |= result.batterySaverEnabled && !mPowerManager.isInteractive();
break;
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 1dada92..f4454ae 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -146,8 +146,8 @@
if (isDumpstateBinderServiceRunningLocked()) {
Slog.w(TAG, "'dumpstate' is already running. Cannot start a new bugreport"
+ " while another one is currently in progress.");
- // TODO(b/111441001): Use a new error code; add this to the documentation of the API.
- reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
+ reportError(listener,
+ IDumpstateListener.BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS);
return;
}
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index dc990af..4dd58e0 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -30,6 +30,7 @@
import android.os.ServiceManager.ServiceNotFoundException;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import java.io.File;
@@ -48,7 +49,9 @@
class ApexManager {
static final String TAG = "ApexManager";
private final IApexService mApexService;
- private final Map<String, PackageInfo> mActivePackagesCache;
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private Map<String, PackageInfo> mActivePackagesCache;
ApexManager() {
try {
@@ -57,31 +60,35 @@
} catch (ServiceNotFoundException e) {
throw new IllegalStateException("Required service apexservice not available");
}
- mActivePackagesCache = populateActivePackagesCache();
}
- @NonNull
- private Map<String, PackageInfo> populateActivePackagesCache() {
- try {
- List<PackageInfo> list = new ArrayList<>();
- final ApexInfo[] activePkgs = mApexService.getActivePackages();
- for (ApexInfo ai : activePkgs) {
- // If the device is using flattened APEX, don't report any APEX
- // packages since they won't be managed or updated by PackageManager.
- if ((new File(ai.packagePath)).isDirectory()) {
- break;
- }
- try {
- list.add(PackageParser.generatePackageInfoFromApex(
- new File(ai.packagePath), true /* collect certs */));
- } catch (PackageParserException pe) {
- throw new IllegalStateException("Unable to parse: " + ai, pe);
- }
+ private void populateActivePackagesCacheIfNeeded() {
+ synchronized (mLock) {
+ if (mActivePackagesCache != null) {
+ return;
}
- return list.stream().collect(Collectors.toMap(p -> p.packageName, Function.identity()));
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
- throw new RuntimeException(re);
+ try {
+ List<PackageInfo> list = new ArrayList<>();
+ final ApexInfo[] activePkgs = mApexService.getActivePackages();
+ for (ApexInfo ai : activePkgs) {
+ // If the device is using flattened APEX, don't report any APEX
+ // packages since they won't be managed or updated by PackageManager.
+ if ((new File(ai.packagePath)).isDirectory()) {
+ break;
+ }
+ try {
+ list.add(PackageParser.generatePackageInfoFromApex(
+ new File(ai.packagePath), true /* collect certs */));
+ } catch (PackageParserException pe) {
+ throw new IllegalStateException("Unable to parse: " + ai, pe);
+ }
+ }
+ mActivePackagesCache = list.stream().collect(
+ Collectors.toMap(p -> p.packageName, Function.identity()));
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
+ throw new RuntimeException(re);
+ }
}
}
@@ -96,6 +103,7 @@
* is not found.
*/
@Nullable PackageInfo getActivePackage(String packageName) {
+ populateActivePackagesCacheIfNeeded();
return mActivePackagesCache.get(packageName);
}
@@ -106,6 +114,7 @@
* active package.
*/
Collection<PackageInfo> getActivePackages() {
+ populateActivePackagesCacheIfNeeded();
return mActivePackagesCache.values();
}
@@ -205,6 +214,21 @@
}
/**
+ * Abandons the (only) active session previously submitted.
+ *
+ * @return {@code true} upon success, {@code false} if any remote exception occurs
+ */
+ boolean abortActiveSession() {
+ try {
+ mApexService.abortActiveSession();
+ return true;
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to contact apexservice", re);
+ return false;
+ }
+ }
+
+ /**
* Dumps various state information to the provided {@link PrintWriter} object.
*
* @param pw the {@link PrintWriter} object to send information to.
@@ -217,7 +241,7 @@
ipw.println("Active APEX packages:");
ipw.increaseIndent();
try {
- populateActivePackagesCache();
+ populateActivePackagesCacheIfNeeded();
for (PackageInfo pi : mActivePackagesCache.values()) {
if (packageName != null && !packageName.equals(pi.packageName)) {
continue;
@@ -254,4 +278,8 @@
ipw.println("Couldn't communicate with apexd.");
}
}
+
+ public void onBootCompleted() {
+ populateActivePackagesCacheIfNeeded();
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index d501c4f..cced0f4 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -209,8 +209,10 @@
mStagingManager = new StagingManager(pm, this, am);
}
- private void setBootCompleted() {
+ private void onBootCompleted() {
mBootCompleted = true;
+ // Tell APEX manager about it as well
+ mApexManager.onBootCompleted();
}
boolean isBootCompleted() {
@@ -223,7 +225,7 @@
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- setBootCompleted();
+ onBootCompleted();
mContext.unregisterReceiver(this);
}
}, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 31eb324..7ed49fc 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -490,9 +490,9 @@
if (info.childSessionIds == null) {
info.childSessionIds = EMPTY_CHILD_SESSION_ARRAY;
}
- info.isSessionApplied = mStagedSessionApplied;
- info.isSessionReady = mStagedSessionReady;
- info.isSessionFailed = mStagedSessionFailed;
+ info.isStagedSessionApplied = mStagedSessionApplied;
+ info.isStagedSessionReady = mStagedSessionReady;
+ info.isStagedSessionFailed = mStagedSessionFailed;
info.setStagedSessionErrorCode(mStagedSessionErrorCode, mStagedSessionErrorMessage);
}
return info;
@@ -1867,6 +1867,15 @@
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked();
+ if (mCommitted && params.isStaged) {
+ synchronized (mLock) {
+ mDestroyed = true;
+ }
+ mStagingManager.abortCommittedSession(this);
+
+ //TODO(b/123624108): delete staging dir
+ }
+
if (mRelinquished) {
Slog.d(TAG, "Ignoring abandon after commit relinquished control");
return;
@@ -2029,6 +2038,7 @@
mStagedSessionErrorMessage = errorMessage;
Slog.d(TAG, "Marking session " + sessionId + " as failed: " + errorMessage);
}
+ cleanStageDir();
mCallback.onStagedSessionChanged(this);
}
@@ -2040,7 +2050,9 @@
mStagedSessionFailed = false;
mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
mStagedSessionErrorMessage = "";
+ Slog.d(TAG, "Marking session " + sessionId + " as applied");
}
+ cleanStageDir();
mCallback.onStagedSessionChanged(this);
}
@@ -2095,6 +2107,19 @@
}
}
+ private void cleanStageDir() {
+ if (isMultiPackage()) {
+ for (int childSessionId : getChildSessionIds()) {
+ mSessionProvider.getSession(childSessionId).cleanStageDir();
+ }
+ } else {
+ try {
+ mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
+ } catch (InstallerException ignored) {
+ }
+ }
+ }
+
void dump(IndentingPrintWriter pw) {
synchronized (mLock) {
dumpLocked(pw);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 5216967..114810d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -300,9 +300,9 @@
pw.println("appPackageName = " + session.getAppPackageName()
+ "; sessionId = " + session.getSessionId()
+ "; isStaged = " + session.isStaged()
- + "; isSessionReady = " + session.isSessionReady()
- + "; isSessionApplied = " + session.isSessionApplied()
- + "; isSessionFailed = " + session.isSessionFailed() + ";");
+ + "; isStagedSessionReady = " + session.isStagedSessionReady()
+ + "; isStagedSessionApplied = " + session.isStagedSessionApplied()
+ + "; isStagedSessionFailed = " + session.isStagedSessionFailed() + ";");
}
} catch (RemoteException e) {
pw.println("Failure ["
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index ff6d7a8..9deea9e 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2173,7 +2173,8 @@
public boolean hasShareTargets(String packageName, String packageToCheck,
@UserIdInt int userId) {
verifyCaller(packageName, userId);
- enforceSystem();
+ enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS,
+ "hasShareTargets");
synchronized (mLock) {
throwIfUserLockedL(userId);
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index a38c836..e956b74 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -445,11 +445,32 @@
void abortSession(@NonNull PackageInstallerSession session) {
synchronized (mStagedSessions) {
- updateStoredSession(session);
mStagedSessions.remove(session.sessionId);
}
}
+ void abortCommittedSession(@NonNull PackageInstallerSession session) {
+ if (session.isStagedSessionApplied()) {
+ Slog.w(TAG, "Cannot abort applied session!");
+ return;
+ }
+ if (isStagedSessionFinalized(session.sessionId)) {
+ Slog.w(TAG, "Cannot abort session because it is not active or APEXD is not reachable");
+ return;
+ }
+
+ mApexManager.abortActiveSession();
+
+ abortSession(session);
+ }
+
+ private boolean isStagedSessionFinalized(int sessionId) {
+ ApexSessionInfo session = mApexManager.getStagedSessionInfo(sessionId);
+
+ /* checking if the session is in a final state, i.e., not active anymore */
+ return session.isUnknown || session.isActivationFailed || session.isSuccess;
+ }
+
@GuardedBy("mStagedSessions")
private boolean isMultiPackageSessionComplete(@NonNull PackageInstallerSession session) {
// This method assumes that the argument is either a parent session of a multi-package
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 93a3d0a..447234e 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -850,7 +850,7 @@
}
for (String packageName : packageNames) {
grantPermissionsToSystemPackage(packageName, userId,
- PHONE_PERMISSIONS, LOCATION_PERMISSIONS, SMS_PERMISSIONS);
+ PHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS, SMS_PERMISSIONS);
}
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 11839a5..d2c0ee3 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -528,7 +528,7 @@
PackageInstaller.SessionInfo session = installer.getSessionInfo(
data.stagedSessionId);
if (session != null) {
- if (session.isSessionApplied()) {
+ if (session.isStagedSessionApplied()) {
synchronized (mLock) {
data.isAvailable = true;
}
@@ -538,7 +538,7 @@
Log.e(TAG, "Unable to save rollback info for : "
+ data.rollbackId, ioe);
}
- } else if (session.isSessionFailed()) {
+ } else if (session.isStagedSessionFailed()) {
// TODO: Do we need to remove this from
// mAvailableRollbacks, or is it okay to leave as
// unavailable until the next reboot when it will go
@@ -1195,13 +1195,13 @@
}
if (pi.isStaged()) {
- if (!pi.isSessionFailed()) {
+ if (!pi.isStagedSessionFailed()) {
// TODO: The session really isn't "enabled" at this point, since more work might
// be required post reboot.
// TODO: We need to make this case consistent with the call from onFinished.
// Ideally, we'd call completeEnableRollback excatly once per multi-package session
// with the parentSessionId only.
- completeEnableRollback(pi.sessionId, pi.isSessionReady());
+ completeEnableRollback(pi.sessionId, pi.isStagedSessionReady());
} else {
// TODO: Clean up the saved rollback when the session fails. This may need to be
// unified with the case where things fail post reboot.
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 3a2b69f..d24f217 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -218,10 +218,10 @@
&& (sessionId != PackageInstaller.SessionInfo.INVALID_ID)) {
PackageInstaller.SessionInfo sessionInfo =
packageInstaller.getSessionInfo(sessionId);
- if (sessionInfo.isSessionReady()) {
+ if (sessionInfo.isStagedSessionReady()) {
mContext.unregisterReceiver(listener);
mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
- } else if (sessionInfo.isSessionFailed()) {
+ } else if (sessionInfo.isStagedSessionFailed()) {
mContext.unregisterReceiver(listener);
}
}
diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index 4b413e5..296a652 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -16,14 +16,13 @@
package com.android.server.timezone;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.EventLogTags;
-import com.android.server.SystemService;
-import com.android.timezone.distro.DistroException;
-import com.android.timezone.distro.DistroVersion;
-import com.android.timezone.distro.StagedDistroOperation;
-import com.android.timezone.distro.TimeZoneDistro;
-import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
+import static android.app.timezone.RulesState.DISTRO_STATUS_INSTALLED;
+import static android.app.timezone.RulesState.DISTRO_STATUS_NONE;
+import static android.app.timezone.RulesState.DISTRO_STATUS_UNKNOWN;
+import static android.app.timezone.RulesState.STAGED_OPERATION_INSTALL;
+import static android.app.timezone.RulesState.STAGED_OPERATION_NONE;
+import static android.app.timezone.RulesState.STAGED_OPERATION_UNINSTALL;
+import static android.app.timezone.RulesState.STAGED_OPERATION_UNKNOWN;
import android.app.timezone.Callback;
import android.app.timezone.DistroFormatVersion;
@@ -37,6 +36,21 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.EventLogTags;
+import com.android.server.SystemService;
+import com.android.timezone.distro.DistroException;
+import com.android.timezone.distro.DistroVersion;
+import com.android.timezone.distro.StagedDistroOperation;
+import com.android.timezone.distro.TimeZoneDistro;
+import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
+
+import libcore.icu.ICU;
+import libcore.timezone.TimeZoneDataFiles;
+import libcore.timezone.TimeZoneFinder;
+import libcore.timezone.TzDataSetVersion;
+import libcore.timezone.ZoneInfoDB;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -46,18 +60,6 @@
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
-import libcore.icu.ICU;
-import libcore.timezone.TzDataSetVersion;
-import libcore.timezone.TimeZoneFinder;
-import libcore.timezone.ZoneInfoDB;
-
-import static android.app.timezone.RulesState.DISTRO_STATUS_INSTALLED;
-import static android.app.timezone.RulesState.DISTRO_STATUS_NONE;
-import static android.app.timezone.RulesState.DISTRO_STATUS_UNKNOWN;
-import static android.app.timezone.RulesState.STAGED_OPERATION_INSTALL;
-import static android.app.timezone.RulesState.STAGED_OPERATION_NONE;
-import static android.app.timezone.RulesState.STAGED_OPERATION_UNINSTALL;
-import static android.app.timezone.RulesState.STAGED_OPERATION_UNKNOWN;
public final class RulesManagerService extends IRulesManager.Stub {
@@ -96,8 +98,6 @@
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
static final String REQUIRED_QUERY_PERMISSION =
android.Manifest.permission.QUERY_TIME_ZONE_RULES;
- private static final File SYSTEM_TZ_DATA_FILE = new File("/system/usr/share/zoneinfo/tzdata");
- private static final File TZ_DATA_DIR = new File("/data/misc/zoneinfo");
private final AtomicBoolean mOperationInProgress = new AtomicBoolean(false);
private final PermissionHelper mPermissionHelper;
@@ -108,12 +108,14 @@
private static RulesManagerService create(Context context) {
RulesManagerServiceHelperImpl helper = new RulesManagerServiceHelperImpl(context);
+ File baseVersionFile = new File(TimeZoneDataFiles.getRuntimeModuleTzVersionFile());
+ File tzDataDir = new File(TimeZoneDataFiles.getDataTimeZoneRootDir());
return new RulesManagerService(
helper /* permissionHelper */,
helper /* executor */,
helper /* intentHelper */,
PackageTracker.create(context),
- new TimeZoneDistroInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR));
+ new TimeZoneDistroInstaller(TAG, baseVersionFile, tzDataDir));
}
// A constructor that can be used by tests to supply mocked / faked dependencies.
@@ -143,11 +145,11 @@
/** Like {@link #getRulesState()} without the permission check. */
private RulesState getRulesStateInternal() {
synchronized(this) {
- String systemRulesVersion;
+ TzDataSetVersion baseVersion;
try {
- systemRulesVersion = mInstaller.getSystemRulesVersion();
+ baseVersion = mInstaller.readBaseVersion();
} catch (IOException e) {
- Slog.w(TAG, "Failed to read system rules", e);
+ Slog.w(TAG, "Failed to read base rules version", e);
return null;
}
@@ -196,7 +198,7 @@
Slog.w(TAG, "Failed to read staged distro.", e);
}
}
- return new RulesState(systemRulesVersion, DISTRO_FORMAT_VERSION_SUPPORTED,
+ return new RulesState(baseVersion.rulesVersion, DISTRO_FORMAT_VERSION_SUPPORTED,
operationInProgress, stagedOperationStatus, stagedDistroRulesVersion,
distroStatus, installedDistroRulesVersion);
}
@@ -454,13 +456,13 @@
pw.println("Operation in progress: " + value);
break;
}
- case 's': {
- // Report system image rules version
+ case 'b': {
+ // Report base rules version
String value = "Unknown";
if (rulesState != null) {
- value = rulesState.getSystemRulesVersion();
+ value = rulesState.getBaseRulesVersion();
}
- pw.println("System rules version: " + value);
+ pw.println("Base rules version: " + value);
break;
}
case 'c': {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 91d573d..f3f507f 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -3271,7 +3271,12 @@
}
final WindowState w = mTopFullscreenOpaqueWindowState;
- if (w != mFocusedWindow) {
+ if (w == null || w != mFocusedWindow) {
+ return false;
+ }
+ // If the bounds of activity window is different from its parent, then reject to be seamless
+ // because the window position may change after rotation that will look like a sudden jump.
+ if (w.mAppToken != null && !w.mAppToken.matchParentBounds()) {
return false;
}
@@ -3279,8 +3284,7 @@
// it and is in the fullscreen opaque state. Seamless rotation
// requires freezing various Surface states and won't work well
// with animations, so we disable it in the animation case for now.
- if (w != null && !w.isAnimatingLw()
- && w.getAttrs().rotationAnimation == ROTATION_ANIMATION_SEAMLESS) {
+ if (!w.isAnimatingLw() && w.getAttrs().rotationAnimation == ROTATION_ANIMATION_SEAMLESS) {
return true;
}
return false;
diff --git a/services/core/java/com/android/server/wm/WindowTraceBuffer.java b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
index 2ce6e6c..a4ee907 100644
--- a/services/core/java/com/android/server/wm/WindowTraceBuffer.java
+++ b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
@@ -98,9 +98,8 @@
ProtoOutputStream proto = new ProtoOutputStream();
proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
os.write(proto.getBytes());
- while (!mBuffer.isEmpty()) {
- proto = mBuffer.poll();
- mBufferUsedSize -= proto.getRawSize();
+ for (ProtoOutputStream protoOutputStream : mBuffer) {
+ proto = protoOutputStream;
byte[] protoBytes = proto.getBytes();
os.write(protoBytes);
}
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index 1eb7b98..830dbbe 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -30,6 +30,7 @@
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServerCallbacks;
import android.net.ip.IIpClientCallbacks;
+import android.net.util.SharedLog;
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
@@ -40,6 +41,7 @@
import com.android.internal.annotations.GuardedBy;
+import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
@@ -61,6 +63,9 @@
@GuardedBy("mPendingNetStackRequests")
private INetworkStackConnector mConnector;
+ @GuardedBy("mLog")
+ private final SharedLog mLog = new SharedLog(TAG);
+
private volatile boolean mNetworkStackStartRequested = false;
private interface NetworkStackCallback {
@@ -129,13 +134,14 @@
private class NetworkStackConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
+ log("Network stack service connected");
registerNetworkStackService(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO: crash/reboot the system ?
- Slog.wtf(TAG, "Lost network stack connector");
+ logWtf("Lost network stack connector", null);
}
};
@@ -144,6 +150,7 @@
ServiceManager.addService(Context.NETWORK_STACK_SERVICE, service, false /* allowIsolated */,
DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
+ log("Network stack service registered");
final ArrayList<NetworkStackCallback> requests;
synchronized (mPendingNetStackRequests) {
@@ -166,6 +173,7 @@
* started.
*/
public void start(Context context) {
+ log("Starting network stack");
mNetworkStackStartRequested = true;
// Try to bind in-process if the library is available
IBinder connector = null;
@@ -177,7 +185,7 @@
connector = (IBinder) service.getMethod("makeConnector", Context.class)
.invoke(null, context);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
- Slog.wtf(TAG, "Could not create network stack connector from NetworkStackService");
+ logWtf("Could not create network stack connector from NetworkStackService", e);
// TODO: crash/reboot system here ?
return;
} catch (ClassNotFoundException e) {
@@ -186,26 +194,28 @@
// In-process network stack. Add the service to the service manager here.
if (connector != null) {
+ log("Registering in-process network stack connector");
registerNetworkStackService(connector);
return;
}
// Start the network stack process. The service will be added to the service manager in
// NetworkStackConnection.onServiceConnected().
+ log("Starting network stack process");
final Intent intent = new Intent(INetworkStackConnector.class.getName());
final ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null) {
- Slog.wtf(TAG, "Could not resolve the network stack with " + intent);
+ logWtf("Could not resolve the network stack with " + intent, null);
// TODO: crash/reboot system server ?
return;
}
final PackageManager pm = context.getPackageManager();
int uid = -1;
try {
- uid = pm.getPackageUid(comp.getPackageName(), UserHandle.USER_SYSTEM);
+ uid = pm.getPackageUidAsUser(comp.getPackageName(), UserHandle.USER_SYSTEM);
} catch (PackageManager.NameNotFoundException e) {
- Slog.wtf("Network stack package not found", e);
+ logWtf("Network stack package not found", e);
// Fall through
}
if (uid != Process.NETWORK_STACK_UID) {
@@ -221,10 +231,31 @@
if (!context.bindServiceAsUser(intent, new NetworkStackConnection(),
Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
- Slog.wtf(TAG,
- "Could not bind to network stack in-process, or in app with " + intent);
+ logWtf("Could not bind to network stack in-process, or in app with " + intent, null);
+ return;
// TODO: crash/reboot system server if no network stack after a timeout ?
}
+
+ log("Network stack service start requested");
+ }
+
+ private void log(@NonNull String message) {
+ synchronized (mLog) {
+ mLog.log(message);
+ }
+ }
+
+ private void logWtf(@NonNull String message, @Nullable Throwable e) {
+ Slog.wtf(TAG, message);
+ synchronized (mLog) {
+ mLog.e(message, e);
+ }
+ }
+
+ private void loge(@NonNull String message, @Nullable Throwable e) {
+ synchronized (mLog) {
+ mLog.e(message, e);
+ }
}
/**
@@ -243,12 +274,12 @@
while ((connector = ServiceManager.getService(Context.NETWORK_STACK_SERVICE)) == null) {
Thread.sleep(20);
if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
- Slog.e(TAG, "Timeout waiting for NetworkStack connector");
+ loge("Timeout waiting for NetworkStack connector", null);
return null;
}
}
} catch (InterruptedException e) {
- Slog.e(TAG, "Error waiting for NetworkStack connector", e);
+ loge("Error waiting for NetworkStack connector", e);
return null;
}
@@ -286,4 +317,20 @@
request.onNetworkStackConnected(connector);
}
+
+ /**
+ * Dump NetworkStackClient logs to the specified {@link PrintWriter}.
+ */
+ public void dump(PrintWriter pw) {
+ // dump is thread-safe on SharedLog
+ mLog.dump(null, pw, null);
+
+ final int requestsQueueLength;
+ synchronized (mPendingNetStackRequests) {
+ requestsQueueLength = mPendingNetStackRequests.size();
+ }
+
+ pw.println();
+ pw.println("pendingNetStackRequests length: " + requestsQueueLength);
+ }
}
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index 8e3023b..339607b 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -275,6 +275,9 @@
public void stop() {
closeSocket();
+ // Wake up mMulticastTransmitter thread to interrupt a potential 1 day sleep before
+ // the thread's termination.
+ maybeNotifyMulticastTransmitter();
mMulticastTransmitter = null;
mUnicastResponder = null;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 76beb8f..7e6b7da 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -6286,6 +6286,15 @@
mManager.getShareTargets(filter);
}
+ public void testHasShareTargets_permission() {
+ assertExpectException(SecurityException.class, "Missing permission", () ->
+ mManager.hasShareTargets(CALLING_PACKAGE_1));
+
+ // Has permission, now it should pass.
+ mCallerPermissions.add(permission.MANAGE_APP_PREDICTIONS);
+ mManager.hasShareTargets(CALLING_PACKAGE_1);
+ }
+
public void testDumpsys_crossProfile() {
prepareCrossProfileDataSet();
dumpsysOnLogcat("test1", /* force= */ true);
diff --git a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
index 1b106dd..5c6fe0f 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
@@ -16,34 +16,9 @@
package com.android.server.timezone;
-import com.android.timezone.distro.DistroVersion;
-import com.android.timezone.distro.StagedDistroOperation;
-import com.android.timezone.distro.TimeZoneDistro;
-import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import android.app.timezone.Callback;
-import android.app.timezone.DistroRulesVersion;
-import android.app.timezone.ICallback;
-import android.app.timezone.RulesManager;
-import android.app.timezone.RulesState;
-import android.os.ParcelFileDescriptor;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.concurrent.Executor;
-import javax.annotation.Nullable;
-
-import libcore.io.IoUtils;
-import libcore.timezone.TzDataSetVersion;
-
import static com.android.server.timezone.RulesManagerService.REQUIRED_QUERY_PERMISSION;
import static com.android.server.timezone.RulesManagerService.REQUIRED_UPDATER_PERMISSION;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -61,11 +36,43 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import android.app.timezone.Callback;
+import android.app.timezone.DistroRulesVersion;
+import android.app.timezone.ICallback;
+import android.app.timezone.RulesManager;
+import android.app.timezone.RulesState;
+import android.os.ParcelFileDescriptor;
+
+import com.android.timezone.distro.DistroVersion;
+import com.android.timezone.distro.StagedDistroOperation;
+import com.android.timezone.distro.TimeZoneDistro;
+import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
+
+import libcore.io.IoUtils;
+import libcore.timezone.TzDataSetVersion;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.concurrent.Executor;
+
+import javax.annotation.Nullable;
+
/**
* White box interaction / unit testing of the {@link RulesManagerService}.
*/
public class RulesManagerServiceTest {
+ private static final int CURRENT_FORMAT_MAJOR_VERSION =
+ TzDataSetVersion.currentFormatMajorVersion();
+ private static final int CURRENT_FORMAT_MINOR_VERSION =
+ TzDataSetVersion.currentFormatMinorVersion();
+
private RulesManagerService mRulesManagerService;
private FakeExecutor mFakeExecutor;
@@ -116,8 +123,8 @@
}
@Test
- public void getRulesState_systemRulesError() throws Exception {
- configureDeviceCannotReadSystemRulesVersion();
+ public void getRulesState_baseVersionError() throws Exception {
+ configureDeviceCannotReadBaseVersion();
assertNull(mRulesManagerService.getRulesState());
}
@@ -126,18 +133,18 @@
public void getRulesState_stagedInstall() throws Exception {
configureCallerHasPermission();
- configureDeviceSystemRulesVersion("2016a");
+ configureDeviceBaseVersion("2016a");
DistroVersion stagedDistroVersion = new DistroVersion(
- TzDataSetVersion.currentFormatMajorVersion(),
- TzDataSetVersion.currentFormatMinorVersion() - 1,
+ CURRENT_FORMAT_MAJOR_VERSION,
+ CURRENT_FORMAT_MINOR_VERSION - 1,
"2016c",
- 3);
+ 3 /* revision */);
configureStagedInstall(stagedDistroVersion);
DistroVersion installedDistroVersion = new DistroVersion(
- TzDataSetVersion.currentFormatMajorVersion(),
- TzDataSetVersion.currentFormatMinorVersion() - 1,
+ CURRENT_FORMAT_MAJOR_VERSION,
+ CURRENT_FORMAT_MINOR_VERSION - 1,
"2016b",
4);
configureInstalledDistroVersion(installedDistroVersion);
@@ -158,13 +165,13 @@
public void getRulesState_nothingStaged() throws Exception {
configureCallerHasPermission();
- configureDeviceSystemRulesVersion("2016a");
+ configureDeviceBaseVersion("2016a");
configureNoStagedOperation();
DistroVersion installedDistroVersion = new DistroVersion(
- TzDataSetVersion.currentFormatMajorVersion(),
- TzDataSetVersion.currentFormatMinorVersion() - 1,
+ CURRENT_FORMAT_MAJOR_VERSION,
+ CURRENT_FORMAT_MINOR_VERSION - 1,
"2016b",
4);
configureInstalledDistroVersion(installedDistroVersion);
@@ -183,13 +190,13 @@
public void getRulesState_uninstallStaged() throws Exception {
configureCallerHasPermission();
- configureDeviceSystemRulesVersion("2016a");
+ configureDeviceBaseVersion("2016a");
configureStagedUninstall();
DistroVersion installedDistroVersion = new DistroVersion(
- TzDataSetVersion.currentFormatMajorVersion(),
- TzDataSetVersion.currentFormatMinorVersion() - 1,
+ CURRENT_FORMAT_MAJOR_VERSION,
+ CURRENT_FORMAT_MINOR_VERSION - 1,
"2016b",
4);
configureInstalledDistroVersion(installedDistroVersion);
@@ -208,8 +215,8 @@
public void getRulesState_installedRulesError() throws Exception {
configureCallerHasPermission();
- String systemRulesVersion = "2016a";
- configureDeviceSystemRulesVersion(systemRulesVersion);
+ String baseRulesVersion = "2016a";
+ configureDeviceBaseVersion(baseRulesVersion);
configureStagedUninstall();
configureDeviceCannotReadInstalledDistroVersion();
@@ -226,14 +233,14 @@
public void getRulesState_stagedRulesError() throws Exception {
configureCallerHasPermission();
- String systemRulesVersion = "2016a";
- configureDeviceSystemRulesVersion(systemRulesVersion);
+ String baseRulesVersion = "2016a";
+ configureDeviceBaseVersion(baseRulesVersion);
configureDeviceCannotReadStagedDistroOperation();
DistroVersion installedDistroVersion = new DistroVersion(
- TzDataSetVersion.currentFormatMajorVersion(),
- TzDataSetVersion.currentFormatMinorVersion() - 1,
+ CURRENT_FORMAT_MAJOR_VERSION,
+ CURRENT_FORMAT_MINOR_VERSION - 1,
"2016b",
4);
configureInstalledDistroVersion(installedDistroVersion);
@@ -252,13 +259,13 @@
public void getRulesState_noInstalledRules() throws Exception {
configureCallerHasPermission();
- String systemRulesVersion = "2016a";
- configureDeviceSystemRulesVersion(systemRulesVersion);
+ String baseRulesVersion = "2016a";
+ configureDeviceBaseVersion(baseRulesVersion);
configureNoStagedOperation();
configureInstalledDistroVersion(null);
RulesState expectedRuleState = new RulesState(
- systemRulesVersion, RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
+ baseRulesVersion, RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
false /* operationInProgress */,
RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
RulesState.DISTRO_STATUS_NONE, null /* installedDistroRulesVersion */);
@@ -269,15 +276,15 @@
public void getRulesState_operationInProgress() throws Exception {
configureCallerHasPermission();
- String systemRulesVersion = "2016a";
+ String baseRulesVersion = "2016a";
String installedRulesVersion = "2016b";
int revision = 3;
- configureDeviceSystemRulesVersion(systemRulesVersion);
+ configureDeviceBaseVersion(baseRulesVersion);
DistroVersion installedDistroVersion = new DistroVersion(
- TzDataSetVersion.currentFormatMajorVersion(),
- TzDataSetVersion.currentFormatMinorVersion() - 1,
+ CURRENT_FORMAT_MAJOR_VERSION,
+ CURRENT_FORMAT_MINOR_VERSION - 1,
installedRulesVersion,
revision);
configureInstalledDistroVersion(installedDistroVersion);
@@ -297,7 +304,7 @@
DistroRulesVersion expectedInstalledDistroRulesVersion =
new DistroRulesVersion(installedRulesVersion, revision);
RulesState expectedRuleState = new RulesState(
- systemRulesVersion, RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
+ baseRulesVersion, RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
true /* operationInProgress */,
RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
RulesState.DISTRO_STATUS_INSTALLED, expectedInstalledDistroRulesVersion);
@@ -858,11 +865,20 @@
.thenReturn(true);
// Set up the mocks to return (arbitrary) information about the current device state.
- when(mMockTimeZoneDistroInstaller.getSystemRulesVersion()).thenReturn("2017a");
- when(mMockTimeZoneDistroInstaller.getInstalledDistroVersion()).thenReturn(
- new DistroVersion(2, 3, "2017b", 4));
+ TzDataSetVersion baseVersion = new TzDataSetVersion(
+ CURRENT_FORMAT_MAJOR_VERSION, CURRENT_FORMAT_MINOR_VERSION, "2017a",
+ 1 /* revision */);
+ when(mMockTimeZoneDistroInstaller.readBaseVersion()).thenReturn(baseVersion);
+ DistroVersion installedDistroVersion = new DistroVersion(
+ CURRENT_FORMAT_MAJOR_VERSION, CURRENT_FORMAT_MINOR_VERSION, "2017b",
+ 4 /* revision */);
+ when(mMockTimeZoneDistroInstaller.getInstalledDistroVersion())
+ .thenReturn(installedDistroVersion);
+ DistroVersion stagedDistroVersion = new DistroVersion(
+ CURRENT_FORMAT_MAJOR_VERSION, CURRENT_FORMAT_MINOR_VERSION, "2017c",
+ 7 /* revision */);
when(mMockTimeZoneDistroInstaller.getStagedDistroOperation()).thenReturn(
- StagedDistroOperation.install(new DistroVersion(5, 6, "2017c", 7)));
+ StagedDistroOperation.install(stagedDistroVersion));
// Do the dump call.
String dumpedOutput = doDumpCallAndCapture(rulesManagerService, args);
@@ -973,8 +989,11 @@
return new CheckToken(1, new PackageVersions(1, 1));
}
- private void configureDeviceSystemRulesVersion(String systemRulesVersion) throws Exception {
- when(mMockTimeZoneDistroInstaller.getSystemRulesVersion()).thenReturn(systemRulesVersion);
+ private void configureDeviceBaseVersion(String baseRulesVersion) throws Exception {
+ TzDataSetVersion tzDataSetVersion = new TzDataSetVersion(
+ CURRENT_FORMAT_MAJOR_VERSION, CURRENT_FORMAT_MINOR_VERSION, baseRulesVersion,
+ 1 /* revision */);
+ when(mMockTimeZoneDistroInstaller.readBaseVersion()).thenReturn(tzDataSetVersion);
}
private void configureInstalledDistroVersion(@Nullable DistroVersion installedDistroVersion)
@@ -1002,8 +1021,8 @@
.thenThrow(new IOException("Simulated failure"));
}
- private void configureDeviceCannotReadSystemRulesVersion() throws Exception {
- when(mMockTimeZoneDistroInstaller.getSystemRulesVersion())
+ private void configureDeviceCannotReadBaseVersion() throws Exception {
+ when(mMockTimeZoneDistroInstaller.readBaseVersion())
.thenThrow(new IOException("Simulated failure"));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 8349ac7f..07dd93c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -25,20 +25,27 @@
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.graphics.PixelFormat;
import android.platform.test.annotations.Presubmit;
+import android.view.Surface;
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
@@ -196,4 +203,33 @@
DisplayPolicy.updateLightNavigationBarLw(0, opaqueDarkNavBar,
opaqueDarkNavBar, imeDrawLightNavBar, imeDrawLightNavBar));
}
+
+ @Test
+ public void testShouldRotateSeamlessly() {
+ final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
+ final WindowManager.LayoutParams attrs = mAppWindow.mAttrs;
+ attrs.x = attrs.y = 0;
+ attrs.height = attrs.width = WindowManager.LayoutParams.MATCH_PARENT;
+ attrs.rotationAnimation = ROTATION_ANIMATION_SEAMLESS;
+ final DisplayRotation displayRotation = mock(DisplayRotation.class);
+ doReturn(Surface.ROTATION_180).when(displayRotation).getUpsideDownRotation();
+
+ synchronized (mWm.mGlobalLock) {
+ policy.focusChangedLw(null /* lastFocus */, mAppWindow);
+ policy.applyPostLayoutPolicyLw(
+ mAppWindow, attrs, null /* attached */, null /* imeTarget */);
+ spyOn(policy);
+ doReturn(true).when(policy).navigationBarCanMove();
+ // The focused fullscreen opaque window without override bounds should be able to be
+ // rotated seamlessly.
+ assertTrue(policy.shouldRotateSeamlessly(
+ displayRotation, Surface.ROTATION_0, Surface.ROTATION_90));
+
+ spyOn(mAppWindow.mAppToken);
+ doReturn(false).when(mAppWindow.mAppToken).matchParentBounds();
+ // No seamless rotation if the window may be positioned with offset after rotation.
+ assertFalse(policy.shouldRotateSeamlessly(
+ displayRotation, Surface.ROTATION_0, Surface.ROTATION_90));
+ }
+ }
}
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index f53cb82..6e839ab 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -26,7 +26,7 @@
* @hide
*/
@SystemApi
-public class DisconnectCause {
+public final class DisconnectCause {
/** The disconnect cause is not valid (Not received a disconnect cause) */
public static final int NOT_VALID = -1;
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index ffebc04..bb0673f 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -176,26 +176,21 @@
/**
* Listen for {@link PreciseCallState.State} of ringing, background and foreground calls.
- * {@more}
- * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
- * READ_PRECISE_PHONE_STATE}
*
* @hide
*/
+ @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
@SystemApi
public static final int LISTEN_PRECISE_CALL_STATE = 0x00000800;
/**
* Listen for {@link PreciseDataConnectionState} on the data connection (cellular).
*
- * {@more}
- * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
- * READ_PRECISE_PHONE_STATE}
- *
* @see #onPreciseDataConnectionStateChanged
*
* @hide
*/
+ @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
@SystemApi
public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 0x00001000;
@@ -331,12 +326,10 @@
/**
* Listen for call disconnect causes which contains {@link DisconnectCause} and
* {@link PreciseDisconnectCause}.
- * {@more}
- * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
- * READ_PRECISE_PHONE_STATE}
*
* @hide
*/
+ @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
@SystemApi
public static final int LISTEN_CALL_DISCONNECT_CAUSES = 0x02000000;
@@ -356,13 +349,10 @@
* Listen for IMS call disconnect causes which contains
* {@link android.telephony.ims.ImsReasonInfo}
*
- * {@more}
- * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
- * READ_PRECISE_PHONE_STATE}
- *
* @see #onImsCallDisconnectCauseChanged(ImsReasonInfo)
* @hide
*/
+ @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
@SystemApi
public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 0x08000000;
@@ -579,8 +569,9 @@
* @param callState {@link PreciseCallState}
* @hide
*/
+ @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
@SystemApi
- public void onPreciseCallStateChanged(PreciseCallState callState) {
+ public void onPreciseCallStateChanged(@NonNull PreciseCallState callState) {
// default implementation empty
}
@@ -591,6 +582,7 @@
*
* @hide
*/
+ @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
@SystemApi
public void onCallDisconnectCauseChanged(int disconnectCause, int preciseDisconnectCause) {
// default implementation empty
@@ -602,6 +594,7 @@
*
* @hide
*/
+ @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
@SystemApi
public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo) {
// default implementation empty
@@ -613,6 +606,7 @@
*
* @hide
*/
+ @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
@SystemApi
public void onPreciseDataConnectionStateChanged(
PreciseDataConnectionState dataConnectionState) {
diff --git a/telephony/java/android/telephony/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java
index af88748..54980a2 100644
--- a/telephony/java/android/telephony/PreciseDisconnectCause.java
+++ b/telephony/java/android/telephony/PreciseDisconnectCause.java
@@ -23,7 +23,7 @@
* @hide
*/
@SystemApi
-public class PreciseDisconnectCause {
+public final class PreciseDisconnectCause {
/** The disconnect cause is not valid (Not received a disconnect cause).*/
public static final int NOT_VALID = -1;
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index d2ae106..d461bd0 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -215,13 +215,52 @@
* @see android.telephony#CellSignalStrengthGsm
*/
public @NonNull List<CellSignalStrength> getCellSignalStrengths() {
- List<CellSignalStrength> cssList = new ArrayList<>(2); // Usually have 2 or fewer elems
- if (mLte.isValid()) cssList.add(mLte);
- if (mCdma.isValid()) cssList.add(mCdma);
- if (mTdscdma.isValid()) cssList.add(mTdscdma);
- if (mWcdma.isValid()) cssList.add(mWcdma);
- if (mGsm.isValid()) cssList.add(mGsm);
- if (mNr.isValid()) cssList.add(mNr);
+ return getCellSignalStrengths(CellSignalStrength.class);
+ }
+
+ /**
+ * Returns a List of CellSignalStrength Components of this SignalStrength Report.
+ *
+ * Use this API to access underlying
+ * {@link android.telephony#CellSignalStrength CellSignalStrength} objects that provide more
+ * granular information about the SignalStrength report. Only valid (non-empty)
+ * CellSignalStrengths will be returned. The order of any returned elements is not guaranteed,
+ * and the list may contain more than one instance of a CellSignalStrength type.
+ *
+ * @param clazz a class type that extends
+ * {@link android.telephony.CellSignalStrength CellSignalStrength} to filter possible
+ * return values.
+ * @return a List of CellSignalStrength or an empty List if there are no valid measurements.
+ *
+ * @see android.telephony#CellSignalStrength
+ * @see android.telephony#CellSignalStrengthNr
+ * @see android.telephony#CellSignalStrengthLte
+ * @see android.telephony#CellSignalStrengthTdscdma
+ * @see android.telephony#CellSignalStrengthWcdma
+ * @see android.telephony#CellSignalStrengthCdma
+ * @see android.telephony#CellSignalStrengthGsm
+ */
+ public <T extends CellSignalStrength> @NonNull List<T> getCellSignalStrengths(
+ @NonNull Class<T> clazz) {
+ List<T> cssList = new ArrayList<>(2); // Usually have 2 or fewer elems
+ if (mLte.isValid() && clazz.isAssignableFrom(CellSignalStrengthLte.class)) {
+ cssList.add((T) mLte);
+ }
+ if (mCdma.isValid() && clazz.isAssignableFrom(CellSignalStrengthCdma.class)) {
+ cssList.add((T) mCdma);
+ }
+ if (mTdscdma.isValid() && clazz.isAssignableFrom(CellSignalStrengthTdscdma.class)) {
+ cssList.add((T) mTdscdma);
+ }
+ if (mWcdma.isValid() && clazz.isAssignableFrom(CellSignalStrengthWcdma.class)) {
+ cssList.add((T) mWcdma);
+ }
+ if (mGsm.isValid() && clazz.isAssignableFrom(CellSignalStrengthGsm.class)) {
+ cssList.add((T) mGsm);
+ }
+ if (mNr.isValid() && clazz.isAssignableFrom(CellSignalStrengthNr.class)) {
+ cssList.add((T) mNr);
+ }
return cssList;
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f1869b0..c1d1440 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8665,24 +8665,26 @@
/**
- * Returns a well-formed IETF BCP 47 language tag representing the locale from the SIM, e.g,
- * en-US. Returns {@code null} if no locale could be derived from subscriptions.
+ * Returns a locale based on the country and language from the SIM. Returns {@code null} if
+ * no locale could be derived from subscriptions.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
*
* @see Locale#toLanguageTag()
- * @see Locale#forLanguageTag(String)
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- @Nullable public String getSimLocale() {
+ @Nullable public Locale getSimLocale() {
try {
final ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.getSimLocaleForSubscriber(getSubId());
+ String languageTag = telephony.getSimLocaleForSubscriber(getSubId());
+ if (!TextUtils.isEmpty(languageTag)) {
+ return Locale.forLanguageTag(languageTag);
+ }
}
} catch (RemoteException ex) {
}
diff --git a/telephony/java/android/telephony/ims/Rcs1To1Thread.java b/telephony/java/android/telephony/ims/Rcs1To1Thread.java
index d4a78ff..0bb1b43 100644
--- a/telephony/java/android/telephony/ims/Rcs1To1Thread.java
+++ b/telephony/java/android/telephony/ims/Rcs1To1Thread.java
@@ -22,6 +22,8 @@
* 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
*/
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 a547c5c0..994b27a 100644
--- a/telephony/java/android/telephony/ims/RcsEvent.java
+++ b/telephony/java/android/telephony/ims/RcsEvent.java
@@ -17,6 +17,8 @@
/**
* The base class for events that can happen on {@link RcsParticipant}s and {@link RcsThread}s.
+ *
+ * @hide
*/
public abstract class RcsEvent {
private final long mTimestamp;
diff --git a/telephony/java/android/telephony/ims/RcsEventQueryParams.java b/telephony/java/android/telephony/ims/RcsEventQueryParams.java
index 9dbfe43..5f8fa80 100644
--- a/telephony/java/android/telephony/ims/RcsEventQueryParams.java
+++ b/telephony/java/android/telephony/ims/RcsEventQueryParams.java
@@ -37,6 +37,8 @@
* 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
*/
public final class RcsEventQueryParams implements Parcelable {
/**
diff --git a/telephony/java/android/telephony/ims/RcsEventQueryResult.java b/telephony/java/android/telephony/ims/RcsEventQueryResult.java
index 92bda81..d6347e3 100644
--- a/telephony/java/android/telephony/ims/RcsEventQueryResult.java
+++ b/telephony/java/android/telephony/ims/RcsEventQueryResult.java
@@ -22,6 +22,8 @@
* 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
*/
public class RcsEventQueryResult {
private RcsQueryContinuationToken mContinuationToken;
diff --git a/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java b/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java
index 14af8ea..4742ba2 100644
--- a/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java
+++ b/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java
@@ -24,6 +24,8 @@
* Pass an instance of this class to
* {@link RcsMessage#insertFileTransfer(RcsFileTransferCreationParams)} create an
* {@link RcsFileTransferPart} and save it into storage.
+ *
+ * @hide
*/
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 9531c2e..3816cd4 100644
--- a/telephony/java/android/telephony/ims/RcsFileTransferPart.java
+++ b/telephony/java/android/telephony/ims/RcsFileTransferPart.java
@@ -26,6 +26,8 @@
/**
* 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
*/
public class RcsFileTransferPart {
/**
diff --git a/telephony/java/android/telephony/ims/RcsGroupThread.java b/telephony/java/android/telephony/ims/RcsGroupThread.java
index 6e17bc2..8cd633b 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThread.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThread.java
@@ -29,6 +29,8 @@
* 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
*/
public class RcsGroupThread extends RcsThread {
/**
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java
index 99086aa..4a6b963 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java
@@ -19,6 +19,8 @@
/**
* An event that happened on an {@link RcsGroupThread}.
+ *
+ * @hide
*/
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 cbd762d..3c6c74f 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java
@@ -22,6 +22,8 @@
/**
* 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
*/
public final class RcsGroupThreadIconChangedEvent extends RcsGroupThreadEvent {
private final Uri mNewIcon;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java
index a2a4fab..5403253 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java
@@ -21,6 +21,8 @@
/**
* 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
*/
public final class RcsGroupThreadNameChangedEvent extends RcsGroupThreadEvent {
private final String mNewName;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java
index 183cd9a..48be479 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java
@@ -20,6 +20,8 @@
/**
* 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
*/
public final class RcsGroupThreadParticipantJoinedEvent extends RcsGroupThreadEvent {
private final RcsParticipant mJoinedParticipantId;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java
index c12549b..b724a3f 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java
@@ -20,6 +20,8 @@
/**
* 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
*/
public final class RcsGroupThreadParticipantLeftEvent extends RcsGroupThreadEvent {
private RcsParticipant mLeavingParticipant;
diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessage.java b/telephony/java/android/telephony/ims/RcsIncomingMessage.java
index 61911ab..06e2a41 100644
--- a/telephony/java/android/telephony/ims/RcsIncomingMessage.java
+++ b/telephony/java/android/telephony/ims/RcsIncomingMessage.java
@@ -19,6 +19,8 @@
/**
* This is a single instance of a message received over RCS.
+ *
+ * @hide
*/
public class RcsIncomingMessage extends RcsMessage {
/**
diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java
index 61dedbc..58dc1bc 100644
--- a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java
+++ b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java
@@ -24,6 +24,8 @@
* {@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
*/
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 22e4b22..63dc1ac 100644
--- a/telephony/java/android/telephony/ims/RcsManager.java
+++ b/telephony/java/android/telephony/ims/RcsManager.java
@@ -20,6 +20,8 @@
/**
* The manager class for RCS related utilities.
+ *
+ * @hide
*/
@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 3227413..b0d0d5a 100644
--- a/telephony/java/android/telephony/ims/RcsMessage.java
+++ b/telephony/java/android/telephony/ims/RcsMessage.java
@@ -27,6 +27,8 @@
/**
* This is a single instance of a message sent or received over RCS.
+ *
+ * @hide
*/
public abstract class RcsMessage {
/**
diff --git a/telephony/java/android/telephony/ims/RcsMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsMessageCreationParams.java
index c46c605..f0eea88 100644
--- a/telephony/java/android/telephony/ims/RcsMessageCreationParams.java
+++ b/telephony/java/android/telephony/ims/RcsMessageCreationParams.java
@@ -27,6 +27,8 @@
* {@link RcsThread#addIncomingMessage(RcsIncomingMessageCreationParams)} and
* {@link RcsThread#addOutgoingMessage(RcsOutgoingMessageCreationParams)} to create and persist
* {@link RcsMessage}s on an {@link RcsThread}
+ *
+ * @hide
*/
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 535a597..6491ac9 100644
--- a/telephony/java/android/telephony/ims/RcsMessageQueryParams.java
+++ b/telephony/java/android/telephony/ims/RcsMessageQueryParams.java
@@ -31,6 +31,8 @@
* 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
*/
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 3514b48..e4020c1 100644
--- a/telephony/java/android/telephony/ims/RcsMessageQueryResult.java
+++ b/telephony/java/android/telephony/ims/RcsMessageQueryResult.java
@@ -32,6 +32,8 @@
* 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
*/
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 b0b930c..9064251 100644
--- a/telephony/java/android/telephony/ims/RcsMessageSnippet.java
+++ b/telephony/java/android/telephony/ims/RcsMessageSnippet.java
@@ -23,6 +23,8 @@
/**
* An immutable summary of the latest {@link RcsMessage} on an {@link RcsThread}
+ *
+ * @hide
*/
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 31f2983..3111652 100644
--- a/telephony/java/android/telephony/ims/RcsMessageStore.java
+++ b/telephony/java/android/telephony/ims/RcsMessageStore.java
@@ -26,6 +26,8 @@
/**
* RcsMessageStore is the application interface to RcsProvider and provides access methods to
* RCS related database tables.
+ *
+ * @hide
*/
public class RcsMessageStore {
/**
diff --git a/telephony/java/android/telephony/ims/RcsMessageStoreException.java b/telephony/java/android/telephony/ims/RcsMessageStoreException.java
index f25bb17..3b3fcf2 100644
--- a/telephony/java/android/telephony/ims/RcsMessageStoreException.java
+++ b/telephony/java/android/telephony/ims/RcsMessageStoreException.java
@@ -19,6 +19,8 @@
/**
* An exception that happened on {@link RcsMessageStore} or one of the derived storage classes in
* {@link android.telephony.ims}
+ *
+ * @hide
*/
public class RcsMessageStoreException extends Exception {
diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessage.java b/telephony/java/android/telephony/ims/RcsOutgoingMessage.java
index 06fb832..1b4bfe5 100644
--- a/telephony/java/android/telephony/ims/RcsOutgoingMessage.java
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessage.java
@@ -23,6 +23,8 @@
/**
* This is a single instance of a message sent over RCS.
+ *
+ * @hide
*/
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 979634a..81e3244 100644
--- a/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java
@@ -23,6 +23,8 @@
* {@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
*/
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 1c87b13..2db49c6 100644
--- a/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java
@@ -21,6 +21,8 @@
/**
* This class holds the delivery information of an {@link RcsOutgoingMessage} for each
* {@link RcsParticipant} that the message was intended for.
+ *
+ * @hide
*/
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 7ba5d8e..bcf134a 100644
--- a/telephony/java/android/telephony/ims/RcsParticipant.java
+++ b/telephony/java/android/telephony/ims/RcsParticipant.java
@@ -20,6 +20,8 @@
/**
* RcsParticipant is an RCS capable contact that can participate in {@link RcsThread}s.
+ *
+ * @hide
*/
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 cc2613f..61801f3 100644
--- a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
+++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
@@ -21,6 +21,8 @@
/**
* 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
*/
public final class RcsParticipantAliasChangedEvent extends RcsEvent {
// 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 d24d079..ada9b8a 100644
--- a/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java
+++ b/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java
@@ -30,6 +30,8 @@
* 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
*/
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 505f1a5..92e2fa78 100644
--- a/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java
+++ b/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java
@@ -28,6 +28,8 @@
* 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
*/
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 08643de..970c110 100644
--- a/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java
+++ b/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java
@@ -31,6 +31,8 @@
* @see RcsMessageQueryResult#getContinuationToken()
* @see RcsParticipantQueryResult#getContinuationToken()
* @see RcsThreadQueryResult#getContinuationToken()
+ *
+ * @hide
*/
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 e015dd3..cf1dc76 100644
--- a/telephony/java/android/telephony/ims/RcsThread.java
+++ b/telephony/java/android/telephony/ims/RcsThread.java
@@ -27,6 +27,8 @@
/**
* RcsThread represents a single RCS conversation thread. It holds messages that were sent and
* received and events that occurred on that thread.
+ *
+ * @hide
*/
public abstract class RcsThread {
/**
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryParams.java b/telephony/java/android/telephony/ims/RcsThreadQueryParams.java
index 05a5a39..81eee40 100644
--- a/telephony/java/android/telephony/ims/RcsThreadQueryParams.java
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryParams.java
@@ -35,6 +35,8 @@
/**
* 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
*/
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 1cac61d..9f2fba5 100644
--- a/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
@@ -32,6 +32,8 @@
* 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
*/
public final class RcsThreadQueryResult implements Parcelable {
// A token for the caller to continue their query for the next batch of results
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java
index 60bd60f..fece8ba 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java
@@ -49,7 +49,7 @@
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mContent.setLeftTopRightBottom(0, 0, width, height);
- RecordingCanvas canvas = mContent.startRecording();
+ RecordingCanvas canvas = mContent.beginRecording();
canvas.drawColor(Color.WHITE);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.BLACK);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MyLittleTextureView.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MyLittleTextureView.java
index 8bd7d79..08d5d4f 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/MyLittleTextureView.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MyLittleTextureView.java
@@ -60,14 +60,14 @@
outline.setAlpha(1f);
childNode.setOutline(outline);
{
- Canvas canvas = childNode.startRecording();
+ Canvas canvas = childNode.beginRecording();
canvas.drawColor(Color.BLUE);
}
childNode.endRecording();
childNode.setElevation(20f);
{
- Canvas canvas = mContent.startRecording();
+ Canvas canvas = mContent.beginRecording();
canvas.drawColor(Color.WHITE);
canvas.enableZ();
canvas.drawRenderNode(childNode);
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index 097d33d..def5b8e 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -345,7 +345,7 @@
PackageInstaller.SessionInfo info =
intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
if (info != null && info.getSessionId() == sessionId) {
- if (info.isSessionReady() || info.isSessionFailed()) {
+ if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
try {
sessionStatus.put(info);
} catch (InterruptedException e) {
@@ -365,13 +365,13 @@
PackageInstaller.SessionInfo info = installer.getSessionInfo(sessionId);
try {
- if (info.isSessionReady() || info.isSessionFailed()) {
+ if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
sessionStatus.put(info);
}
info = sessionStatus.take();
context.unregisterReceiver(sessionUpdatedReceiver);
- if (info.isSessionFailed()) {
+ if (info.isStagedSessionFailed()) {
throw new AssertionError(info.getStagedSessionErrorMessage());
}
} catch (InterruptedException e) {
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 0032960..ffc1a92 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -44,6 +44,7 @@
Maybe<ResourceName> ToResourceName(
const android::ResTable::resource_name& name_in) {
+ // TODO: Remove this when ResTable and AssetManager(1) are removed from AAPT2
ResourceName name_out;
if (!name_in.package) {
return {};
@@ -79,6 +80,41 @@
return name_out;
}
+Maybe<ResourceName> ToResourceName(const android::AssetManager2::ResourceName& name_in) {
+ ResourceName name_out;
+ if (!name_in.package) {
+ return {};
+ }
+
+ name_out.package = std::string(name_in.package, name_in.package_len);
+
+ const ResourceType* type;
+ if (name_in.type16) {
+ type = ParseResourceType(
+ util::Utf16ToUtf8(StringPiece16(name_in.type16, name_in.type_len)));
+ } else if (name_in.type) {
+ type = ParseResourceType(StringPiece(name_in.type, name_in.type_len));
+ } else {
+ return {};
+ }
+
+ if (!type) {
+ return {};
+ }
+
+ name_out.type = *type;
+
+ if (name_in.entry16) {
+ name_out.entry =
+ util::Utf16ToUtf8(StringPiece16(name_in.entry16, name_in.entry_len));
+ } else if (name_in.entry) {
+ name_out.entry = std::string(name_in.entry, name_in.entry_len);
+ } else {
+ return {};
+ }
+ return name_out;
+}
+
bool ParseResourceName(const StringPiece& str, ResourceNameRef* out_ref,
bool* out_private) {
if (str.empty()) {
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index e282fd58..a8a3120 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -20,6 +20,7 @@
#include <functional>
#include <memory>
+#include "androidfw/AssetManager2.h"
#include "androidfw/ConfigDescription.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
@@ -78,6 +79,12 @@
const android::ResTable::resource_name& name);
/**
+ * Convert an android::AssetManager2::ResourceName to an aapt::ResourceName struct.
+ */
+Maybe<ResourceName> ToResourceName(
+ const android::AssetManager2::ResourceName& name_in);
+
+/**
* Returns a boolean value if the string is equal to TRUE, true, True, FALSE,
* false, or False.
*/
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 22edd2f..a7b8d25 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -717,28 +717,20 @@
return true;
}
-static int32_t FindFrameworkAssetManagerCookie(const android::AssetManager& assets) {
+static android::ApkAssetsCookie FindFrameworkAssetManagerCookie(
+ const android::AssetManager2& assets) {
using namespace android;
// Find the system package (0x01). AAPT always generates attributes with the type 0x01, so
// we're looking for the first attribute resource in the system package.
- const ResTable& table = assets.getResources(true);
- Res_value val;
- ssize_t idx = table.getResource(0x01010000, &val, true);
- if (idx != NO_ERROR) {
- // Try as a bag.
- const ResTable::bag_entry* entry;
- ssize_t cnt = table.lockBag(0x01010000, &entry);
- if (cnt >= 0) {
- idx = entry->stringBlock;
- }
- table.unlockBag(entry);
- }
+ Res_value val{};
+ ResTable_config config{};
+ uint32_t type_spec_flags;
+ ApkAssetsCookie idx = assets.GetResource(0x01010000, true /** may_be_bag */,
+ 0 /** density_override */, &val, &config,
+ &type_spec_flags);
- if (idx < 0) {
- return 0;
- }
- return table.getTableCookie(idx);
+ return idx;
}
class Linker {
@@ -750,17 +742,17 @@
file_collection_(util::make_unique<io::FileCollection>()) {
}
- void ExtractCompileSdkVersions(android::AssetManager* assets) {
+ void ExtractCompileSdkVersions(android::AssetManager2* assets) {
using namespace android;
- int32_t cookie = FindFrameworkAssetManagerCookie(*assets);
- if (cookie == 0) {
+ android::ApkAssetsCookie cookie = FindFrameworkAssetManagerCookie(*assets);
+ if (cookie == android::kInvalidCookie) {
// No Framework assets loaded. Not a failure.
return;
}
std::unique_ptr<Asset> manifest(
- assets->openNonAsset(cookie, kAndroidManifestPath, Asset::AccessMode::ACCESS_BUFFER));
+ assets->OpenNonAsset(kAndroidManifestPath, cookie, Asset::AccessMode::ACCESS_BUFFER));
if (manifest == nullptr) {
// No errors.
return;
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index a844a43..78e0074 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -20,9 +20,11 @@
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "androidfw/AssetManager.h"
+#include "androidfw/Asset.h"
+#include "androidfw/AssetManager2.h"
#include "androidfw/ConfigDescription.h"
#include "androidfw/ResourceTypes.h"
+#include "androidfw/ResourceUtils.h"
#include "NameMangler.h"
#include "Resource.h"
@@ -30,6 +32,7 @@
#include "ValueVisitor.h"
#include "util/Util.h"
+using ::android::ApkAssets;
using ::android::ConfigDescription;
using ::android::StringPiece;
using ::android::StringPiece16;
@@ -214,51 +217,75 @@
}
bool AssetManagerSymbolSource::AddAssetPath(const StringPiece& path) {
- int32_t cookie = 0;
- return assets_.addAssetPath(android::String8(path.data(), path.size()), &cookie);
+ if (std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path.data())) {
+ apk_assets_.push_back(std::move(apk));
+
+ std::vector<const ApkAssets*> apk_assets;
+ for (const std::unique_ptr<const ApkAssets>& apk_asset : apk_assets_) {
+ apk_assets.push_back(apk_asset.get());
+ }
+
+ asset_manager_.SetApkAssets(apk_assets, true /* invalidate_caches */,
+ false /* filter_incompatible_configs */);
+ return true;
+ }
+ return false;
}
std::map<size_t, std::string> AssetManagerSymbolSource::GetAssignedPackageIds() const {
std::map<size_t, std::string> package_map;
- const android::ResTable& table = assets_.getResources(false);
- const size_t package_count = table.getBasePackageCount();
- for (size_t i = 0; i < package_count; i++) {
- package_map[table.getBasePackageId(i)] =
- util::Utf16ToUtf8(android::StringPiece16(table.getBasePackageName(i).string()));
- }
+ asset_manager_.ForEachPackage([&package_map](const std::string& name, uint8_t id) -> bool {
+ package_map.insert(std::make_pair(id, name));
+ return true;
+ });
+
return package_map;
}
bool AssetManagerSymbolSource::IsPackageDynamic(uint32_t packageId) const {
- return assets_.getResources(false).isPackageDynamic(packageId);
+ if (packageId == 0) {
+ return true;
+ }
+
+ for (const std::unique_ptr<const ApkAssets>& assets : apk_assets_) {
+ for (const std::unique_ptr<const android::LoadedPackage>& loaded_package
+ : assets->GetLoadedArsc()->GetPackages()) {
+ if (packageId == loaded_package->GetPackageId() && loaded_package->IsDynamic()) {
+ return true;
+ }
+ }
+ }
+
+ return false;
}
static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable(
- const android::ResTable& table, ResourceId id) {
- // Try as a bag.
- const android::ResTable::bag_entry* entry;
- ssize_t count = table.lockBag(id.id, &entry);
- if (count < 0) {
- table.unlockBag(entry);
+ android::AssetManager2& am, ResourceId id) {
+ if (am.GetApkAssets().empty()) {
+ return {};
+ }
+
+ const android::ResolvedBag* bag = am.GetBag(id.id);
+ if (bag == nullptr) {
return nullptr;
}
// We found a resource.
std::unique_ptr<SymbolTable::Symbol> s = util::make_unique<SymbolTable::Symbol>(id);
- // Check to see if it is an attribute.
- for (size_t i = 0; i < (size_t)count; i++) {
- if (entry[i].map.name.ident == android::ResTable_map::ATTR_TYPE) {
- s->attribute = std::make_shared<Attribute>(entry[i].map.value.data);
+ const size_t count = bag->entry_count;
+ for (uint32_t i = 0; i < count; i++) {
+ if (bag->entries[i].key == android::ResTable_map::ATTR_TYPE) {
+ s->attribute = std::make_shared<Attribute>(bag->entries[i].value.data);
break;
}
}
if (s->attribute) {
- for (size_t i = 0; i < (size_t)count; i++) {
- const android::ResTable_map& map_entry = entry[i].map;
- if (Res_INTERNALID(map_entry.name.ident)) {
- switch (map_entry.name.ident) {
+ for (size_t i = 0; i < count; i++) {
+ const android::ResolvedBag::Entry& map_entry = bag->entries[i];
+ if (Res_INTERNALID(map_entry.key)) {
+ switch (map_entry.key) {
case android::ResTable_map::ATTR_MIN:
s->attribute->min_int = static_cast<int32_t>(map_entry.value.data);
break;
@@ -269,74 +296,65 @@
continue;
}
- android::ResTable::resource_name entry_name;
- if (!table.getResourceName(map_entry.name.ident, false, &entry_name)) {
- table.unlockBag(entry);
+ android::AssetManager2::ResourceName name;
+ if (!am.GetResourceName(map_entry.key, &name)) {
return nullptr;
}
- Maybe<ResourceName> parsed_name = ResourceUtils::ToResourceName(entry_name);
+ Maybe<ResourceName> parsed_name = ResourceUtils::ToResourceName(name);
if (!parsed_name) {
return nullptr;
}
Attribute::Symbol symbol;
symbol.symbol.name = parsed_name.value();
- symbol.symbol.id = ResourceId(map_entry.name.ident);
+ symbol.symbol.id = ResourceId(map_entry.key);
symbol.value = map_entry.value.data;
s->attribute->symbols.push_back(std::move(symbol));
}
}
- table.unlockBag(entry);
+
return s;
}
std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName(
const ResourceName& name) {
- const android::ResTable& table = assets_.getResources(false);
+ const std::string mangled_entry = NameMangler::MangleEntry(name.package, name.entry);
- const std::u16string package16 = util::Utf8ToUtf16(name.package);
- const std::u16string type16 = util::Utf8ToUtf16(to_string(name.type));
- const std::u16string entry16 = util::Utf8ToUtf16(name.entry);
- const std::u16string mangled_entry16 =
- util::Utf8ToUtf16(NameMangler::MangleEntry(name.package, name.entry));
-
+ bool found = false;
+ ResourceId res_id = 0;
uint32_t type_spec_flags;
- ResourceId res_id;
// There can be mangled resources embedded within other packages. Here we will
// look into each package and look-up the mangled name until we find the resource.
- const size_t count = table.getBasePackageCount();
- for (size_t i = 0; i < count; i++) {
- const android::String16 package_name = table.getBasePackageName(i);
- StringPiece16 real_package16 = package16;
- StringPiece16 real_entry16 = entry16;
- std::u16string scratch_entry16;
- if (StringPiece16(package_name) != package16) {
- real_entry16 = mangled_entry16;
- real_package16 = package_name.string();
+ asset_manager_.ForEachPackage([&](const std::string& package_name, uint8_t id) -> bool {
+ ResourceName real_name(name.package, name.type, name.entry);
+
+ if (package_name != name.package) {
+ real_name.entry = mangled_entry;
+ real_name.package = package_name;
}
- type_spec_flags = 0;
- res_id = table.identifierForName(real_entry16.data(), real_entry16.size(), type16.data(),
- type16.size(), real_package16.data(), real_package16.size(),
- &type_spec_flags);
- if (res_id.is_valid()) {
- break;
+ res_id = asset_manager_.GetResourceId(real_name.to_string());
+ if (res_id.is_valid() && asset_manager_.GetResourceFlags(res_id.id, &type_spec_flags)) {
+ found = true;
+ return false;
}
- }
- if (!res_id.is_valid()) {
+ return true;
+ });
+
+ if (!found) {
return {};
}
std::unique_ptr<SymbolTable::Symbol> s;
if (name.type == ResourceType::kAttr) {
- s = LookupAttributeInTable(table, res_id);
+ s = LookupAttributeInTable(asset_manager_, res_id);
} else {
s = util::make_unique<SymbolTable::Symbol>();
s->id = res_id;
- s->is_dynamic = table.isResourceDynamic(res_id.id);
+ s->is_dynamic = IsPackageDynamic(ResourceId(res_id).package_id());
}
if (s) {
@@ -346,13 +364,13 @@
return {};
}
-static Maybe<ResourceName> GetResourceName(const android::ResTable& table,
+static Maybe<ResourceName> GetResourceName(android::AssetManager2& am,
ResourceId id) {
- android::ResTable::resource_name res_name = {};
- if (!table.getResourceName(id.id, true, &res_name)) {
+ android::AssetManager2::ResourceName name;
+ if (!am.GetResourceName(id.id, &name)) {
return {};
}
- return ResourceUtils::ToResourceName(res_name);
+ return ResourceUtils::ToResourceName(name);
}
std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById(
@@ -361,22 +379,30 @@
// Exit early and avoid the error logs from AssetManager.
return {};
}
- const android::ResTable& table = assets_.getResources(false);
- Maybe<ResourceName> maybe_name = GetResourceName(table, id);
+
+ if (apk_assets_.empty()) {
+ return {};
+ }
+
+ Maybe<ResourceName> maybe_name = GetResourceName(asset_manager_, id);
if (!maybe_name) {
return {};
}
- uint32_t type_spec_flags = 0;
- table.getResourceFlags(id.id, &type_spec_flags);
+ uint32_t type_spec_flags = 0;
+ if (!asset_manager_.GetResourceFlags(id.id, &type_spec_flags)) {
+ return {};
+ }
+
+ ResourceName& name = maybe_name.value();
std::unique_ptr<SymbolTable::Symbol> s;
- if (maybe_name.value().type == ResourceType::kAttr) {
- s = LookupAttributeInTable(table, id);
+ if (name.type == ResourceType::kAttr) {
+ s = LookupAttributeInTable(asset_manager_, id);
} else {
s = util::make_unique<SymbolTable::Symbol>();
s->id = id;
- s->is_dynamic = table.isResourceDynamic(id.id);
+ s->is_dynamic = IsPackageDynamic(ResourceId(id).package_id());
}
if (s) {
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index 2d8bd02..6997cd6 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -22,7 +22,8 @@
#include <vector>
#include "android-base/macros.h"
-#include "androidfw/AssetManager.h"
+#include "androidfw/Asset.h"
+#include "androidfw/AssetManager2.h"
#include "utils/JenkinsHash.h"
#include "utils/LruCache.h"
@@ -201,12 +202,13 @@
std::unique_ptr<SymbolTable::Symbol> FindByReference(
const Reference& ref) override;
- android::AssetManager* GetAssetManager() {
- return &assets_;
+ android::AssetManager2* GetAssetManager() {
+ return &asset_manager_;
}
private:
- android::AssetManager assets_;
+ android::AssetManager2 asset_manager_;
+ std::vector<std::unique_ptr<const android::ApkAssets>> apk_assets_;
DISALLOW_COPY_AND_ASSIGN(AssetManagerSymbolSource);
};
diff --git a/tools/aapt2/process/SymbolTable_test.cpp b/tools/aapt2/process/SymbolTable_test.cpp
index 1f59d70..ddc2101 100644
--- a/tools/aapt2/process/SymbolTable_test.cpp
+++ b/tools/aapt2/process/SymbolTable_test.cpp
@@ -76,40 +76,54 @@
EXPECT_THAT(symbol_table.FindByName(test::ParseNameOrDie("com.android.lib:id/foo")), NotNull());
}
-TEST(SymbolTableTest, FindByNameWhenSymbolIsMangledInResTable) {
+using SymbolTableTestFixture = CommandTestFixture;
+TEST_F(SymbolTableTestFixture, FindByNameWhenSymbolIsMangledInResTable) {
using namespace android;
+ StdErrDiagnostics diag;
- std::unique_ptr<IAaptContext> context =
- test::ContextBuilder()
- .SetCompilationPackage("com.android.app")
- .SetPackageId(0x7f)
- .SetPackageType(PackageType::kApp)
- .SetMinSdkVersion(SDK_LOLLIPOP_MR1)
- .SetNameManglerPolicy(NameManglerPolicy{"com.android.app"})
- .Build();
+ // Create a static library.
+ const std::string static_lib_compiled_files_dir = GetTestPath("static-lib-compiled");
+ ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
+ R"(<?xml version="1.0" encoding="utf-8"?>
+ <resources>
+ <item type="id" name="foo"/>
+ </resources>)",
+ static_lib_compiled_files_dir, &diag));
- // Create a ResourceTable with a mangled resource, simulating a static library being merged into
- // the main application package.
- std::unique_ptr<ResourceTable> table =
- test::ResourceTableBuilder()
- .AddSimple("com.android.app:id/" + NameMangler::MangleEntry("com.android.lib", "foo"),
- ResourceId(0x7f020000))
- .AddSimple("com.android.app:id/bar", ResourceId(0x7f020001))
- .Build();
+ const std::string static_lib_apk = GetTestPath("static_lib.apk");
+ std::vector<std::string> link_args = {
+ "--manifest", GetDefaultManifest("com.android.lib"),
+ "--min-sdk-version", "22",
+ "--static-lib",
+ "-o", static_lib_apk,
+ };
+ ASSERT_TRUE(Link(link_args, static_lib_compiled_files_dir, &diag));
- BigBuffer buffer(1024u);
- TableFlattener flattener({}, &buffer);
- ASSERT_TRUE(flattener.Consume(context.get(), table.get()));
+ // Merge the static library into the main application package. The static library resources will
+ // be mangled with the library package name.
+ const std::string app_compiled_files_dir = GetTestPath("app-compiled");
+ ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
+ R"(<?xml version="1.0" encoding="utf-8"?>
+ <resources>
+ <item type="id" name="bar"/>
+ </resources>)",
+ app_compiled_files_dir, &diag));
- std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
+ const std::string out_apk = GetTestPath("out.apk");
+ link_args = {
+ "--manifest", GetDefaultManifest("com.android.app"),
+ "--min-sdk-version", "22",
+ "-o", out_apk,
+ static_lib_apk
+ };
+ ASSERT_TRUE(Link(link_args, app_compiled_files_dir, &diag));
// Construct the test AssetManager.
auto asset_manager_source = util::make_unique<AssetManagerSymbolSource>();
- ResTable& res_table = const_cast<ResTable&>(
- asset_manager_source->GetAssetManager()->getResources(false /*required*/));
- ASSERT_THAT(res_table.add(data.get(), buffer.size()), Eq(NO_ERROR));
+ asset_manager_source->AddAssetPath(out_apk);
- SymbolTable symbol_table(context->GetNameMangler());
+ NameMangler name_mangler(NameManglerPolicy{"com.android.app"});
+ SymbolTable symbol_table(&name_mangler);
symbol_table.AppendSource(std::move(asset_manager_source));
EXPECT_THAT(symbol_table.FindByName(test::ParseNameOrDie("com.android.lib:id/foo")), NotNull());
diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp
index 3fcdfb7..a51b4a4 100644
--- a/tools/aapt2/test/Fixture.cpp
+++ b/tools/aapt2/test/Fixture.cpp
@@ -37,6 +37,8 @@
namespace aapt {
+const char* CommandTestFixture::kDefaultPackageName = "com.aapt.command.test";
+
void ClearDirectory(const android::StringPiece& path) {
const std::string root_dir = path.to_string();
std::unique_ptr<DIR, decltype(closedir)*> dir(opendir(root_dir.data()), closedir);
@@ -124,12 +126,12 @@
return LinkCommand(diag).Execute(link_args, &std::cerr) == 0;
}
-std::string CommandTestFixture::GetDefaultManifest() {
+std::string CommandTestFixture::GetDefaultManifest(const char* package_name) {
const std::string manifest_file = GetTestPath("AndroidManifest.xml");
- CHECK(WriteFile(manifest_file, R"(
+ CHECK(WriteFile(manifest_file, android::base::StringPrintf(R"(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.aapt.command.test">
- </manifest>)"));
+ package="%s">
+ </manifest>)", package_name)));
return manifest_file;
}
diff --git a/tools/aapt2/test/Fixture.h b/tools/aapt2/test/Fixture.h
index 3079c75..fce2aeb 100644
--- a/tools/aapt2/test/Fixture.h
+++ b/tools/aapt2/test/Fixture.h
@@ -81,7 +81,7 @@
IDiagnostics* diag);
// Creates a minimal android manifest within the test directory and returns the file path.
- std::string GetDefaultManifest();
+ std::string GetDefaultManifest(const char* package_name = kDefaultPackageName);
// Returns pointer to data inside APK files
std::unique_ptr<io::IData> OpenFileAsData(LoadedApk* apk,
@@ -91,6 +91,7 @@
void AssertLoadXml(LoadedApk* apk, const io::IData* data,
android::ResXMLTree* out_tree);
+ static const char* kDefaultPackageName;
private:
DISALLOW_COPY_AND_ASSIGN(CommandTestFixture);
};
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 604b257..5d57de6 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -102,12 +102,21 @@
#endif
bool mkdirs(const std::string& path) {
- #ifdef _WIN32
- // Start after the drive path if present. Calling mkdir with only the drive will cause an error.
- size_t current_pos = 1u;
- if (path.size() >= 3 && path[1] == ':' &&
- (path[2] == '\\' || path[2] == '/')) {
- current_pos = 3u;
+ #ifdef _WIN32
+ // Start after the long path prefix if present.
+ bool require_drive = false;
+ size_t current_pos = 0u;
+ if (util::StartsWith(path, R"(\\?\)")) {
+ require_drive = true;
+ current_pos = 4u;
+ }
+
+ // Start after the drive path if present.
+ if (path.size() >= 3 && path[current_pos + 1] == ':' &&
+ (path[current_pos + 2] == '\\' || path[current_pos + 2] == '/')) {
+ current_pos += 3u;
+ } else if (require_drive) {
+ return false;
}
#else
// Start after the first character so that we don't consume the root '/'.
diff --git a/tools/aapt2/util/Files_test.cpp b/tools/aapt2/util/Files_test.cpp
index 202cc26..6c38080 100644
--- a/tools/aapt2/util/Files_test.cpp
+++ b/tools/aapt2/util/Files_test.cpp
@@ -19,6 +19,7 @@
#include <sstream>
#include "android-base/stringprintf.h"
+#include "android-base/utf8.h"
#include "test/Test.h"
@@ -65,5 +66,40 @@
EXPECT_EQ(expected_path_, base);
}
+#ifdef _WIN32
+TEST_F(FilesTest, WindowsMkdirsLongPath) {
+ // Creating directory paths longer than the Windows maximum path length (260 charatcers) should
+ // succeed.
+ const std::string kDirName = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+ const size_t kRecursiveDepth = 10u;
+
+ // Recursively create the test file path and clean up the created directories after the files have
+ // been created.
+ std::function<void(std::string, size_t)> CreateResursiveDirs =
+ [&kDirName, &CreateResursiveDirs](std::string current_path, const size_t n) -> void {
+ AppendPath(¤t_path, kDirName);
+
+ if (n == 0) {
+ ASSERT_TRUE(file::mkdirs(current_path)) << "Failed to create path " << current_path;
+ } else {
+ CreateResursiveDirs(current_path, n - 1);
+ }
+
+ // Clean up the created directories.
+ _rmdir(current_path.data());
+ };
+
+ CreateResursiveDirs(
+ android::base::StringPrintf(R"(\\?\%s)", android::base::GetExecutableDirectory().data()),
+ kRecursiveDepth);
+}
+
+TEST_F(FilesTest, WindowsMkdirsLongPathMissingDrive) {
+ ASSERT_FALSE(file::mkdirs(R"(\\?\local\path\to\file)"));
+ ASSERT_FALSE(file::mkdirs(R"(\\?\:local\path\to\file)"));
+ ASSERT_FALSE(file::mkdirs(R"(\\?\\local\path\to\file)"));
+}
+#endif
+
} // namespace files
} // namespace aapt