Merge "Exclude recent tasks within an ActivityView"
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 fce28d9..0967479 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -14946,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();
@@ -14963,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();
@@ -14986,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 {
@@ -44862,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();
@@ -45669,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 b580deb..6f314f3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -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/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/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 497d5ba..b01cd0e 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -277,12 +277,8 @@
      *
      * @param showingKeyguard True if the keyguard is showing, false otherwise.
      * @param showingAod True if AOD is showing, false otherwise.
-     * @param secondaryDisplaysShowing The displayId's of the secondary displays on which the
-     * keyguard is showing, or {@code null} if there is no such display. Only meaningful if showing
-     * is {@code true}.
      */
-    void setLockScreenShown(boolean showingKeyguard, boolean showingAod,
-            in int[] secondaryDisplaysShowing);
+    void setLockScreenShown(boolean showingKeyguard, boolean showingAod);
     Bundle getAssistContextExtras(int requestType);
     boolean launchAssistIntent(in Intent intent, int requestType, in String hint, int userHandle,
             in Bundle args);
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/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/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/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 42e8aa6..a43dc60 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -79,7 +79,7 @@
     }
 
     /**
-     * Utility to create an instance of {@link ApfProgramEvent}.
+     * Utility to create an instance of {@link ValidationProbeEvent}.
      */
     public static class Builder {
         private long mDurationMs;
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/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 792eda7..463eae68 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -209,7 +209,7 @@
         } else {
             // TODO(b/123099468): figure out if it's ok to reuse the proxy; add logging
             if (DEBUG) Log.d(TAG, "Reusing proxy for session " + sessionId);
-            proxy.update(focusedId, focusedValue);
+            proxy.update(focusedId, focusedValue, callback);
         }
         // TODO(b/123101711): set cancellation signal
         final CancellationSignal cancellationSignal = null;
@@ -299,13 +299,14 @@
         private final Object mLock = new Object();
         private final IAugmentedAutofillManagerClient mClient;
         private final int mSessionId;
-        private final IFillCallback mCallback;
         public final int taskId;
         public final ComponentName componentName;
         @GuardedBy("mLock")
         private AutofillId mFocusedId;
         @GuardedBy("mLock")
         private AutofillValue mFocusedValue;
+        @GuardedBy("mLock")
+        private IFillCallback mCallback;
 
         /**
          * Id of the last field that cause the Autofill UI to be shown.
@@ -316,8 +317,8 @@
         private AutofillId mLastShownId;
 
         // Objects used to log metrics
-        private final long mRequestTime;
-        private long mOnSuccessTime;
+        private final long mFirstRequestTime;
+        private long mFirstOnSuccessTime;
         private long mUiFirstShownTime;
         private long mUiFirstDestroyedTime;
 
@@ -338,7 +339,7 @@
             this.componentName = componentName;
             this.mFocusedId = focusedId;
             this.mFocusedValue = focusedValue;
-            this.mRequestTime = requestTime;
+            this.mFirstRequestTime = requestTime;
             // TODO(b/123099468): linkToDeath
         }
 
@@ -400,11 +401,18 @@
             mClient.requestHideFillUi(mSessionId, mFocusedId);
         }
 
-        private void update(@NonNull AutofillId focusedId, @NonNull AutofillValue focusedValue) {
+        private void update(@NonNull AutofillId focusedId, @NonNull AutofillValue focusedValue,
+                @NonNull IFillCallback callback) {
             synchronized (mLock) {
                 // TODO(b/123099468): should we close the popupwindow if the focused id changed?
                 mFocusedId = focusedId;
                 mFocusedValue = focusedValue;
+                if (mCallback != null) {
+                    // TODO(b/123101711): we need to check whether the previous request was
+                    //  completed or not, and if not, cancel it first.
+                    Slog.d(TAG, "mCallback is updated.");
+                }
+                mCallback = callback;
             }
         }
 
@@ -426,11 +434,11 @@
         public void report(@ReportEvent int event) {
             switch (event) {
                 case REPORT_EVENT_ON_SUCCESS:
-                    if (mOnSuccessTime == 0) {
-                        mOnSuccessTime = SystemClock.elapsedRealtime();
+                    if (mFirstOnSuccessTime == 0) {
+                        mFirstOnSuccessTime = SystemClock.elapsedRealtime();
                         if (DEBUG) {
-                            Slog.d(TAG, "Service responsed in "
-                                    + TimeUtils.formatDuration(mOnSuccessTime - mRequestTime));
+                            Slog.d(TAG, "Service responded in " + TimeUtils.formatDuration(
+                                    mFirstOnSuccessTime - mFirstRequestTime));
                         }
                     }
                     try {
@@ -443,8 +451,8 @@
                     if (mUiFirstShownTime == 0) {
                         mUiFirstShownTime = SystemClock.elapsedRealtime();
                         if (DEBUG) {
-                            Slog.d(TAG, "UI shown in "
-                                    + TimeUtils.formatDuration(mUiFirstShownTime - mRequestTime));
+                            Slog.d(TAG, "UI shown in " + TimeUtils.formatDuration(
+                                    mUiFirstShownTime - mFirstRequestTime));
                         }
                     }
                     break;
@@ -452,9 +460,8 @@
                     if (mUiFirstDestroyedTime == 0) {
                         mUiFirstDestroyedTime = SystemClock.elapsedRealtime();
                         if (DEBUG) {
-                            Slog.d(TAG, "UI destroyed in "
-                                    + TimeUtils.formatDuration(
-                                            mUiFirstDestroyedTime - mRequestTime));
+                            Slog.d(TAG, "UI destroyed in " + TimeUtils.formatDuration(
+                                    mUiFirstDestroyedTime - mFirstRequestTime));
                         }
                     }
                     break;
@@ -486,20 +493,20 @@
                 pw.print(prefix); pw.println("smartSuggestion:");
                 mSmartSuggestion.dump(prefix2, pw);
             }
-            if (mOnSuccessTime > 0) {
-                final long responseTime = mOnSuccessTime - mRequestTime;
+            if (mFirstOnSuccessTime > 0) {
+                final long responseTime = mFirstOnSuccessTime - mFirstRequestTime;
                 pw.print(prefix); pw.print("response time: ");
                 TimeUtils.formatDuration(responseTime, pw); pw.println();
             }
 
             if (mUiFirstShownTime > 0) {
-                final long uiRenderingTime = mUiFirstShownTime - mRequestTime;
+                final long uiRenderingTime = mUiFirstShownTime - mFirstRequestTime;
                 pw.print(prefix); pw.print("UI rendering time: ");
                 TimeUtils.formatDuration(uiRenderingTime, pw); pw.println();
             }
 
             if (mUiFirstDestroyedTime > 0) {
-                final long uiTotalTime = mUiFirstDestroyedTime - mRequestTime;
+                final long uiTotalTime = mUiFirstDestroyedTime - mFirstRequestTime;
                 pw.print(prefix); pw.print("UI life time: ");
                 TimeUtils.formatDuration(uiTotalTime, pw); pw.println();
             }
@@ -510,6 +517,7 @@
                 if (mFillWindow != null) {
                     if (DEBUG) Log.d(TAG, "destroying window");
                     mFillWindow.destroy();
+                    mFillWindow = null;
                 }
             }
         }
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/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 1d89628..140c34f 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -51,7 +51,7 @@
         DEFAULT_FLAGS.put("settings_slice_injection", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
         DEFAULT_FLAGS.put("settings_wifi_mac_randomization", "true");
-        DEFAULT_FLAGS.put("settings_mainline_module", "false");
+        DEFAULT_FLAGS.put("settings_mainline_module", "true");
         DEFAULT_FLAGS.put("settings_dynamic_android", "false");
         DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
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..16f6c1d 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()) {
@@ -5163,11 +5277,8 @@
         protected int onProcess(QueuedInputEvent q) {
             if (q.mEvent instanceof KeyEvent) {
                 return processKeyEvent(q);
-            } else {
-                final int source = q.mEvent.getSource();
-                if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
-                    return processPointerEvent(q);
-                }
+            } else if (q.mEvent instanceof MotionEvent) {
+                return processMotionEvent(q);
             }
             return FORWARD;
         }
@@ -5191,6 +5302,23 @@
             return FORWARD;
         }
 
+        private int processMotionEvent(QueuedInputEvent q) {
+            final MotionEvent event = (MotionEvent) q.mEvent;
+
+            if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
+                return processPointerEvent(q);
+            }
+
+            // If the motion event is from an absolute position device, exit touch mode
+            final int action = event.getActionMasked();
+            if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
+                if (event.isFromSource(InputDevice.SOURCE_CLASS_POSITION)) {
+                    ensureTouchMode(false);
+                }
+            }
+            return FORWARD;
+        }
+
         private int processPointerEvent(QueuedInputEvent q) {
             final MotionEvent event = (MotionEvent)q.mEvent;
 
@@ -5523,6 +5651,12 @@
         private int processGenericMotionEvent(QueuedInputEvent q) {
             final MotionEvent event = (MotionEvent)q.mEvent;
 
+            if (event.isFromSource(InputDevice.SOURCE_TOUCHPAD)) {
+                if (hasPointerCapture() && mView.dispatchCapturedPointerEvent(event)) {
+                    return FINISH_HANDLED;
+                }
+            }
+
             // Deliver the event to the view.
             if (mView.dispatchGenericMotionEvent(event)) {
                 return FINISH_HANDLED;
@@ -7093,7 +7227,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..70fe230 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;
@@ -370,6 +371,24 @@
     public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES =
             "smart_suggestion_supported_modes";
 
+    /**
+     * Sets how long (in ms) the augmented autofill service is bound while idle.
+     *
+     * <p>Use {@code 0} to keep it permanently bound.
+     *
+     * @hide
+     */
+    public static final String DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT =
+            "augmented_service_idle_unbind_timeout";
+
+    /**
+     * Sets how long (in ms) the augmented autofill service request is killed if not replied.
+     *
+     * @hide
+     */
+    public static final String DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT =
+            "augmented_service_request_timeout";
+
     /** @hide */
     public static final int RESULT_OK = 0;
     /** @hide */
@@ -467,6 +486,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 +1652,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 +1892,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 +2410,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/view/textclassifier/ActionsSuggestionsHelper.java b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
index 4d917a1..efdc968 100644
--- a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
+++ b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
@@ -16,6 +16,7 @@
 
 package android.view.textclassifier;
 
+import android.annotation.Nullable;
 import android.app.Person;
 import android.content.Context;
 import android.text.TextUtils;
@@ -110,6 +111,19 @@
                 SelectionSessionLogger.CLASSIFIER_ID, modelName, hash);
     }
 
+    /**
+     * Returns a {@link android.view.textclassifier.LabeledIntent.TitleChooser} for
+     * conversation actions use case.
+     */
+    @Nullable
+    public static LabeledIntent.TitleChooser createTitleChooser(String actionType) {
+        if (ConversationAction.TYPE_OPEN_URL.equals(actionType)) {
+            return (labeledIntent, resolveInfo) -> resolveInfo.handleAllWebDataURI
+                    ? labeledIntent.titleWithEntity : labeledIntent.titleWithoutEntity;
+        }
+        return null;
+    }
+
     private static final class PersonEncoder {
         private final Map<Person, Integer> mMapping = new ArrayMap<>();
         private int mNextUserId = FIRST_NON_LOCAL_USER;
diff --git a/core/java/android/view/textclassifier/IntentFactory.java b/core/java/android/view/textclassifier/IntentFactory.java
index 9f3b97f..722c812 100644
--- a/core/java/android/view/textclassifier/IntentFactory.java
+++ b/core/java/android/view/textclassifier/IntentFactory.java
@@ -32,7 +32,7 @@
     /**
      * Return a list of LabeledIntent from the classification result.
      */
-    List<TextClassifierImpl.LabeledIntent> create(
+    List<LabeledIntent> create(
             Context context,
             String text,
             boolean foreignText,
@@ -43,9 +43,10 @@
      * Inserts translate action to the list if it is a foreign text.
      */
     static void insertTranslateAction(
-            List<TextClassifierImpl.LabeledIntent> actions, Context context, String text) {
-        actions.add(new TextClassifierImpl.LabeledIntent(
+            List<LabeledIntent> actions, Context context, String text) {
+        actions.add(new LabeledIntent(
                 context.getString(com.android.internal.R.string.translate),
+                /* titleWithEntity */ null,
                 context.getString(com.android.internal.R.string.translate_desc),
                 new Intent(Intent.ACTION_TRANSLATE)
                         // TODO: Probably better to introduce a "translate" scheme instead of
diff --git a/core/java/android/view/textclassifier/LabeledIntent.java b/core/java/android/view/textclassifier/LabeledIntent.java
new file mode 100644
index 0000000..7544dc1
--- /dev/null
+++ b/core/java/android/view/textclassifier/LabeledIntent.java
@@ -0,0 +1,157 @@
+/*
+ * 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.view.textclassifier;
+
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.app.RemoteAction;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Icon;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Helper class to store the information from which RemoteActions are built.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public final class LabeledIntent {
+    private static final String TAG = "LabeledIntent";
+    public static final int DEFAULT_REQUEST_CODE = 0;
+    private static final TitleChooser DEFAULT_TITLE_CHOOSER =
+            (labeledIntent, resolveInfo) -> {
+                if (!TextUtils.isEmpty(labeledIntent.titleWithEntity)) {
+                    return labeledIntent.titleWithEntity;
+                }
+                return labeledIntent.titleWithoutEntity;
+            };
+
+    @Nullable
+    public final String titleWithoutEntity;
+    @Nullable
+    public final String titleWithEntity;
+    public final String description;
+    // Do not update this intent.
+    public final Intent intent;
+    public final int requestCode;
+
+    /**
+     * Initializes a LabeledIntent.
+     *
+     * <p>NOTE: {@code requestCode} is required to not be {@link #DEFAULT_REQUEST_CODE}
+     * if distinguishing info (e.g. the classified text) is represented in intent extras only.
+     * In such circumstances, the request code should represent the distinguishing info
+     * (e.g. by generating a hashcode) so that the generated PendingIntent is (somewhat)
+     * unique. To be correct, the PendingIntent should be definitely unique but we try a
+     * best effort approach that avoids spamming the system with PendingIntents.
+     */
+    // TODO: Fix the issue mentioned above so the behaviour is correct.
+    public LabeledIntent(
+            @Nullable String titleWithoutEntity,
+            @Nullable String titleWithEntity,
+            String description,
+            Intent intent,
+            int requestCode) {
+        if (TextUtils.isEmpty(titleWithEntity) && TextUtils.isEmpty(titleWithoutEntity)) {
+            throw new IllegalArgumentException(
+                    "titleWithEntity and titleWithoutEntity should not be both null");
+        }
+        this.titleWithoutEntity = titleWithoutEntity;
+        this.titleWithEntity = titleWithEntity;
+        this.description = Preconditions.checkNotNull(description);
+        this.intent = Preconditions.checkNotNull(intent);
+        this.requestCode = requestCode;
+    }
+
+    /**
+     * Return the resolved result.
+     */
+    @Nullable
+    public Result resolve(
+            Context context, @Nullable TitleChooser titleChooser) {
+        final PackageManager pm = context.getPackageManager();
+        final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
+        final String packageName = resolveInfo != null && resolveInfo.activityInfo != null
+                ? resolveInfo.activityInfo.packageName : null;
+        Icon icon = null;
+        Intent resolvedIntent = new Intent(intent);
+        boolean shouldShowIcon = false;
+        if (packageName != null && !"android".equals(packageName)) {
+            // There is a default activity handling the intent.
+            resolvedIntent.setComponent(
+                    new ComponentName(packageName, resolveInfo.activityInfo.name));
+            if (resolveInfo.activityInfo.getIconResource() != 0) {
+                icon = Icon.createWithResource(
+                        packageName, resolveInfo.activityInfo.getIconResource());
+                shouldShowIcon = true;
+            }
+        }
+        if (icon == null) {
+            // RemoteAction requires that there be an icon.
+            icon = Icon.createWithResource("android",
+                    com.android.internal.R.drawable.ic_more_items);
+        }
+        final PendingIntent pendingIntent =
+                TextClassification.createPendingIntent(context, resolvedIntent, requestCode);
+        if (pendingIntent == null) {
+            return null;
+        }
+        if (titleChooser == null) {
+            titleChooser = DEFAULT_TITLE_CHOOSER;
+        }
+        CharSequence title = titleChooser.chooseTitle(this, resolveInfo);
+        if (TextUtils.isEmpty(title)) {
+            Log.w(TAG, "Custom titleChooser return null, fallback to the default titleChooser");
+            title = DEFAULT_TITLE_CHOOSER.chooseTitle(this, resolveInfo);
+        }
+        final RemoteAction action =
+                new RemoteAction(icon, title, description, pendingIntent);
+        action.setShouldShowIcon(shouldShowIcon);
+        return new Result(resolvedIntent, action);
+    }
+
+    /**
+     * Data class that holds the result.
+     */
+    public static final class Result {
+        public final Intent resolvedIntent;
+        public final RemoteAction remoteAction;
+
+        public Result(Intent resolvedIntent, RemoteAction remoteAction) {
+            this.resolvedIntent = Preconditions.checkNotNull(resolvedIntent);
+            this.remoteAction = Preconditions.checkNotNull(remoteAction);
+        }
+    }
+
+    /**
+     * An object to choose a title from resolved info.  If {@code null} is returned,
+     * {@link #titleWithEntity} will be used if it exists, {@link #titleWithoutEntity} otherwise.
+     */
+    public interface TitleChooser {
+        /**
+         * Picks a title from a {@link LabeledIntent} by looking into resolved info.
+         */
+        @Nullable
+        CharSequence chooseTitle(LabeledIntent labeledIntent, ResolveInfo resolveInfo);
+    }
+}
diff --git a/core/java/android/view/textclassifier/LegacyIntentFactory.java b/core/java/android/view/textclassifier/LegacyIntentFactory.java
index 2d0d032..ea9229d 100644
--- a/core/java/android/view/textclassifier/LegacyIntentFactory.java
+++ b/core/java/android/view/textclassifier/LegacyIntentFactory.java
@@ -29,7 +29,6 @@
 import android.provider.Browser;
 import android.provider.CalendarContract;
 import android.provider.ContactsContract;
-import android.view.textclassifier.TextClassifierImpl.LabeledIntent;
 
 import com.google.android.textclassifier.AnnotatorModel;
 
@@ -100,8 +99,7 @@
             IntentFactory.insertTranslateAction(actions, context, text);
         }
         actions.forEach(
-                action -> action.getIntent()
-                        .putExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, true));
+                action -> action.intent.putExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, true));
         return actions;
     }
 
@@ -110,12 +108,14 @@
         final List<LabeledIntent> actions = new ArrayList<>();
         actions.add(new LabeledIntent(
                 context.getString(com.android.internal.R.string.email),
+                /* titleWithEntity */ null,
                 context.getString(com.android.internal.R.string.email_desc),
                 new Intent(Intent.ACTION_SENDTO)
                         .setData(Uri.parse(String.format("mailto:%s", text))),
                 LabeledIntent.DEFAULT_REQUEST_CODE));
         actions.add(new LabeledIntent(
                 context.getString(com.android.internal.R.string.add_contact),
+                /* titleWithEntity */ null,
                 context.getString(com.android.internal.R.string.add_contact_desc),
                 new Intent(Intent.ACTION_INSERT_OR_EDIT)
                         .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
@@ -133,6 +133,7 @@
         if (!userRestrictions.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS, false)) {
             actions.add(new LabeledIntent(
                     context.getString(com.android.internal.R.string.dial),
+                    /* titleWithEntity */ null,
                     context.getString(com.android.internal.R.string.dial_desc),
                     new Intent(Intent.ACTION_DIAL).setData(
                             Uri.parse(String.format("tel:%s", text))),
@@ -140,6 +141,7 @@
         }
         actions.add(new LabeledIntent(
                 context.getString(com.android.internal.R.string.add_contact),
+                /* titleWithEntity */ null,
                 context.getString(com.android.internal.R.string.add_contact_desc),
                 new Intent(Intent.ACTION_INSERT_OR_EDIT)
                         .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
@@ -148,6 +150,7 @@
         if (!userRestrictions.getBoolean(UserManager.DISALLOW_SMS, false)) {
             actions.add(new LabeledIntent(
                     context.getString(com.android.internal.R.string.sms),
+                    /* titleWithEntity */ null,
                     context.getString(com.android.internal.R.string.sms_desc),
                     new Intent(Intent.ACTION_SENDTO)
                             .setData(Uri.parse(String.format("smsto:%s", text))),
@@ -163,6 +166,7 @@
             final String encText = URLEncoder.encode(text, "UTF-8");
             actions.add(new LabeledIntent(
                     context.getString(com.android.internal.R.string.map),
+                    /* titleWithEntity */ null,
                     context.getString(com.android.internal.R.string.map_desc),
                     new Intent(Intent.ACTION_VIEW)
                             .setData(Uri.parse(String.format("geo:0,0?q=%s", encText))),
@@ -181,6 +185,7 @@
         final List<LabeledIntent> actions = new ArrayList<>();
         actions.add(new LabeledIntent(
                 context.getString(com.android.internal.R.string.browse),
+                /* titleWithEntity */ null,
                 context.getString(com.android.internal.R.string.browse_desc),
                 new Intent(Intent.ACTION_VIEW)
                         .setDataAndNormalize(Uri.parse(text))
@@ -211,6 +216,7 @@
         final List<LabeledIntent> actions = new ArrayList<>();
         actions.add(new LabeledIntent(
                 context.getString(com.android.internal.R.string.view_flight),
+                /* titleWithEntity */ null,
                 context.getString(com.android.internal.R.string.view_flight_desc),
                 new Intent(Intent.ACTION_WEB_SEARCH)
                         .putExtra(SearchManager.QUERY, text),
@@ -225,6 +231,7 @@
         ContentUris.appendId(builder, parsedTime.toEpochMilli());
         return new LabeledIntent(
                 context.getString(com.android.internal.R.string.view_calendar),
+                /* titleWithEntity */ null,
                 context.getString(com.android.internal.R.string.view_calendar_desc),
                 new Intent(Intent.ACTION_VIEW).setData(builder.build()),
                 LabeledIntent.DEFAULT_REQUEST_CODE);
@@ -236,6 +243,7 @@
         final boolean isAllDay = TextClassifier.TYPE_DATE.equals(type);
         return new LabeledIntent(
                 context.getString(com.android.internal.R.string.add_calendar_event),
+                /* titleWithEntity */ null,
                 context.getString(com.android.internal.R.string.add_calendar_event_desc),
                 new Intent(Intent.ACTION_INSERT)
                         .setData(CalendarContract.Events.CONTENT_URI)
@@ -252,6 +260,7 @@
         final List<LabeledIntent> actions = new ArrayList<>();
         actions.add(new LabeledIntent(
                 context.getString(com.android.internal.R.string.define),
+                /* titleWithEntity */ null,
                 context.getString(com.android.internal.R.string.define_desc),
                 new Intent(Intent.ACTION_DEFINE)
                         .putExtra(Intent.EXTRA_TEXT, text),
diff --git a/core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java b/core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java
index 2467802..ed0259f 100644
--- a/core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java
+++ b/core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java
@@ -48,12 +48,12 @@
     }
 
     /**
-     * Returns a list of {@link android.view.textclassifier.TextClassifierImpl.LabeledIntent}
+     * Returns a list of {@link android.view.textclassifier.LabeledIntent}
      * that are constructed from the classification result.
      */
     @NonNull
     @Override
-    public List<TextClassifierImpl.LabeledIntent> create(
+    public List<LabeledIntent> create(
             Context context,
             String text,
             boolean foreignText,
@@ -68,7 +68,7 @@
             Log.w(TAG, "RemoteActionTemplate is missing, fallback to LegacyIntentFactory.");
             return mFallback.create(context, text, foreignText, referenceTime, classification);
         }
-        final List<TextClassifierImpl.LabeledIntent> labeledIntents =
+        final List<LabeledIntent> labeledIntents =
                 mTemplateIntentFactory.create(remoteActionTemplates);
         if (foreignText) {
             IntentFactory.insertTranslateAction(labeledIntents, context, text.trim());
diff --git a/core/java/android/view/textclassifier/TemplateIntentFactory.java b/core/java/android/view/textclassifier/TemplateIntentFactory.java
index 95f88c7..0696d98 100644
--- a/core/java/android/view/textclassifier/TemplateIntentFactory.java
+++ b/core/java/android/view/textclassifier/TemplateIntentFactory.java
@@ -42,29 +42,29 @@
     private static final String TAG = TextClassifier.DEFAULT_LOG_TAG;
 
     @NonNull
-    public List<TextClassifierImpl.LabeledIntent> create(
+    public List<LabeledIntent> create(
             @Nullable RemoteActionTemplate[] remoteActionTemplates) {
         if (ArrayUtils.isEmpty(remoteActionTemplates)) {
             return Collections.emptyList();
         }
-        final List<TextClassifierImpl.LabeledIntent> labeledIntents = new ArrayList<>();
+        final List<LabeledIntent> labeledIntents = new ArrayList<>();
         for (RemoteActionTemplate remoteActionTemplate : remoteActionTemplates) {
             if (!isValidTemplate(remoteActionTemplate)) {
                 Log.w(TAG, "Invalid RemoteActionTemplate skipped.");
                 continue;
             }
             labeledIntents.add(
-                    new TextClassifierImpl.LabeledIntent(
-                            remoteActionTemplate.title,
+                    new LabeledIntent(
+                            remoteActionTemplate.titleWithoutEntity,
+                            remoteActionTemplate.titleWithEntity,
                             remoteActionTemplate.description,
                             createIntent(remoteActionTemplate),
                             remoteActionTemplate.requestCode == null
-                                    ? TextClassifierImpl.LabeledIntent.DEFAULT_REQUEST_CODE
+                                    ? LabeledIntent.DEFAULT_REQUEST_CODE
                                     : remoteActionTemplate.requestCode));
         }
         labeledIntents.forEach(
-                action -> action.getIntent()
-                        .putExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, true));
+                action -> action.intent.putExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, true));
         return labeledIntents;
     }
 
@@ -73,7 +73,8 @@
             Log.w(TAG, "Invalid RemoteActionTemplate: is null");
             return false;
         }
-        if (TextUtils.isEmpty(remoteActionTemplate.title)) {
+        if (TextUtils.isEmpty(remoteActionTemplate.titleWithEntity)
+                && TextUtils.isEmpty(remoteActionTemplate.titleWithoutEntity)) {
             Log.w(TAG, "Invalid RemoteActionTemplate: title is null");
             return false;
         }
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index e628f19..632328b 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -19,21 +19,14 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.WorkerThread;
-import android.app.PendingIntent;
 import android.app.RemoteAction;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.drawable.Icon;
 import android.icu.util.ULocale;
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.ParcelFileDescriptor;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 
@@ -430,7 +423,12 @@
             // Given that we only support implicit intent here, we should expect there is just one
             // intent for each action type.
             if (!labeledIntents.isEmpty()) {
-                remoteAction = labeledIntents.get(0).asRemoteAction(mContext);
+                LabeledIntent.TitleChooser titleChooser =
+                        ActionsSuggestionsHelper.createTitleChooser(actionType);
+                LabeledIntent.Result result = labeledIntents.get(0).resolve(mContext, titleChooser);
+                if (result != null) {
+                    remoteAction = result.remoteAction;
+                }
             }
             conversationActions.add(
                     new ConversationAction.Builder(actionType)
@@ -593,23 +591,26 @@
                 foreignLanguageBundle != null,
                 referenceTime,
                 highestScoringResult);
+        LabeledIntent.TitleChooser titleChooser =
+                (labeledIntent, resolveInfo) -> labeledIntent.titleWithoutEntity;
         for (LabeledIntent labeledIntent : labeledIntents) {
-            final RemoteAction action = labeledIntent.asRemoteAction(mContext);
-            if (action == null) {
+            LabeledIntent.Result result = labeledIntent.resolve(mContext, titleChooser);
+            if (result == null) {
                 continue;
             }
+            final RemoteAction action = result.remoteAction;
             if (isPrimaryAction) {
                 // For O backwards compatibility, the first RemoteAction is also written to the
                 // legacy API fields.
                 builder.setIcon(action.getIcon().loadDrawable(mContext));
                 builder.setLabel(action.getTitle().toString());
-                builder.setIntent(labeledIntent.getIntent());
+                builder.setIntent(result.resolvedIntent);
                 builder.setOnClickListener(TextClassification.createIntentOnClickListener(
                         TextClassification.createPendingIntent(mContext,
-                                labeledIntent.getIntent(), labeledIntent.getRequestCode())));
+                                result.resolvedIntent, labeledIntent.requestCode)));
                 isPrimaryAction = false;
             }
-            builder.addAction(action, labeledIntent.getIntent());
+            builder.addAction(action, result.resolvedIntent);
         }
 
         return builder.setId(createId(text, start, end)).build();
@@ -737,89 +738,5 @@
             return LocaleList.getDefault().get(0).toLanguageTag();
         }
     }
-
-    /**
-     * Helper class to store the information from which RemoteActions are built.
-     */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
-    public static final class LabeledIntent {
-
-        static final int DEFAULT_REQUEST_CODE = 0;
-
-        private final String mTitle;
-        private final String mDescription;
-        private final Intent mIntent;
-        private final int mRequestCode;
-
-        /**
-         * Initializes a LabeledIntent.
-         *
-         * <p>NOTE: {@code reqestCode} is required to not be {@link #DEFAULT_REQUEST_CODE}
-         * if distinguishing info (e.g. the classified text) is represented in intent extras only.
-         * In such circumstances, the request code should represent the distinguishing info
-         * (e.g. by generating a hashcode) so that the generated PendingIntent is (somewhat)
-         * unique. To be correct, the PendingIntent should be definitely unique but we try a
-         * best effort approach that avoids spamming the system with PendingIntents.
-         */
-        // TODO: Fix the issue mentioned above so the behaviour is correct.
-        LabeledIntent(String title, String description, Intent intent, int requestCode) {
-            mTitle = title;
-            mDescription = description;
-            mIntent = intent;
-            mRequestCode = requestCode;
-        }
-
-        @VisibleForTesting
-        public String getTitle() {
-            return mTitle;
-        }
-
-        @VisibleForTesting
-        public String getDescription() {
-            return mDescription;
-        }
-
-        @VisibleForTesting
-        public Intent getIntent() {
-            return mIntent;
-        }
-
-        @VisibleForTesting
-        public int getRequestCode() {
-            return mRequestCode;
-        }
-
-        @Nullable
-        RemoteAction asRemoteAction(Context context) {
-            final PackageManager pm = context.getPackageManager();
-            final ResolveInfo resolveInfo = pm.resolveActivity(mIntent, 0);
-            final String packageName = resolveInfo != null && resolveInfo.activityInfo != null
-                    ? resolveInfo.activityInfo.packageName : null;
-            Icon icon = null;
-            boolean shouldShowIcon = false;
-            if (packageName != null && !"android".equals(packageName)) {
-                // There is a default activity handling the intent.
-                mIntent.setComponent(new ComponentName(packageName, resolveInfo.activityInfo.name));
-                if (resolveInfo.activityInfo.getIconResource() != 0) {
-                    icon = Icon.createWithResource(
-                            packageName, resolveInfo.activityInfo.getIconResource());
-                    shouldShowIcon = true;
-                }
-            }
-            if (icon == null) {
-                // RemoteAction requires that there be an icon.
-                icon = Icon.createWithResource("android",
-                        com.android.internal.R.drawable.ic_more_items);
-            }
-            final PendingIntent pendingIntent =
-                    TextClassification.createPendingIntent(context, mIntent, mRequestCode);
-            if (pendingIntent == null) {
-                return null;
-            }
-            final RemoteAction action = new RemoteAction(icon, mTitle, mDescription, pendingIntent);
-            action.setShouldShowIcon(shouldShowIcon);
-            return action;
-        }
-    }
 }
 
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/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
index e19a32e..87e048c 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -86,6 +86,10 @@
                 && wakeScreenGestureAvailable();
     }
 
+    public long getWakeLockScreenDebounce() {
+        return mContext.getResources().getInteger(R.integer.config_dozeWakeLockScreenDebounce);
+    }
+
     public String doubleTapSensorType() {
         return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType);
     }
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/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 0938e56..16517bf 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -244,6 +244,11 @@
 // Copying (CC) garbage collector.
 static const char* kNoGenerationalCCRuntimeOption = "-Xgc:nogenerational_cc";
 
+// Feature flag name for running the JIT in Zygote experiment, b/119800099.
+static const char* ENABLE_APEX_IMAGE = "enable_apex_image";
+// Flag to pass to the runtime when using the apex image.
+static const char* kApexImageOption = "-Ximage:/system/framework/apex.art";
+
 static AndroidRuntime* gCurRuntime = NULL;
 
 /*
@@ -678,8 +683,17 @@
     char jdwpProviderBuf[sizeof("-XjdwpProvider:") - 1 + PROPERTY_VALUE_MAX];
     char bootImageBuf[sizeof("-Ximage:") - 1 + PROPERTY_VALUE_MAX];
 
-    if (parseRuntimeOption("dalvik.vm.boot-image", bootImageBuf, "-Ximage:")) {
-        ALOGI("Boot image: '%s'\n", bootImageBuf);
+    std::string use_apex_image =
+        server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
+                                                             ENABLE_APEX_IMAGE,
+                                                             /*default_value=*/ "");
+    if (use_apex_image == "true") {
+        addOption(kApexImageOption);
+        ALOGI("Using Apex boot image: '%s'\n", kApexImageOption);
+    } else if (parseRuntimeOption("dalvik.vm.boot-image", bootImageBuf, "-Ximage:")) {
+        ALOGI("Using dalvik.vm.boot-image: '%s'\n", bootImageBuf);
+    } else {
+        ALOGI("Using default boot image");
     }
 
     bool checkJni = false;
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/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index f74fc21..e48bcf6 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -615,6 +615,23 @@
     // CATEGORY: SETTINGS
     // OS: Q
     ACTION_PANEL_INTERACTION = 1658;
+
+    // ACTION: Show Contextual homepage, log latency in loading cards
+    ACTION_CONTEXTUAL_HOME_SHOW = 1662;
+
+    // ACTION: Contextual card displays
+    ACTION_CONTEXTUAL_CARD_SHOW = 1663;
+
+    // ACTION: Contextual cards are eligible to be shown, but don't rank high
+    ACTION_CONTEXTUAL_CARD_NOT_SHOW = 1664;
+
+    // ACTION: Settings > long press a card, and click dismiss
+    // Contextual card is dismissed
+    ACTION_CONTEXTUAL_CARD_DISMISS = 1665;
+
+    // ACTION: Settings > click a card
+    // Contextual card is clicked
+    ACTION_CONTEXTUAL_CARD_CLICK = 1666;
 }
 
 /**
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..0041bfc 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2272,6 +2272,7 @@
 
     <!-- If the sensor that wakes up the lock screen is available or not. -->
     <bool name="config_dozeWakeLockScreenSensorAvailable">false</bool>
+    <integer name="config_dozeWakeLockScreenDebounce">3000</integer>
 
     <!-- Control whether the always on display mode is available. This should only be enabled on
          devices where the display has been tuned to be power efficient in DOZE and/or DOZE_SUSPEND
@@ -3363,6 +3364,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/symbols.xml b/core/res/res/values/symbols.xml
index 8df0e19..be7aaa4 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" />
 
@@ -3403,6 +3404,7 @@
 
   <java-symbol type="string" name="config_dozeLongPressSensorType" />
   <java-symbol type="bool" name="config_dozeWakeLockScreenSensorAvailable" />
+  <java-symbol type="integer" name="config_dozeWakeLockScreenDebounce" />
 
   <java-symbol type="array" name="config_allowedGlobalInstantAppSettings" />
   <java-symbol type="array" name="config_allowedSystemInstantAppSettings" />
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
new file mode 100644
index 0000000..833c734
--- /dev/null
+++ b/core/tests/coretests/Android.bp
@@ -0,0 +1,113 @@
+android_test {
+    name: "FrameworksCoreTests",
+
+    srcs: [
+        "src/**/*.java",
+        "src/**/I*.aidl",
+        "DisabledTestApp/src/**/*.java",
+        "EnabledTestApp/src/**/*.java",
+        "BinderProxyCountingTestApp/src/**/*.java",
+        "BinderProxyCountingTestService/src/**/*.java",
+        "aidl/**/I*.aidl",
+    ],
+
+    aidl: {
+        local_include_dirs: ["aidl"],
+    },
+
+    dxflags: ["--core-library"],
+
+    aaptflags: [
+        "-0 .dat",
+        "-0 .gld",
+        "-c fa",
+    ],
+    static_libs: [
+        "frameworks-base-testutils",
+        "core-tests-support",
+        "android-common",
+        "frameworks-core-util-lib",
+        "mockwebserver",
+        "guava",
+        "androidx.test.espresso.core",
+        "androidx.test.ext.junit",
+        "androidx.test.runner",
+        "androidx.test.rules",
+        "mockito-target-minus-junit4",
+        "ub-uiautomator",
+        "platform-test-annotations",
+        "truth-prebuilt",
+        "print-test-util-lib",
+        "testng",
+    ],
+
+    libs: [
+        "android.test.runner",
+        "telephony-common",
+        "testables",
+        "org.apache.http.legacy",
+        "android.test.base",
+        "android.test.mock",
+        "framework-atb-backward-compatibility",
+    ],
+
+    platform_apis: true,
+    test_suites: ["device-tests"],
+
+    certificate: "platform",
+
+    resource_dirs: ["res"],
+    resource_zips: [":FrameworksCoreTests_apks_as_resources"],
+}
+
+// Rules to copy all the test apks to the intermediate raw resource directory
+java_genrule {
+    name: "FrameworksCoreTests_apks_as_resources",
+    srcs: [
+        ":FrameworksCoreTests_install",
+        ":FrameworksCoreTests_install_bad_dex",
+        ":FrameworksCoreTests_install_complete_package_info",
+        ":FrameworksCoreTests_install_decl_perm",
+        ":FrameworksCoreTests_install_jni_lib_open_from_apk",
+        ":FrameworksCoreTests_install_loc_auto",
+        ":FrameworksCoreTests_install_loc_internal",
+        ":FrameworksCoreTests_install_loc_sdcard",
+        ":FrameworksCoreTests_install_loc_unspecified",
+        ":FrameworksCoreTests_install_multi_package",
+        ":FrameworksCoreTests_install_split_base",
+        ":FrameworksCoreTests_install_split_feature_a",
+        ":FrameworksCoreTests_install_use_perm_good",
+        ":FrameworksCoreTests_install_uses_feature",
+        ":FrameworksCoreTests_install_verifier_bad",
+        ":FrameworksCoreTests_install_verifier_good",
+        ":FrameworksCoreTests_keyset_permdef_sa_unone",
+        ":FrameworksCoreTests_keyset_permuse_sa_ua_ub",
+        ":FrameworksCoreTests_keyset_permuse_sb_ua_ub",
+        ":FrameworksCoreTests_keyset_sab_ua",
+        ":FrameworksCoreTests_keyset_sa_ua",
+        ":FrameworksCoreTests_keyset_sa_uab",
+        ":FrameworksCoreTests_keyset_sa_ua_ub",
+        ":FrameworksCoreTests_keyset_sa_ub",
+        ":FrameworksCoreTests_keyset_sa_unone",
+        ":FrameworksCoreTests_keyset_sau_ub",
+        ":FrameworksCoreTests_keyset_sb_ua",
+        ":FrameworksCoreTests_keyset_sb_ub",
+        ":FrameworksCoreTests_keyset_splata_api",
+        ":FrameworksCoreTests_keyset_splat_api",
+        ":FrameworksCoreTests_locales",
+        ":FrameworksCoreTests_version_1",
+        ":FrameworksCoreTests_version_1_diff",
+        ":FrameworksCoreTests_version_1_nosys",
+        ":FrameworksCoreTests_version_2",
+        ":FrameworksCoreTests_version_2_diff",
+        ":FrameworksCoreTests_version_3",
+    ],
+    out: ["FrameworkCoreTests_apks_as_resources.res.zip"],
+    tools: ["soong_zip"],
+
+    cmd: "mkdir -p $(genDir)/res/raw && " +
+        "for i in $(in); do " +
+        "  x=$${i##*FrameworksCoreTests_}; echo $${x}; cp $$i $(genDir)/res/raw/$${x%.apk};" +
+        "done && " +
+        "$(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res",
+}
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
deleted file mode 100644
index 40ebd44..0000000
--- a/core/tests/coretests/Android.mk
+++ /dev/null
@@ -1,85 +0,0 @@
-ACTUAL_LOCAL_PATH := $(call my-dir)
-
-# this var will hold all the test apk module names later.
-FrameworkCoreTests_all_apks :=
-
-# We have to include the subdir makefiles first
-# so that FrameworkCoreTests_all_apks will be populated correctly.
-include $(call all-makefiles-under,$(ACTUAL_LOCAL_PATH))
-
-LOCAL_PATH := $(ACTUAL_LOCAL_PATH)
-
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
-	$(call all-java-files-under, src) \
-	$(call all-Iaidl-files-under, src) \
-	$(call all-java-files-under, DisabledTestApp/src) \
-	$(call all-java-files-under, EnabledTestApp/src) \
-	$(call all-java-files-under, BinderProxyCountingTestApp/src) \
-	$(call all-java-files-under, BinderProxyCountingTestService/src) \
-	$(call all-Iaidl-files-under, aidl)
-
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
-
-LOCAL_DX_FLAGS := --core-library
-LOCAL_JACK_FLAGS := --multi-dex native
-LOCAL_AAPT_FLAGS = -0 dat -0 gld -c fa
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    frameworks-base-testutils \
-    core-tests-support \
-    android-common \
-    frameworks-core-util-lib \
-    mockwebserver \
-    guava \
-    androidx.test.espresso.core \
-    androidx.test.ext.junit \
-    androidx.test.runner \
-    androidx.test.rules \
-    mockito-target-minus-junit4 \
-    ub-uiautomator \
-    platform-test-annotations \
-    truth-prebuilt \
-    print-test-util-lib \
-    testng # TODO: remove once Android migrates to JUnit 4.12, which provide assertThrows
-
-LOCAL_JAVA_LIBRARIES := \
-    android.test.runner \
-    telephony-common \
-    testables \
-    org.apache.http.legacy \
-    android.test.base \
-    android.test.mock \
-    framework-atb-backward-compatibility \
-
-LOCAL_PACKAGE_NAME := FrameworksCoreTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_CERTIFICATE := platform
-
-# intermediate dir to include all the test apks as raw resource
-FrameworkCoreTests_intermediates := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME))/test_apks/res
-LOCAL_RESOURCE_DIR := $(FrameworkCoreTests_intermediates) $(LOCAL_PATH)/res
-
-# Disable AAPT2 because the hacks below depend on the AAPT rules implementation
-LOCAL_USE_AAPT2 := false
-
-include $(BUILD_PACKAGE)
-# Rules to copy all the test apks to the intermediate raw resource directory
-FrameworkCoreTests_all_apks_res := $(addprefix $(FrameworkCoreTests_intermediates)/raw/, \
-    $(foreach a, $(FrameworkCoreTests_all_apks), $(patsubst FrameworkCoreTests_%,%,$(a))))
-
-$(FrameworkCoreTests_all_apks_res): $(FrameworkCoreTests_intermediates)/raw/%: $(call intermediates-dir-for,APPS,FrameworkCoreTests_%)/package.apk
-	$(call copy-file-to-new-target)
-
-# Use R_file_stamp as dependency because we want the test apks in place before the R.java is generated.
-$(R_file_stamp) : $(FrameworkCoreTests_all_apks_res)
-
-FrameworkCoreTests_all_apks :=
-FrameworkCoreTests_intermediates :=
-FrameworkCoreTests_all_apks_res :=
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/Android.bp b/core/tests/coretests/BinderProxyCountingTestApp/Android.bp
new file mode 100644
index 0000000..6279a48
--- /dev/null
+++ b/core/tests/coretests/BinderProxyCountingTestApp/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+    name: "BinderProxyCountingTestApp",
+
+    static_libs: ["coretests-aidl"],
+    srcs: ["**/*.java"],
+
+    sdk_version: "current",
+    certificate: "platform",
+
+    test_suites: ["device-tests"],
+}
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk b/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
deleted file mode 100644
index 4642694..0000000
--- a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := BinderProxyCountingTestApp
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-include $(BUILD_PACKAGE)
-
diff --git a/core/tests/coretests/BinderProxyCountingTestService/Android.bp b/core/tests/coretests/BinderProxyCountingTestService/Android.bp
new file mode 100644
index 0000000..22718cb
--- /dev/null
+++ b/core/tests/coretests/BinderProxyCountingTestService/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+    name: "BinderProxyCountingTestService",
+
+    static_libs: ["coretests-aidl"],
+    srcs: ["**/*.java"],
+
+    platform_apis: true,
+    certificate: "platform",
+
+    test_suites: ["device-tests"],
+}
diff --git a/core/tests/coretests/BinderProxyCountingTestService/Android.mk b/core/tests/coretests/BinderProxyCountingTestService/Android.mk
deleted file mode 100644
index f852c7a..0000000
--- a/core/tests/coretests/BinderProxyCountingTestService/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := BinderProxyCountingTestService
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-include $(BUILD_PACKAGE)
-
diff --git a/core/tests/coretests/BstatsTestApp/Android.bp b/core/tests/coretests/BstatsTestApp/Android.bp
new file mode 100644
index 0000000..424c71a
--- /dev/null
+++ b/core/tests/coretests/BstatsTestApp/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+    name: "BstatsTestApp",
+
+    test_suites: [
+        "device-tests",
+    ],
+
+    static_libs: ["coretests-aidl"],
+
+    srcs: ["**/*.java"],
+
+    sdk_version: "current",
+    certificate: "platform",
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+}
diff --git a/core/tests/coretests/BstatsTestApp/Android.mk b/core/tests/coretests/BstatsTestApp/Android.mk
deleted file mode 100644
index a5872a5..0000000
--- a/core/tests/coretests/BstatsTestApp/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := BstatsTestApp
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-LOCAL_DEX_PREOPT := false
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/DisabledTestApp/Android.bp b/core/tests/coretests/DisabledTestApp/Android.bp
new file mode 100644
index 0000000..419816e
--- /dev/null
+++ b/core/tests/coretests/DisabledTestApp/Android.bp
@@ -0,0 +1,8 @@
+android_test_helper_app {
+    name: "DisabledTestApp",
+
+    srcs: ["**/*.java"],
+
+    sdk_version: "current",
+    certificate: "platform",
+}
diff --git a/core/tests/coretests/DisabledTestApp/Android.mk b/core/tests/coretests/DisabledTestApp/Android.mk
deleted file mode 100644
index e4304f7..0000000
--- a/core/tests/coretests/DisabledTestApp/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := DisabledTestApp
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
-
diff --git a/core/tests/coretests/EnabledTestApp/Android.bp b/core/tests/coretests/EnabledTestApp/Android.bp
new file mode 100644
index 0000000..bc4f4bd
--- /dev/null
+++ b/core/tests/coretests/EnabledTestApp/Android.bp
@@ -0,0 +1,8 @@
+android_test_helper_app {
+    name: "EnabledTestApp",
+
+    srcs: ["**/*.java"],
+
+    sdk_version: "current",
+    certificate: "platform",
+}
diff --git a/core/tests/coretests/EnabledTestApp/Android.mk b/core/tests/coretests/EnabledTestApp/Android.mk
deleted file mode 100644
index cd37f08..0000000
--- a/core/tests/coretests/EnabledTestApp/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := EnabledTestApp
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
-
diff --git a/core/tests/coretests/aidl/Android.bp b/core/tests/coretests/aidl/Android.bp
new file mode 100644
index 0000000..6e442db
--- /dev/null
+++ b/core/tests/coretests/aidl/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_test {
+    name: "coretests-aidl",
+    sdk_version: "current",
+    srcs: ["**/*.aidl"],
+}
diff --git a/core/tests/coretests/aidl/Android.mk b/core/tests/coretests/aidl/Android.mk
deleted file mode 100644
index 86e36b6..0000000
--- a/core/tests/coretests/aidl/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := $(call all-subdir-Iaidl-files)
-LOCAL_MODULE := coretests-aidl
-include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/core/tests/coretests/apks/Android.bp b/core/tests/coretests/apks/Android.bp
new file mode 100644
index 0000000..20c87b2
--- /dev/null
+++ b/core/tests/coretests/apks/Android.bp
@@ -0,0 +1,7 @@
+java_defaults {
+    name: "FrameworksCoreTests_apks_defaults",
+    sdk_version: "current",
+
+    // Every package should have a native library
+    jni_libs: ["libframeworks_coretests_jni"],
+}
diff --git a/core/tests/coretests/apks/Android.mk b/core/tests/coretests/apks/Android.mk
deleted file mode 100644
index 98c0c2a..0000000
--- a/core/tests/coretests/apks/Android.mk
+++ /dev/null
@@ -1,7 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-FrameworkCoreTests_BUILD_PACKAGE := $(LOCAL_PATH)/FrameworkCoreTests_apk.mk
-
-# build sub packages
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk b/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
deleted file mode 100644
index 8a7d72a5..0000000
--- a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-
-LOCAL_MODULE_TAGS := tests
-
-# Disable dexpreopt.
-LOCAL_DEX_PREOPT := false
-
-# Make sure every package name gets the FrameworkCoreTests_ prefix.
-LOCAL_PACKAGE_NAME := FrameworkCoreTests_$(LOCAL_PACKAGE_NAME)
-LOCAL_SDK_VERSION := current
-
-# Every package should have a native library
-LOCAL_JNI_SHARED_LIBRARIES := libframeworks_coretests_jni
-
-FrameworkCoreTests_all_apks += $(LOCAL_PACKAGE_NAME)
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install-split-base/Android.bp b/core/tests/coretests/apks/install-split-base/Android.bp
new file mode 100644
index 0000000..ddf75b2
--- /dev/null
+++ b/core/tests/coretests/apks/install-split-base/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_split_base",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install-split-base/Android.mk b/core/tests/coretests/apks/install-split-base/Android.mk
deleted file mode 100644
index 5b60e31..0000000
--- a/core/tests/coretests/apks/install-split-base/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_split_base
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
\ No newline at end of file
diff --git a/core/tests/coretests/apks/install-split-feature-a/Android.bp b/core/tests/coretests/apks/install-split-feature-a/Android.bp
new file mode 100644
index 0000000..9ec9893
--- /dev/null
+++ b/core/tests/coretests/apks/install-split-feature-a/Android.bp
@@ -0,0 +1,11 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_split_feature_a",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+
+    aaptflags: [
+        "--custom-package com.google.android.dexapis.splitapp.feature_a",
+        "--package-id 0x80",
+    ],
+}
diff --git a/core/tests/coretests/apks/install-split-feature-a/Android.mk b/core/tests/coretests/apks/install-split-feature-a/Android.mk
deleted file mode 100644
index 0f37d16..0000000
--- a/core/tests/coretests/apks/install-split-feature-a/Android.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_split_feature_a
-
-LOCAL_USE_AAPT2 := true
-LOCAL_AAPT_FLAGS += --custom-package com.google.android.dexapis.splitapp.feature_a
-LOCAL_AAPT_FLAGS += --package-id 0x80
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
\ No newline at end of file
diff --git a/core/tests/coretests/apks/install/Android.bp b/core/tests/coretests/apks/install/Android.bp
new file mode 100644
index 0000000..e783fe2
--- /dev/null
+++ b/core/tests/coretests/apks/install/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install/Android.mk b/core/tests/coretests/apks/install/Android.mk
deleted file mode 100644
index b38dc20..0000000
--- a/core/tests/coretests/apks/install/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_bad_dex/Android.bp b/core/tests/coretests/apks/install_bad_dex/Android.bp
new file mode 100644
index 0000000..d156793
--- /dev/null
+++ b/core/tests/coretests/apks/install_bad_dex/Android.bp
@@ -0,0 +1,23 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_bad_dex_",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["src/**/*.java"],
+}
+
+// Inject bad classes.dex file.
+java_genrule {
+    name: "FrameworksCoreTests_install_bad_dex",
+    tools: [
+        "soong_zip",
+        "merge_zips",
+    ],
+    srcs: [
+        ":FrameworksCoreTests_install_bad_dex_",
+        "classes.dex",
+    ],
+    out: ["FrameworksCoreTests_install_bad_dex.apk"],
+    cmd: "$(location soong_zip) -o $(genDir)/classes.dex.zip -j -f $(location classes.dex) && " +
+        "$(location merge_zips) -ignore-duplicates $(out) $(genDir)/classes.dex.zip " +
+        "$(location :FrameworksCoreTests_install_bad_dex_)",
+}
diff --git a/core/tests/coretests/apks/install_bad_dex/Android.mk b/core/tests/coretests/apks/install_bad_dex/Android.mk
deleted file mode 100644
index 05983aa..0000000
--- a/core/tests/coretests/apks/install_bad_dex/Android.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_bad_dex
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-# Override target specific variable PRIVATE_DEX_FILE to inject bad classes.dex file.
-$(LOCAL_BUILT_MODULE): PRIVATE_DEX_FILE := $(LOCAL_PATH)/classes.dex
diff --git a/core/tests/coretests/apks/install_complete_package_info/Android.bp b/core/tests/coretests/apks/install_complete_package_info/Android.bp
new file mode 100644
index 0000000..123558bd
--- /dev/null
+++ b/core/tests/coretests/apks/install_complete_package_info/Android.bp
@@ -0,0 +1,7 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_complete_package_info",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
+
diff --git a/core/tests/coretests/apks/install_complete_package_info/Android.mk b/core/tests/coretests/apks/install_complete_package_info/Android.mk
deleted file mode 100644
index 19bf356..0000000
--- a/core/tests/coretests/apks/install_complete_package_info/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_complete_package_info
-#LOCAL_MANIFEST_FILE := api_test/AndroidManifest.xml
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-#include $(BUILD_PACKAGE)
-
diff --git a/core/tests/coretests/apks/install_decl_perm/Android.bp b/core/tests/coretests/apks/install_decl_perm/Android.bp
new file mode 100644
index 0000000..868e8b5
--- /dev/null
+++ b/core/tests/coretests/apks/install_decl_perm/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_decl_perm",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_decl_perm/Android.mk b/core/tests/coretests/apks/install_decl_perm/Android.mk
deleted file mode 100644
index 86370c8..0000000
--- a/core/tests/coretests/apks/install_decl_perm/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_decl_perm
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_jni_lib/Android.bp b/core/tests/coretests/apks/install_jni_lib/Android.bp
index c1a6bd0..f20f599 100644
--- a/core/tests/coretests/apks/install_jni_lib/Android.bp
+++ b/core/tests/coretests/apks/install_jni_lib/Android.bp
@@ -14,6 +14,7 @@
 
 cc_test_library {
     name: "libframeworks_coretests_jni",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
 
     srcs: ["com_android_frameworks_coretests_JNITest.cpp"],
 
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.bp b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.bp
new file mode 100644
index 0000000..602b704
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_jni_lib_open_from_apk",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk
deleted file mode 100644
index 6b3b55e..0000000
--- a/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_jni_lib_open_from_apk
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_loc_auto/Android.bp b/core/tests/coretests/apks/install_loc_auto/Android.bp
new file mode 100644
index 0000000..6393915
--- /dev/null
+++ b/core/tests/coretests/apks/install_loc_auto/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_loc_auto",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_loc_auto/Android.mk b/core/tests/coretests/apks/install_loc_auto/Android.mk
deleted file mode 100644
index 6435f36..0000000
--- a/core/tests/coretests/apks/install_loc_auto/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_loc_auto
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_loc_internal/Android.bp b/core/tests/coretests/apks/install_loc_internal/Android.bp
new file mode 100644
index 0000000..770aaa5
--- /dev/null
+++ b/core/tests/coretests/apks/install_loc_internal/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_loc_internal",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_loc_internal/Android.mk b/core/tests/coretests/apks/install_loc_internal/Android.mk
deleted file mode 100644
index 8cc8b8e..0000000
--- a/core/tests/coretests/apks/install_loc_internal/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_loc_internal
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_loc_sdcard/Android.bp b/core/tests/coretests/apks/install_loc_sdcard/Android.bp
new file mode 100644
index 0000000..1779401
--- /dev/null
+++ b/core/tests/coretests/apks/install_loc_sdcard/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_loc_sdcard",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_loc_sdcard/Android.mk b/core/tests/coretests/apks/install_loc_sdcard/Android.mk
deleted file mode 100644
index e1411c2..0000000
--- a/core/tests/coretests/apks/install_loc_sdcard/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_loc_sdcard
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_loc_unspecified/Android.bp b/core/tests/coretests/apks/install_loc_unspecified/Android.bp
new file mode 100644
index 0000000..21c0f82
--- /dev/null
+++ b/core/tests/coretests/apks/install_loc_unspecified/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_loc_unspecified",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_loc_unspecified/Android.mk b/core/tests/coretests/apks/install_loc_unspecified/Android.mk
deleted file mode 100644
index 0741d04..0000000
--- a/core/tests/coretests/apks/install_loc_unspecified/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_loc_unspecified
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_multi_package/Android.bp b/core/tests/coretests/apks/install_multi_package/Android.bp
new file mode 100644
index 0000000..249242e
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_multi_package",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_multi_package/Android.mk b/core/tests/coretests/apks/install_multi_package/Android.mk
deleted file mode 100644
index 3f163de..0000000
--- a/core/tests/coretests/apks/install_multi_package/Android.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_multi_package
-
-LOCAL_USE_AAPT2 := true
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-#include $(BUILD_PACKAGE)
-
diff --git a/core/tests/coretests/apks/install_use_perm_good/Android.bp b/core/tests/coretests/apks/install_use_perm_good/Android.bp
new file mode 100644
index 0000000..bb41ebb
--- /dev/null
+++ b/core/tests/coretests/apks/install_use_perm_good/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_use_perm_good",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_use_perm_good/Android.mk b/core/tests/coretests/apks/install_use_perm_good/Android.mk
deleted file mode 100644
index e2661a1..0000000
--- a/core/tests/coretests/apks/install_use_perm_good/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_use_perm_good
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_uses_feature/Android.bp b/core/tests/coretests/apks/install_uses_feature/Android.bp
new file mode 100644
index 0000000..0ec747b
--- /dev/null
+++ b/core/tests/coretests/apks/install_uses_feature/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_uses_feature",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_uses_feature/Android.mk b/core/tests/coretests/apks/install_uses_feature/Android.mk
deleted file mode 100644
index b60d734..0000000
--- a/core/tests/coretests/apks/install_uses_feature/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_uses_feature
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_verifier_bad/Android.bp b/core/tests/coretests/apks/install_verifier_bad/Android.bp
new file mode 100644
index 0000000..1265739
--- /dev/null
+++ b/core/tests/coretests/apks/install_verifier_bad/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_verifier_bad",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_verifier_bad/Android.mk b/core/tests/coretests/apks/install_verifier_bad/Android.mk
deleted file mode 100644
index 745b4d3..0000000
--- a/core/tests/coretests/apks/install_verifier_bad/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_verifier_bad
-
-LOCAL_USE_AAPT2 := true
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_verifier_good/Android.bp b/core/tests/coretests/apks/install_verifier_good/Android.bp
new file mode 100644
index 0000000..4911ffb
--- /dev/null
+++ b/core/tests/coretests/apks/install_verifier_good/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_install_verifier_good",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_verifier_good/Android.mk b/core/tests/coretests/apks/install_verifier_good/Android.mk
deleted file mode 100644
index 150fd8d..0000000
--- a/core/tests/coretests/apks/install_verifier_good/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_verifier_good
-
-LOCAL_USE_AAPT2 := true
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/keyset/Android.bp b/core/tests/coretests/apks/keyset/Android.bp
new file mode 100644
index 0000000..e252b08
--- /dev/null
+++ b/core/tests/coretests/apks/keyset/Android.bp
@@ -0,0 +1,120 @@
+//apks signed by keyset_A
+android_test_helper_app {
+    name: "FrameworksCoreTests_keyset_sa_unone",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    certificate: ":FrameworksCoreTests_keyset_A_cert",
+    manifest: "uNone/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "FrameworksCoreTests_keyset_sa_ua",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    certificate: ":FrameworksCoreTests_keyset_A_cert",
+    manifest: "uA/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "FrameworksCoreTests_keyset_sa_ub",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    certificate: ":FrameworksCoreTests_keyset_A_cert",
+    manifest: "uB/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "FrameworksCoreTests_keyset_sa_uab",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    certificate: ":FrameworksCoreTests_keyset_A_cert",
+    manifest: "uAB/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "FrameworksCoreTests_keyset_sa_ua_ub",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    certificate: ":FrameworksCoreTests_keyset_A_cert",
+    manifest: "uAuB/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "FrameworksCoreTests_keyset_permdef_sa_unone",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    certificate: ":FrameworksCoreTests_keyset_A_cert",
+    manifest: "permDef/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "FrameworksCoreTests_keyset_permuse_sa_ua_ub",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    certificate: ":FrameworksCoreTests_keyset_A_cert",
+    manifest: "permUse/AndroidManifest.xml",
+}
+
+//apks signed by keyset_B
+android_test_helper_app {
+    name: "FrameworksCoreTests_keyset_sb_ua",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    certificate: ":FrameworksCoreTests_keyset_B_cert",
+    manifest: "uA/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "FrameworksCoreTests_keyset_sb_ub",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    certificate: ":FrameworksCoreTests_keyset_B_cert",
+    manifest: "uB/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "FrameworksCoreTests_keyset_permuse_sb_ua_ub",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    certificate: ":FrameworksCoreTests_keyset_B_cert",
+    manifest: "permUse/AndroidManifest.xml",
+}
+
+//apks signed by keyset_A and keyset_B
+android_test_helper_app {
+    name: "FrameworksCoreTests_keyset_sab_ua",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    certificate: ":FrameworksCoreTests_keyset_A_cert",
+    additional_certificates: [":FrameworksCoreTests_keyset_B_cert"],
+    manifest: "uA/AndroidManifest.xml",
+}
+
+//apks signed by keyset_A and unit_test
+android_test_helper_app {
+    name: "FrameworksCoreTests_keyset_sau_ub",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    certificate: ":FrameworksCoreTests_keyset_A_cert",
+    additional_certificates: [":FrameworksCoreTests_keyset_B_cert"],
+    manifest: "uB/AndroidManifest.xml",
+}
+
+//apks signed by platform only
+android_test_helper_app {
+    name: "FrameworksCoreTests_keyset_splat_api",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    certificate: "platform",
+    manifest: "api_test/AndroidManifest.xml",
+}
+
+//apks signed by platform and keyset_A
+android_test_helper_app {
+    name: "FrameworksCoreTests_keyset_splata_api",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    certificate: "platform",
+    additional_certificates: [":FrameworksCoreTests_keyset_A_cert"],
+    manifest: "api_test/AndroidManifest.xml",
+}
diff --git a/core/tests/coretests/apks/keyset/Android.mk b/core/tests/coretests/apks/keyset/Android.mk
deleted file mode 100644
index 306dc90..0000000
--- a/core/tests/coretests/apks/keyset/Android.mk
+++ /dev/null
@@ -1,108 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-#apks signed by keyset_A
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sa_unone
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := uNone/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sa_ua
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := uA/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sa_ub
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := uB/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sa_uab
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := uAB/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sa_ua_ub
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := uAuB/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_permdef_sa_unone
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := permDef/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_permuse_sa_ua_ub
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := permUse/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-#apks signed by keyset_B
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sb_ua
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_B
-LOCAL_MANIFEST_FILE := uA/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sb_ub
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_B
-LOCAL_MANIFEST_FILE := uB/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_permuse_sb_ua_ub
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_B
-LOCAL_MANIFEST_FILE := permUse/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-#apks signed by keyset_A and keyset_B
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sab_ua
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_ADDITIONAL_CERTIFICATES := $(LOCAL_PATH)/../../certs/keyset_B
-LOCAL_MANIFEST_FILE := uA/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-#apks signed by keyset_A and unit_test
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sau_ub
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_ADDITIONAL_CERTIFICATES := $(LOCAL_PATH)/../../certs/keyset_B
-LOCAL_MANIFEST_FILE := uB/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-#apks signed by platform only
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_splat_api
-LOCAL_CERTIFICATE := platform
-LOCAL_MANIFEST_FILE := api_test/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-#apks signed by platform and keyset_A
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_splata_api
-LOCAL_CERTIFICATE := platform
-LOCAL_ADDITIONAL_CERTIFICATES := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := api_test/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
\ No newline at end of file
diff --git a/core/tests/coretests/apks/locales/Android.bp b/core/tests/coretests/apks/locales/Android.bp
new file mode 100644
index 0000000..4a730ef
--- /dev/null
+++ b/core/tests/coretests/apks/locales/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_locales",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+
+    srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/locales/Android.mk b/core/tests/coretests/apks/locales/Android.mk
deleted file mode 100644
index 9cb13dd..0000000
--- a/core/tests/coretests/apks/locales/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := locales
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/version/Android.bp b/core/tests/coretests/apks/version/Android.bp
new file mode 100644
index 0000000..371ccfc
--- /dev/null
+++ b/core/tests/coretests/apks/version/Android.bp
@@ -0,0 +1,54 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_version_1",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    aaptflags: [
+        "--version-code 1",
+        "--version-name 1.0",
+    ],
+    certificate: ":FrameworksCoreTests_unit_test_cert",
+}
+
+android_test_helper_app {
+    name: "FrameworksCoreTests_version_2",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    aaptflags: [
+        "--version-code 2",
+        "--version-name 2.0",
+    ],
+    certificate: ":FrameworksCoreTests_unit_test_cert",
+}
+
+android_test_helper_app {
+    name: "FrameworksCoreTests_version_3",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    aaptflags: [
+        "--version-code 3",
+        "--version-name 3.0",
+    ],
+    certificate: ":FrameworksCoreTests_unit_test_cert",
+}
+
+android_test_helper_app {
+    name: "FrameworksCoreTests_version_1_diff",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    aaptflags: [
+        "--version-code 1",
+        "--version-name 1.0",
+    ],
+    certificate: ":FrameworksCoreTests_unit_test_cert",
+}
+
+android_test_helper_app {
+    name: "FrameworksCoreTests_version_2_diff",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    aaptflags: [
+        "--version-code 2",
+        "--version-name 2.0",
+    ],
+    certificate: ":FrameworksCoreTests_unit_test_cert",
+}
diff --git a/core/tests/coretests/apks/version/Android.mk b/core/tests/coretests/apks/version/Android.mk
deleted file mode 100644
index 3635a58..0000000
--- a/core/tests/coretests/apks/version/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := version_1
-LOCAL_AAPT_FLAGS := --version-code 1 --version-name 1.0
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/unit_test
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := version_2
-LOCAL_AAPT_FLAGS := --version-code 2 --version-name 2.0
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/unit_test
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := version_3
-LOCAL_AAPT_FLAGS := --version-code 3 --version-name 3.0
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/unit_test
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := version_1_diff
-LOCAL_AAPT_FLAGS := --version-code 1 --version-name 1.0
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/unit_test_diff
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := version_2_diff
-LOCAL_AAPT_FLAGS := --version-code 2 --version-name 2.0
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/unit_test_diff
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/version_nosys/Android.bp b/core/tests/coretests/apks/version_nosys/Android.bp
new file mode 100644
index 0000000..5756678
--- /dev/null
+++ b/core/tests/coretests/apks/version_nosys/Android.bp
@@ -0,0 +1,10 @@
+android_test_helper_app {
+    name: "FrameworksCoreTests_version_1_nosys",
+    defaults: ["FrameworksCoreTests_apks_defaults"],
+    srcs: ["**/*.java"],
+    aaptflags: [
+        "--version-code 1",
+        "--version-name 1.0",
+    ],
+    certificate: ":FrameworksCoreTests_unit_test_cert",
+}
diff --git a/core/tests/coretests/apks/version_nosys/Android.mk b/core/tests/coretests/apks/version_nosys/Android.mk
deleted file mode 100644
index bbc8e12..0000000
--- a/core/tests/coretests/apks/version_nosys/Android.mk
+++ /dev/null
@@ -1,9 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := version_1_nosys
-LOCAL_AAPT_FLAGS := --version-code 1 --version-name 1.0
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/unit_test
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
diff --git a/core/tests/coretests/certs/Android.bp b/core/tests/coretests/certs/Android.bp
new file mode 100644
index 0000000..bd5c829
--- /dev/null
+++ b/core/tests/coretests/certs/Android.bp
@@ -0,0 +1,14 @@
+android_app_certificate {
+    name: "FrameworksCoreTests_keyset_A_cert",
+    certificate: "keyset_A",
+}
+
+android_app_certificate {
+    name: "FrameworksCoreTests_keyset_B_cert",
+    certificate: "keyset_B",
+}
+
+android_app_certificate {
+    name: "FrameworksCoreTests_unit_test_cert",
+    certificate: "unit_test",
+}
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/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java b/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java
new file mode 100644
index 0000000..e4e9cde
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.view.textclassifier;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class LabeledIntentTest {
+    private static final String TITLE_WITHOUT_ENTITY = "Map";
+    private static final String TITLE_WITH_ENTITY = "Map NW14D1";
+    private static final String DESCRIPTION = "Check the map";
+    private static final Intent INTENT =
+            new Intent(Intent.ACTION_VIEW).setDataAndNormalize(Uri.parse("http://www.android.com"));
+    private static final int REQUEST_CODE = 42;
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
+    public void resolve_preferTitleWithEntity() {
+        LabeledIntent labeledIntent = new LabeledIntent(
+                TITLE_WITHOUT_ENTITY,
+                TITLE_WITH_ENTITY,
+                DESCRIPTION,
+                INTENT,
+                REQUEST_CODE
+        );
+
+        LabeledIntent.Result result =
+                labeledIntent.resolve(mContext, /*titleChooser*/ null);
+
+        assertThat(result).isNotNull();
+        assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITH_ENTITY);
+        assertThat(result.remoteAction.getContentDescription()).isEqualTo(DESCRIPTION);
+        Intent intent = result.resolvedIntent;
+        assertThat(intent.getAction()).isEqualTo(intent.getAction());
+        assertThat(intent.getComponent()).isNotNull();
+    }
+
+    @Test
+    public void resolve_useAvailableTitle() {
+        LabeledIntent labeledIntent = new LabeledIntent(
+                TITLE_WITHOUT_ENTITY,
+                null,
+                DESCRIPTION,
+                INTENT,
+                REQUEST_CODE
+        );
+
+        LabeledIntent.Result result =
+                labeledIntent.resolve(mContext, /*titleChooser*/ null);
+
+        assertThat(result).isNotNull();
+        assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITHOUT_ENTITY);
+        assertThat(result.remoteAction.getContentDescription()).isEqualTo(DESCRIPTION);
+        Intent intent = result.resolvedIntent;
+        assertThat(intent.getAction()).isEqualTo(intent.getAction());
+        assertThat(intent.getComponent()).isNotNull();
+    }
+
+    @Test
+    public void resolve_titleChooser() {
+        LabeledIntent labeledIntent = new LabeledIntent(
+                TITLE_WITHOUT_ENTITY,
+                null,
+                DESCRIPTION,
+                INTENT,
+                REQUEST_CODE
+        );
+
+        LabeledIntent.Result result =
+                labeledIntent.resolve(mContext, (labeledIntent1, resolveInfo) -> "chooser");
+
+        assertThat(result).isNotNull();
+        assertThat(result.remoteAction.getTitle()).isEqualTo("chooser");
+        assertThat(result.remoteAction.getContentDescription()).isEqualTo(DESCRIPTION);
+        Intent intent = result.resolvedIntent;
+        assertThat(intent.getAction()).isEqualTo(intent.getAction());
+        assertThat(intent.getComponent()).isNotNull();
+    }
+
+    @Test
+    public void resolve_titleChooserReturnsNull() {
+        LabeledIntent labeledIntent = new LabeledIntent(
+                TITLE_WITHOUT_ENTITY,
+                null,
+                DESCRIPTION,
+                INTENT,
+                REQUEST_CODE
+        );
+
+        LabeledIntent.Result result =
+                labeledIntent.resolve(mContext, (labeledIntent1, resolveInfo) -> null);
+
+        assertThat(result).isNotNull();
+        assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITHOUT_ENTITY);
+        assertThat(result.remoteAction.getContentDescription()).isEqualTo(DESCRIPTION);
+        Intent intent = result.resolvedIntent;
+        assertThat(intent.getAction()).isEqualTo(intent.getAction());
+        assertThat(intent.getComponent()).isNotNull();
+    }
+
+
+    @Test
+    public void resolve_missingTitle() {
+        assertThrows(
+                IllegalArgumentException.class,
+                () ->
+                        new LabeledIntent(
+                                null,
+                                null,
+                                DESCRIPTION,
+                                INTENT,
+                                REQUEST_CODE
+                        ));
+    }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java
index 73d3eec..743818c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java
@@ -58,9 +58,12 @@
                         null,
                         null,
                         null,
+                        null,
+                        null,
+                        null,
                         null);
 
-        List<TextClassifierImpl.LabeledIntent> intents = mLegacyIntentFactory.create(
+        List<LabeledIntent> intents = mLegacyIntentFactory.create(
                 InstrumentationRegistry.getContext(),
                 TEXT,
                 /* foreignText */ false,
@@ -68,8 +71,8 @@
                 classificationResult);
 
         assertThat(intents).hasSize(1);
-        TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0);
-        Intent intent = labeledIntent.getIntent();
+        LabeledIntent labeledIntent = intents.get(0);
+        Intent intent = labeledIntent.intent;
         assertThat(intent.getAction()).isEqualTo(Intent.ACTION_DEFINE);
         assertThat(intent.getStringExtra(Intent.EXTRA_TEXT)).isEqualTo(TEXT);
         assertThat(
@@ -89,9 +92,12 @@
                         null,
                         null,
                         null,
+                        null,
+                        null,
+                        null,
                         null);
 
-        List<TextClassifierImpl.LabeledIntent> intents = mLegacyIntentFactory.create(
+        List<LabeledIntent> intents = mLegacyIntentFactory.create(
                 InstrumentationRegistry.getContext(),
                 TEXT,
                 /* foreignText */ true,
@@ -99,7 +105,7 @@
                 classificationResult);
 
         assertThat(intents).hasSize(2);
-        assertThat(intents.get(0).getIntent().getAction()).isEqualTo(Intent.ACTION_DEFINE);
-        assertThat(intents.get(1).getIntent().getAction()).isEqualTo(Intent.ACTION_TRANSLATE);
+        assertThat(intents.get(0).intent.getAction()).isEqualTo(Intent.ACTION_DEFINE);
+        assertThat(intents.get(1).intent.getAction()).isEqualTo(Intent.ACTION_TRANSLATE);
     }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
index d9dac31..9fd9e8e 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
@@ -40,7 +40,7 @@
 public class TemplateClassificationIntentFactoryTest {
 
     private static final String TEXT = "text";
-    private static final String TITLE = "Map";
+    private static final String TITLE_WITHOUT_ENTITY = "Map";
     private static final String DESCRIPTION = "Opens in Maps";
     private static final String ACTION = Intent.ACTION_VIEW;
 
@@ -69,9 +69,12 @@
                         null,
                         null,
                         null,
+                        null,
+                        null,
+                        null,
                         createRemoteActionTemplates());
 
-        List<TextClassifierImpl.LabeledIntent> intents =
+        List<LabeledIntent> intents =
                 mTemplateClassificationIntentFactory.create(
                         InstrumentationRegistry.getContext(),
                         TEXT,
@@ -80,14 +83,14 @@
                         classificationResult);
 
         assertThat(intents).hasSize(2);
-        TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0);
-        assertThat(labeledIntent.getTitle()).isEqualTo(TITLE);
-        Intent intent = labeledIntent.getIntent();
+        LabeledIntent labeledIntent = intents.get(0);
+        assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
+        Intent intent = labeledIntent.intent;
         assertThat(intent.getAction()).isEqualTo(ACTION);
         assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
 
         labeledIntent = intents.get(1);
-        intent = labeledIntent.getIntent();
+        intent = labeledIntent.intent;
         assertThat(intent.getAction()).isEqualTo(Intent.ACTION_TRANSLATE);
         assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
     }
@@ -105,9 +108,12 @@
                         null,
                         null,
                         null,
+                        null,
+                        null,
+                        null,
                         createRemoteActionTemplates());
 
-        List<TextClassifierImpl.LabeledIntent> intents =
+        List<LabeledIntent> intents =
                 mTemplateClassificationIntentFactory.create(
                         InstrumentationRegistry.getContext(),
                         TEXT,
@@ -116,9 +122,9 @@
                         classificationResult);
 
         assertThat(intents).hasSize(1);
-        TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0);
-        assertThat(labeledIntent.getTitle()).isEqualTo(TITLE);
-        Intent intent = labeledIntent.getIntent();
+        LabeledIntent labeledIntent = intents.get(0);
+        assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
+        Intent intent = labeledIntent.intent;
         assertThat(intent.getAction()).isEqualTo(ACTION);
         assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
     }
@@ -126,7 +132,8 @@
     private static RemoteActionTemplate[] createRemoteActionTemplates() {
         return new RemoteActionTemplate[]{
                 new RemoteActionTemplate(
-                        TITLE,
+                        TITLE_WITHOUT_ENTITY,
+                        null,
                         DESCRIPTION,
                         ACTION,
                         null,
diff --git a/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
index a1158a7..1860734 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
@@ -38,7 +38,8 @@
 public class TemplateIntentFactoryTest {
 
     private static final String TEXT = "text";
-    private static final String TITLE = "Map";
+    private static final String TITLE_WITHOUT_ENTITY = "Map";
+    private static final String TITLE_WITH_ENTITY = "Map NW14D1";
     private static final String DESCRIPTION = "Check the map";
     private static final String ACTION = Intent.ACTION_VIEW;
     private static final String DATA = Uri.parse("http://www.android.com").toString();
@@ -69,7 +70,8 @@
     @Test
     public void create_full() {
         RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
-                TITLE,
+                TITLE_WITHOUT_ENTITY,
+                TITLE_WITH_ENTITY,
                 DESCRIPTION,
                 ACTION,
                 DATA,
@@ -81,15 +83,16 @@
                 REQUEST_CODE
         );
 
-        List<TextClassifierImpl.LabeledIntent> intents =
+        List<LabeledIntent> intents =
                 mTemplateIntentFactory.create(new RemoteActionTemplate[]{remoteActionTemplate});
 
         assertThat(intents).hasSize(1);
-        TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0);
-        assertThat(labeledIntent.getTitle()).isEqualTo(TITLE);
-        assertThat(labeledIntent.getDescription()).isEqualTo(DESCRIPTION);
-        assertThat(labeledIntent.getRequestCode()).isEqualTo(REQUEST_CODE);
-        Intent intent = labeledIntent.getIntent();
+        LabeledIntent labeledIntent = intents.get(0);
+        assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
+        assertThat(labeledIntent.titleWithEntity).isEqualTo(TITLE_WITH_ENTITY);
+        assertThat(labeledIntent.description).isEqualTo(DESCRIPTION);
+        assertThat(labeledIntent.requestCode).isEqualTo(REQUEST_CODE);
+        Intent intent = labeledIntent.intent;
         assertThat(intent.getAction()).isEqualTo(ACTION);
         assertThat(intent.getData().toString()).isEqualTo(DATA);
         assertThat(intent.getType()).isEqualTo(TYPE);
@@ -104,7 +107,8 @@
     @Test
     public void normalizesScheme() {
         RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
-                TITLE,
+                TITLE_WITHOUT_ENTITY,
+                TITLE_WITH_ENTITY,
                 DESCRIPTION,
                 ACTION,
                 "HTTp://www.android.com",
@@ -116,17 +120,18 @@
                 REQUEST_CODE
         );
 
-        List<TextClassifierImpl.LabeledIntent> intents =
+        List<LabeledIntent> intents =
                 mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
 
-        String data = intents.get(0).getIntent().getData().toString();
+        String data = intents.get(0).intent.getData().toString();
         assertThat(data).isEqualTo("http://www.android.com");
     }
 
     @Test
     public void create_minimal() {
         RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
-                TITLE,
+                TITLE_WITHOUT_ENTITY,
+                null,
                 DESCRIPTION,
                 ACTION,
                 null,
@@ -138,16 +143,17 @@
                 null
         );
 
-        List<TextClassifierImpl.LabeledIntent> intents =
+        List<LabeledIntent> intents =
                 mTemplateIntentFactory.create(new RemoteActionTemplate[]{remoteActionTemplate});
 
         assertThat(intents).hasSize(1);
-        TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0);
-        assertThat(labeledIntent.getTitle()).isEqualTo(TITLE);
-        assertThat(labeledIntent.getDescription()).isEqualTo(DESCRIPTION);
-        assertThat(labeledIntent.getRequestCode()).isEqualTo(
-                TextClassifierImpl.LabeledIntent.DEFAULT_REQUEST_CODE);
-        Intent intent = labeledIntent.getIntent();
+        LabeledIntent labeledIntent = intents.get(0);
+        assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
+        assertThat(labeledIntent.titleWithEntity).isNull();
+        assertThat(labeledIntent.description).isEqualTo(DESCRIPTION);
+        assertThat(labeledIntent.requestCode).isEqualTo(
+                LabeledIntent.DEFAULT_REQUEST_CODE);
+        Intent intent = labeledIntent.intent;
         assertThat(intent.getAction()).isEqualTo(ACTION);
         assertThat(intent.getData()).isNull();
         assertThat(intent.getType()).isNull();
@@ -161,7 +167,7 @@
     public void invalidTemplate_nullTemplate() {
         RemoteActionTemplate remoteActionTemplate = null;
 
-        List<TextClassifierImpl.LabeledIntent> intents =
+        List<LabeledIntent> intents =
                 mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
 
         assertThat(intents).isEmpty();
@@ -170,7 +176,8 @@
     @Test
     public void invalidTemplate_nonEmptyPackageName() {
         RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
-                TITLE,
+                TITLE_WITHOUT_ENTITY,
+                TITLE_WITH_ENTITY,
                 DESCRIPTION,
                 ACTION,
                 DATA,
@@ -182,7 +189,7 @@
                 REQUEST_CODE
         );
 
-        List<TextClassifierImpl.LabeledIntent> intents =
+        List<LabeledIntent> intents =
                 mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
 
         assertThat(intents).isEmpty();
@@ -192,6 +199,7 @@
     public void invalidTemplate_emptyTitle() {
         RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
                 null,
+                null,
                 DESCRIPTION,
                 ACTION,
                 null,
@@ -203,7 +211,7 @@
                 null
         );
 
-        List<TextClassifierImpl.LabeledIntent> intents =
+        List<LabeledIntent> intents =
                 mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
 
         assertThat(intents).isEmpty();
@@ -212,7 +220,8 @@
     @Test
     public void invalidTemplate_emptyDescription() {
         RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
-                TITLE,
+                TITLE_WITHOUT_ENTITY,
+                TITLE_WITH_ENTITY,
                 null,
                 ACTION,
                 null,
@@ -224,7 +233,7 @@
                 null
         );
 
-        List<TextClassifierImpl.LabeledIntent> intents =
+        List<LabeledIntent> intents =
                 mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
 
         assertThat(intents).isEmpty();
@@ -233,7 +242,8 @@
     @Test
     public void invalidTemplate_emptyIntentAction() {
         RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
-                TITLE,
+                TITLE_WITHOUT_ENTITY,
+                TITLE_WITH_ENTITY,
                 DESCRIPTION,
                 null,
                 null,
@@ -245,7 +255,7 @@
                 null
         );
 
-        List<TextClassifierImpl.LabeledIntent> intents =
+        List<LabeledIntent> intents =
                 mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
 
         assertThat(intents).isEmpty();
diff --git a/core/tests/utillib/Android.bp b/core/tests/utillib/Android.bp
new file mode 100644
index 0000000..1f742c2
--- /dev/null
+++ b/core/tests/utillib/Android.bp
@@ -0,0 +1,22 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_library {
+    name: "frameworks-core-util-lib",
+
+    srcs: ["**/*.java"],
+
+    static_libs: ["junit"],
+    libs: ["android.test.base"],
+}
diff --git a/core/tests/utillib/Android.mk b/core/tests/utillib/Android.mk
deleted file mode 100644
index be1ab1f..0000000
--- a/core/tests/utillib/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_MODULE := frameworks-core-util-lib
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-LOCAL_JAVA_LIBRARIES := android.test.base
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
-
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 8d3bac8..920fb4c 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -836,7 +836,7 @@
      * @return A bitmap that represents the specified subset of source
      * @throws IllegalArgumentException if the x, y, width, height values are
      *         outside of the dimensions of the source bitmap, or width is <= 0,
-     *         or height is <= 0
+     *         or height is <= 0, or if the source bitmap has already been recycled
      */
     public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height,
             @Nullable Matrix m, boolean filter) {
@@ -849,6 +849,9 @@
         if (y + height > source.getHeight()) {
             throw new IllegalArgumentException("y + height must be <= bitmap.height()");
         }
+        if (source.isRecycled()) {
+            throw new IllegalArgumentException("cannot use a recycled source in createBitmap");
+        }
 
         // check if we can just return our argument unchanged
         if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() &&
@@ -1270,7 +1273,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..225dc0f
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/metrics/DataStallDetectionStats.java
@@ -0,0 +1,228 @@
+/*
+ * 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.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 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();
+    }
+
+    @Override
+    public boolean equals(@Nullable final Object o) {
+        if (!(o instanceof DataStallDetectionStats)) return false;
+        final DataStallDetectionStats other = (DataStallDetectionStats) o;
+        return (mNetworkType == other.mNetworkType)
+            && (mEvaluationType == other.mEvaluationType)
+            && Arrays.equals(mWifiInfo, other.mWifiInfo)
+            && Arrays.equals(mCellularInfo, other.mCellularInfo)
+            && Arrays.equals(mDns, other.mDns);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mNetworkType, mEvaluationType, mWifiInfo, mCellularInfo, mDns);
+    }
+
+    /**
+     * 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) return DataStallEventProto.AP_BAND_UNKNOWN;
+
+            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;
+            } else {
+                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..e82a5d7 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,66 @@
         }
     }
 
+    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();
+    }
+
+    @VisibleForTesting
+    protected 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 +1045,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 +1695,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..ddb7030 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -39,6 +39,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.INetworkMonitorCallbacks;
@@ -48,8 +49,11 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.captiveportal.CaptivePortalProbeResult;
+import android.net.metrics.DataStallDetectionStats;
+import android.net.metrics.DataStallStatsUtils;
 import android.net.metrics.IpConnectivityLog;
 import android.net.util.SharedLog;
+import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.os.ConditionVariable;
@@ -58,6 +62,7 @@
 import android.provider.Settings;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.telephony.CellSignalStrength;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 
@@ -98,6 +103,8 @@
     private @Mock NetworkMonitor.Dependencies mDependencies;
     private @Mock INetworkMonitorCallbacks mCallbacks;
     private @Spy Network mNetwork = new Network(TEST_NETID);
+    private @Mock DataStallStatsUtils mDataStallStatsUtils;
+    private @Mock WifiInfo mWifiInfo;
 
     private static final int TEST_NETID = 4242;
 
@@ -105,10 +112,12 @@
     private static final String TEST_HTTPS_URL = "https://www.google.com/gen_204";
     private static final String TEST_FALLBACK_URL = "http://fallback.google.com/gen_204";
     private static final String TEST_OTHER_FALLBACK_URL = "http://otherfallback.google.com/gen_204";
+    private static final String TEST_MCCMNC = "123456";
 
     private static final int DATA_STALL_EVALUATION_TYPE_DNS = 1;
     private static final int RETURN_CODE_DNS_SUCCESS = 0;
     private static final int RETURN_CODE_DNS_TIMEOUT = 255;
+    private static final int DEFAULT_DNS_TIMEOUT_THRESHOLD = 5;
 
     private static final int HANDLER_TIMEOUT_MS = 1000;
 
@@ -186,9 +195,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
@@ -199,11 +208,16 @@
         protected void setLastProbeTime(long time) {
             mProbeTime = time;
         }
+
+        @Override
+        protected void addDnsEvents(@NonNull final DataStallDetectionStats.Builder stats) {
+            generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
+        }
     }
 
     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 +226,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 +236,7 @@
     private NetworkMonitor makeMonitor() {
         final NetworkMonitor nm = new NetworkMonitor(
                 mContext, mCallbacks, mNetwork, mLogger, mValidationLogger,
-                mDependencies);
+                mDependencies, mDataStallStatsUtils);
         nm.start();
         waitForIdle(nm.getHandler());
         return nm;
@@ -384,7 +398,7 @@
     public void testIsDataStall_EvaluationDnsOnNotMeteredNetwork() {
         WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
-        makeDnsTimeoutEvent(wrappedMonitor, 5);
+        makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
         assertTrue(wrappedMonitor.isDataStall());
     }
 
@@ -395,7 +409,7 @@
         assertFalse(wrappedMonitor.isDataStall());
 
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
-        makeDnsTimeoutEvent(wrappedMonitor, 5);
+        makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
         assertTrue(wrappedMonitor.isDataStall());
     }
 
@@ -429,7 +443,7 @@
         // Test dns events happened in valid dns time threshold.
         WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
-        makeDnsTimeoutEvent(wrappedMonitor, 5);
+        makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
         assertFalse(wrappedMonitor.isDataStall());
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
         assertTrue(wrappedMonitor.isDataStall());
@@ -438,7 +452,7 @@
         setValidDataStallDnsTimeThreshold(0);
         wrappedMonitor = makeMeteredWrappedNetworkMonitor();
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
-        makeDnsTimeoutEvent(wrappedMonitor, 5);
+        makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
         assertFalse(wrappedMonitor.isDataStall());
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
         assertFalse(wrappedMonitor.isDataStall());
@@ -505,6 +519,59 @@
                 .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(any(), any());
+    }
+
+    @Test
+    public void testDataStall_NoStallSuspectedAndSendMetrics() throws IOException {
+        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
+        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
+        makeDnsTimeoutEvent(wrappedMonitor, 3);
+        assertFalse(wrappedMonitor.isDataStall());
+        verify(mDataStallStatsUtils, never()).write(any(), any());
+    }
+
+    @Test
+    public void testCollectDataStallMetrics() {
+        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
+
+        when(mTelephony.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_LTE);
+        when(mTelephony.getNetworkOperator()).thenReturn(TEST_MCCMNC);
+        when(mTelephony.getSimOperator()).thenReturn(TEST_MCCMNC);
+
+        DataStallDetectionStats.Builder stats =
+                new DataStallDetectionStats.Builder()
+                .setEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS)
+                .setNetworkType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                .setCellData(TelephonyManager.NETWORK_TYPE_LTE /* radioType */,
+                        true /* roaming */,
+                        TEST_MCCMNC /* networkMccmnc */,
+                        TEST_MCCMNC /* simMccmnc */,
+                        CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN /* signalStrength */);
+        generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
+
+        assertEquals(wrappedMonitor.buildDataStallDetectionStats(
+                 NetworkCapabilities.TRANSPORT_CELLULAR), stats.build());
+
+        when(mWifi.getConnectionInfo()).thenReturn(mWifiInfo);
+
+        stats = new DataStallDetectionStats.Builder()
+                .setEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS)
+                .setNetworkType(NetworkCapabilities.TRANSPORT_WIFI)
+                .setWiFiData(mWifiInfo);
+        generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
+
+        assertEquals(
+                wrappedMonitor.buildDataStallDetectionStats(NetworkCapabilities.TRANSPORT_WIFI),
+                stats.build());
+    }
+
     private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
         for (int i = 0; i < count; i++) {
             wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
@@ -594,5 +661,11 @@
     private void setStatus(HttpURLConnection connection, int status) throws IOException {
         doReturn(status).when(connection).getResponseCode();
     }
+
+    private void generateTimeoutDnsEvent(DataStallDetectionStats.Builder stats, int num) {
+        for (int i = 0; i < num; i++) {
+            stats.addDnsEvent(RETURN_CODE_DNS_TIMEOUT, 123456789 /* timeMs */);
+        }
+    }
 }
 
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/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 583dac7..9dd9717 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -17,7 +17,6 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import android.annotation.Nullable;
 import android.app.Presentation;
 import android.content.Context;
 import android.graphics.Point;
@@ -32,15 +31,11 @@
 import android.view.View;
 import android.view.WindowManager;
 
-import java.util.function.BooleanSupplier;
-
 // TODO(multi-display): Support multiple external displays
 public class KeyguardDisplayManager {
     protected static final String TAG = "KeyguardDisplayManager";
     private static boolean DEBUG = KeyguardConstants.DEBUG;
 
-    private final ViewMediatorCallback mCallback;
-
     private final MediaRouter mMediaRouter;
     private final DisplayManager mDisplayService;
     private final Context mContext;
@@ -57,7 +52,7 @@
         public void onDisplayAdded(int displayId) {
             final Display display = mDisplayService.getDisplay(displayId);
             if (mShowing) {
-                notifyIfChanged(() -> showPresentation(display));
+                showPresentation(display);
             }
         }
 
@@ -76,13 +71,12 @@
 
         @Override
         public void onDisplayRemoved(int displayId) {
-            notifyIfChanged(() -> hidePresentation(displayId));
+            hidePresentation(displayId);
         }
     };
 
-    public KeyguardDisplayManager(Context context, ViewMediatorCallback callback) {
+    public KeyguardDisplayManager(Context context) {
         mContext = context;
-        mCallback = callback;
         mMediaRouter = mContext.getSystemService(MediaRouter.class);
         mDisplayService = mContext.getSystemService(DisplayManager.class);
         mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
@@ -138,42 +132,13 @@
 
     /**
      * @param displayId The id of the display to hide the presentation off.
-     * @return {@code true} if the a presentation was removed.
-     *         {@code false} if the presentation was not added before.
      */
-    private boolean hidePresentation(int displayId) {
+    private void hidePresentation(int displayId) {
         final Presentation presentation = mPresentations.get(displayId);
         if (presentation != null) {
             presentation.dismiss();
             mPresentations.remove(displayId);
-            return true;
         }
-        return false;
-    }
-
-    private void notifyIfChanged(BooleanSupplier updateMethod) {
-        if (updateMethod.getAsBoolean()) {
-            final int[] displayList = getPresentationDisplayIds();
-            mCallback.onSecondaryDisplayShowingChanged(displayList);
-        }
-    }
-
-    /**
-     * @return An array of displayId's on which a {@link KeyguardPresentation} is showing on.
-     */
-    @Nullable
-    private int[] getPresentationDisplayIds() {
-        final int size = mPresentations.size();
-        if (size == 0) return null;
-
-        final int[] displayIds = new int[size];
-        for (int i = mPresentations.size() - 1; i >= 0; i--) {
-            final Presentation presentation = mPresentations.valueAt(i);
-            if (presentation != null) {
-                displayIds[i] = presentation.getDisplay().getDisplayId();
-            }
-        }
-        return displayIds;
     }
 
     public void show() {
@@ -181,7 +146,7 @@
             if (DEBUG) Log.v(TAG, "show");
             mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
                     mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
-            notifyIfChanged(() -> updateDisplays(true /* showing */));
+            updateDisplays(true /* showing */);
         }
         mShowing = true;
     }
@@ -190,7 +155,7 @@
         if (mShowing) {
             if (DEBUG) Log.v(TAG, "hide");
             mMediaRouter.removeCallback(mMediaRouterCallback);
-            notifyIfChanged(() -> updateDisplays(false /* showing */));
+            updateDisplays(false /* showing */);
         }
         mShowing = false;
     }
@@ -200,19 +165,19 @@
         @Override
         public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
             if (DEBUG) Log.d(TAG, "onRouteSelected: type=" + type + ", info=" + info);
-            notifyIfChanged(() -> updateDisplays(mShowing));
+            updateDisplays(mShowing);
         }
 
         @Override
         public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
             if (DEBUG) Log.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
-            notifyIfChanged(() -> updateDisplays(mShowing));
+            updateDisplays(mShowing);
         }
 
         @Override
         public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
             if (DEBUG) Log.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
-            notifyIfChanged(() -> updateDisplays(mShowing));
+            updateDisplays(mShowing);
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
index a07c5cb..6e06130 100644
--- a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
@@ -96,11 +96,6 @@
     int getBouncerPromptReason();
 
     /**
-     * Invoked when the secondary displays showing a keyguard window changes.
-     */
-    void onSecondaryDisplayShowingChanged(int[] displayId);
-
-    /**
      * Consumes a message that was enqueued to be displayed on the next time the bouncer shows up.
      * @return Message that should be displayed above the challenge.
      */
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/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 2d1dba6..d1e127d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -38,6 +38,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.internal.hardware.AmbientDisplayConfiguration;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
@@ -60,7 +62,6 @@
     private final Context mContext;
     private final AlarmManager mAlarmManager;
     private final SensorManager mSensorManager;
-    private final TriggerSensor[] mSensors;
     private final ContentResolver mResolver;
     private final TriggerSensor mPickupSensor;
     private final DozeParameters mDozeParameters;
@@ -68,10 +69,12 @@
     private final WakeLock mWakeLock;
     private final Consumer<Boolean> mProxCallback;
     private final Callback mCallback;
+    @VisibleForTesting
+    protected final TriggerSensor[] mSensors;
 
     private final Handler mHandler = new Handler();
     private final ProxSensor mProxSensor;
-
+    private long mDebounceFrom;
 
     public DozeSensors(Context context, AlarmManager alarmManager, SensorManager sensorManager,
             DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
@@ -134,13 +137,21 @@
                         mConfig.wakeScreenGestureAvailable() && alwaysOn,
                         DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
                         false /* reports touch coordinates */,
-                        false /* touchscreen */),
+                        false /* touchscreen */, mConfig.getWakeLockScreenDebounce()),
         };
 
         mProxSensor = new ProxSensor(policy);
         mCallback = callback;
     }
 
+    /**
+     * Temporarily disable some sensors to avoid turning on the device while the user is
+     * turning it off.
+     */
+    public void requestTemporaryDisable() {
+        mDebounceFrom = SystemClock.uptimeMillis();
+    }
+
     private Sensor findSensorWithType(String type) {
         return findSensorWithType(mSensorManager, type);
     }
@@ -320,7 +331,8 @@
         }
     }
 
-    private class TriggerSensor extends TriggerEventListener {
+    @VisibleForTesting
+    class TriggerSensor extends TriggerEventListener {
         final Sensor mSensor;
         final boolean mConfigured;
         final int mPulseReason;
@@ -467,23 +479,25 @@
     /**
      * A Sensor that is injected via plugin.
      */
-    private class PluginSensor extends TriggerSensor {
+    @VisibleForTesting
+    class PluginSensor extends TriggerSensor implements SensorManagerPlugin.SensorEventListener {
 
-        private final SensorManagerPlugin.Sensor mPluginSensor;
-        private final SensorManagerPlugin.SensorEventListener mTriggerEventListener = (event) -> {
-            DozeLog.traceSensor(mContext, mPulseReason);
-            mHandler.post(mWakeLock.wrap(() -> {
-                if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event));
-                mCallback.onSensorPulse(mPulseReason, true /* sensorPerformsProxCheck */, -1, -1,
-                        event.getValues());
-            }));
-        };
+        final SensorManagerPlugin.Sensor mPluginSensor;
+        private long mDebounce;
 
         PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
                 int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen) {
+            this(sensor, setting, configured, pulseReason, reportsTouchCoordinates,
+                    requiresTouchscreen, 0L /* debounce */);
+        }
+
+        PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
+                int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen,
+                long debounce) {
             super(null, setting, configured, pulseReason, reportsTouchCoordinates,
                     requiresTouchscreen);
             mPluginSensor = sensor;
+            mDebounce = debounce;
         }
 
         @Override
@@ -492,11 +506,11 @@
             AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager;
             if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
                     && !mRegistered) {
-                asyncSensorManager.registerPluginListener(mPluginSensor, mTriggerEventListener);
+                asyncSensorManager.registerPluginListener(mPluginSensor, this);
                 mRegistered = true;
                 if (DEBUG) Log.d(TAG, "registerPluginListener");
             } else if (mRegistered) {
-                asyncSensorManager.unregisterPluginListener(mPluginSensor, mTriggerEventListener);
+                asyncSensorManager.unregisterPluginListener(mPluginSensor, this);
                 mRegistered = false;
                 if (DEBUG) Log.d(TAG, "unregisterPluginListener");
             }
@@ -524,6 +538,21 @@
             }
             return sb.append(']').toString();
         }
+
+        @Override
+        public void onSensorChanged(SensorManagerPlugin.SensorEvent event) {
+            DozeLog.traceSensor(mContext, mPulseReason);
+            mHandler.post(mWakeLock.wrap(() -> {
+                final long now = SystemClock.uptimeMillis();
+                if (now < mDebounceFrom + mDebounce) {
+                    if (DEBUG) Log.d(TAG, "onSensorEvent dropped: " + triggerEventToString(event));
+                    return;
+                }
+                if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event));
+                mCallback.onSensorPulse(mPulseReason, true /* sensorPerformsProxCheck */, -1, -1,
+                        event.getValues());
+            }));
+        }
     }
 
     public interface Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 70bf903..b6e830c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -143,8 +143,12 @@
 
         if (isWakeDisplay) {
             onWakeScreen(wakeEvent, mMachine.getState());
-        } else if (isLongPress || isWakeLockScreen) {
+        } else if (isLongPress) {
             requestPulse(pulseReason, sensorPerformedProxCheck);
+        } else if (isWakeLockScreen) {
+            if (wakeEvent) {
+                requestPulse(pulseReason, sensorPerformedProxCheck);
+            }
         } else {
             proximityCheckThenCall((result) -> {
                 if (result == ProximityCheck.RESULT_NEAR) {
@@ -228,6 +232,7 @@
                 if (mDockManager != null) {
                     mDockManager.addListener(mDockEventListener);
                 }
+                mDozeSensors.requestTemporaryDisable();
                 checkTriggersAtInit();
                 break;
             case DOZE:
@@ -250,6 +255,9 @@
                 mDozeSensors.setTouchscreenSensorsListening(false);
                 mDozeSensors.setProxListening(true);
                 break;
+            case DOZE_PULSE_DONE:
+                mDozeSensors.requestTemporaryDisable();
+                break;
             case FINISH:
                 mBroadcastReceiver.unregister(mContext);
                 mDozeHost.removeCallback(mHostCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 66cfadf..172746e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -21,7 +21,6 @@
 import static com.android.internal.telephony.IccCardConstants.State.ABSENT;
 import static com.android.internal.telephony.IccCardConstants.State.PIN_REQUIRED;
 import static com.android.internal.telephony.IccCardConstants.State.PUK_REQUIRED;
-import static com.android.internal.telephony.IccCardConstants.State.READY;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -95,7 +94,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Arrays;
 
 /**
  * Mediates requests related to the keyguard.  This includes queries about the
@@ -247,9 +245,6 @@
     // AOD is enabled and status bar is in AOD state.
     private boolean mAodShowing;
 
-    // display ids of the external display on which we have put a keyguard window
-    private int[] mSecondaryDisplaysShowing;
-
     /** Cached value of #isInputRestricted */
     private boolean mInputRestricted;
 
@@ -687,13 +682,6 @@
             mCustomMessage = null;
             return message;
         }
-
-        @Override
-        public void onSecondaryDisplayShowingChanged(int[] displayIds) {
-            synchronized (KeyguardViewMediator.this) {
-                setShowingLocked(mShowing, mAodShowing, displayIds, false);
-            }
-        }
     };
 
     public void userActivity() {
@@ -722,7 +710,7 @@
         mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter,
                 SYSTEMUI_PERMISSION, null /* scheduler */);
 
-        mKeyguardDisplayManager = new KeyguardDisplayManager(mContext, mViewMediatorCallback);
+        mKeyguardDisplayManager = new KeyguardDisplayManager(mContext);
 
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
 
@@ -738,10 +726,10 @@
             setShowingLocked(!shouldWaitForProvisioning()
                     && !mLockPatternUtils.isLockScreenDisabled(
                             KeyguardUpdateMonitor.getCurrentUser()),
-                    mAodShowing, mSecondaryDisplaysShowing, true /* forceCallbacks */);
+                    mAodShowing, true /* forceCallbacks */);
         } else {
             // The system's keyguard is disabled or missing.
-            setShowingLocked(false, mAodShowing, mSecondaryDisplaysShowing, true);
+            setShowingLocked(false, mAodShowing, true);
         }
 
         mStatusBarKeyguardViewManager =
@@ -1764,12 +1752,10 @@
         playSound(mTrustedSoundId);
     }
 
-    private void updateActivityLockScreenState(boolean showing, boolean aodShowing,
-            int[] secondaryDisplaysShowing) {
+    private void updateActivityLockScreenState(boolean showing, boolean aodShowing) {
         mUiOffloadThread.submit(() -> {
             try {
-                ActivityTaskManager.getService().setLockScreenShown(showing, aodShowing,
-                        secondaryDisplaysShowing);
+                ActivityTaskManager.getService().setLockScreenShown(showing, aodShowing);
             } catch (RemoteException e) {
             }
         });
@@ -1892,8 +1878,7 @@
 
             if (!mHiding) {
                 // Tell ActivityManager that we canceled the keyguardExitAnimation.
-                setShowingLocked(mShowing, mAodShowing, mSecondaryDisplaysShowing,
-                        true /* force */);
+                setShowingLocked(mShowing, mAodShowing, true /* force */);
                 return;
             }
             mHiding = false;
@@ -2163,23 +2148,19 @@
     }
 
     private void setShowingLocked(boolean showing, boolean aodShowing) {
-        setShowingLocked(showing, aodShowing, mSecondaryDisplaysShowing,
-                false /* forceCallbacks */);
+        setShowingLocked(showing, aodShowing, false /* forceCallbacks */);
     }
 
-    private void setShowingLocked(boolean showing, boolean aodShowing,
-            int[] secondaryDisplaysShowing, boolean forceCallbacks) {
+    private void setShowingLocked(boolean showing, boolean aodShowing, boolean forceCallbacks) {
         final boolean notifyDefaultDisplayCallbacks = showing != mShowing
                 || aodShowing != mAodShowing || forceCallbacks;
-        if (notifyDefaultDisplayCallbacks
-                || !Arrays.equals(secondaryDisplaysShowing, mSecondaryDisplaysShowing)) {
+        if (notifyDefaultDisplayCallbacks) {
             mShowing = showing;
             mAodShowing = aodShowing;
-            mSecondaryDisplaysShowing = secondaryDisplaysShowing;
             if (notifyDefaultDisplayCallbacks) {
                 notifyDefaultDisplayCallbacks(showing);
             }
-            updateActivityLockScreenState(showing, aodShowing, secondaryDisplaysShowing);
+            updateActivityLockScreenState(showing, aodShowing);
         }
     }
 
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/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/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index ad4ba75..d3ff63a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -34,9 +34,12 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.view.ActionMode;
 import android.view.DisplayCutout;
+import android.view.GestureDetector;
 import android.view.InputDevice;
 import android.view.InputQueue;
 import android.view.KeyEvent;
@@ -53,6 +56,7 @@
 import android.widget.FrameLayout;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.hardware.AmbientDisplayConfiguration;
 import com.android.internal.view.FloatingActionMode;
 import com.android.internal.widget.FloatingToolbar;
 import com.android.systemui.Dependency;
@@ -63,16 +67,23 @@
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.tuner.TunerService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
+/**
+ * Combined status bar and notification panel view. Also holding backdrop and scrims.
+ */
 public class StatusBarWindowView extends FrameLayout {
     public static final String TAG = "StatusBarWindowView";
     public static final boolean DEBUG = StatusBar.DEBUG;
 
+    private final GestureDetector mGestureDetector;
+    private final StatusBarStateController mStatusBarStateController;
+    private boolean mDoubleTapEnabled;
+    private boolean mSingleTapEnabled;
     private DragDownHelper mDragDownHelper;
-    private DoubleTapHelper mDoubleTapHelper;
     private NotificationStackScrollLayout mStackScrollLayout;
     private NotificationPanelView mNotificationPanel;
     private View mBrightnessMirror;
@@ -95,8 +106,37 @@
     private boolean mTouchActive;
     private boolean mExpandAnimationRunning;
     private boolean mExpandAnimationPending;
-    private final StatusBarStateController
-            mStatusBarStateController = Dependency.get(StatusBarStateController.class);
+
+    private final GestureDetector.SimpleOnGestureListener mGestureListener =
+            new GestureDetector.SimpleOnGestureListener() {
+        @Override
+        public boolean onSingleTapConfirmed(MotionEvent e) {
+            if (mSingleTapEnabled) {
+                mService.wakeUpIfDozing(SystemClock.uptimeMillis(), StatusBarWindowView.this,
+                        "SINGLE_TAP");
+            }
+            return mSingleTapEnabled;
+        }
+
+        @Override
+        public boolean onDoubleTap(MotionEvent e) {
+            if (mDoubleTapEnabled) {
+                mService.wakeUpIfDozing(SystemClock.uptimeMillis(), StatusBarWindowView.this,
+                        "DOUBLE_TAP");
+            }
+            return mDoubleTapEnabled;
+        }
+    };
+    private final TunerService.Tunable mTunable = (key, newValue) -> {
+        AmbientDisplayConfiguration configuration = new AmbientDisplayConfiguration(mContext);
+        switch (key) {
+            case Settings.Secure.DOZE_DOUBLE_TAP_GESTURE:
+                mDoubleTapEnabled = configuration.doubleTapGestureEnabled(UserHandle.USER_CURRENT);
+                break;
+            case Settings.Secure.DOZE_TAP_SCREEN_GESTURE:
+                mSingleTapEnabled = configuration.tapGestureEnabled(UserHandle.USER_CURRENT);
+        }
+    };
 
     /**
      * If set to true, the current gesture started below the notch and we need to dispatch touch
@@ -110,10 +150,11 @@
         mTransparentSrcPaint.setColor(0);
         mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
         mFalsingManager = FalsingManager.getInstance(context);
-        mDoubleTapHelper = new DoubleTapHelper(this, active -> {}, () -> {
-            mService.wakeUpIfDozing(SystemClock.uptimeMillis(), this, "DOUBLE_TAP");
-            return true;
-        }, null, null);
+        mGestureDetector = new GestureDetector(context, mGestureListener);
+        mStatusBarStateController = Dependency.get(StatusBarStateController.class);
+        Dependency.get(TunerService.class).addTunable(mTunable,
+                Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
+                Settings.Secure.DOZE_TAP_SCREEN_GESTURE);
     }
 
     @Override
@@ -306,6 +347,7 @@
             return false;
         }
         mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());
+        mGestureDetector.onTouchEvent(ev);
         if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == VISIBLE) {
             // Disallow new pointers while the brightness mirror is visible. This is so that you
             // can't touch anything other than the brightness slider while the mirror is showing
@@ -366,7 +408,6 @@
     public boolean onTouchEvent(MotionEvent ev) {
         boolean handled = false;
         if (mService.isDozing()) {
-            mDoubleTapHelper.onTouchEvent(ev);
             handled = !mService.isPulsing();
         }
         if ((mStatusBarStateController.getState() == StatusBarState.KEYGUARD && !handled)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 617b191..ffd8206 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -25,6 +25,7 @@
 import static android.media.AudioManager.STREAM_MUSIC;
 import static android.media.AudioManager.STREAM_RING;
 import static android.media.AudioManager.STREAM_VOICE_CALL;
+import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE;
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
 
@@ -431,8 +432,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 */);
@@ -442,6 +442,7 @@
 
     public void initRingerH() {
         if (mRingerIcon != null) {
+            mRingerIcon.setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE);
             mRingerIcon.setOnClickListener(v -> {
                 Prefs.putBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, true);
                 final StreamState ss = mState.states.get(AudioManager.STREAM_RING);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index e91a7e9..0114075 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -29,6 +29,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -82,6 +83,9 @@
         mTestableLooper = TestableLooper.get(this);
         mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
                 new Handler(mTestableLooper.getLooper()));
+        mTunablePaddingService = mDependency.injectMockDependency(TunablePaddingService.class);
+        mTunerService = mDependency.injectMockDependency(TunerService.class);
+        mFragmentService = mDependency.injectMockDependency(FragmentService.class);
 
         mStatusBar = mock(StatusBar.class);
         mWindowManager = mock(WindowManager.class);
@@ -93,12 +97,9 @@
         when(mWindowManager.getDefaultDisplay()).thenReturn(display);
         mContext.addMockSystemService(WindowManager.class, mWindowManager);
 
-        mFragmentService = mDependency.injectMockDependency(FragmentService.class);
         mFragmentHostManager = mock(FragmentHostManager.class);
         when(mFragmentService.getFragmentHostManager(any())).thenReturn(mFragmentHostManager);
 
-        mTunerService = mDependency.injectMockDependency(TunerService.class);
-
 
         mScreenDecorations = new ScreenDecorations() {
             @Override
@@ -126,8 +127,7 @@
         };
         mScreenDecorations.mContext = mContext;
         mScreenDecorations.mComponents = mContext.getComponents();
-
-        mTunablePaddingService = mDependency.injectMockDependency(TunablePaddingService.class);
+        reset(mTunerService);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
new file mode 100644
index 0000000..066dff2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.doze;
+
+import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AlarmManager;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.internal.hardware.AmbientDisplayConfiguration;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.SensorManagerPlugin;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.util.AsyncSensorManager;
+import com.android.systemui.util.wakelock.WakeLock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.Consumer;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class DozeSensorsTest extends SysuiTestCase {
+
+    @Mock
+    private AlarmManager mAlarmManager;
+    @Mock
+    private AsyncSensorManager mSensorManager;
+    @Mock
+    private DozeParameters mDozeParameters;
+    @Mock
+    private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
+    @Mock
+    private WakeLock mWakeLock;
+    @Mock
+    private DozeSensors.Callback mCallback;
+    @Mock
+    private Consumer<Boolean> mProxCallback;
+    @Mock
+    private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy;
+    private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
+    private TestableLooper mTestableLooper;
+    private DozeSensors mDozeSensors;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mTestableLooper = TestableLooper.get(this);
+        when(mAmbientDisplayConfiguration.getWakeLockScreenDebounce()).thenReturn(5000L);
+        when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
+        doAnswer(invocation -> {
+            ((Runnable) invocation.getArgument(0)).run();
+            return null;
+        }).when(mWakeLock).wrap(any(Runnable.class));
+        mDozeSensors = new TestableDozeSensors();
+    }
+
+    @Test
+    public void testSensorDebounce() {
+        mDozeSensors.setListening(true);
+
+        mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class));
+        mTestableLooper.processAllMessages();
+        verify(mCallback).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN),
+                anyBoolean(), anyFloat(), anyFloat(), eq(null));
+
+        mDozeSensors.requestTemporaryDisable();
+        reset(mCallback);
+        mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class));
+        mTestableLooper.processAllMessages();
+        verify(mCallback, never()).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN),
+                anyBoolean(), anyFloat(), anyFloat(), eq(null));
+    }
+
+    private class TestableDozeSensors extends DozeSensors {
+
+        TestableDozeSensors() {
+            super(getContext(), mAlarmManager, mSensorManager, mDozeParameters,
+                    mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback,
+                    mAlwaysOnDisplayPolicy);
+            for (TriggerSensor sensor : mSensors) {
+                if (sensor instanceof PluginSensor
+                        && ((PluginSensor) sensor).mPluginSensor.getType()
+                        == TYPE_WAKE_LOCK_SCREEN) {
+                    mWakeLockScreenListener = (PluginSensor) sensor;
+                }
+            }
+        }
+    }
+}
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/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index b3e5f69..9505f33 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7017,6 +7017,23 @@
     // OS: Q
     ACTION_SWITCH_SHARE_PROFILE = 1661;
 
+    // ACTION: Show Contextual homepage, log latency in loading cards
+    ACTION_CONTEXTUAL_HOME_SHOW = 1662;
+
+    // ACTION: Contextual card displays
+    ACTION_CONTEXTUAL_CARD_SHOW = 1663;
+
+    // ACTION: Contextual cards are eligible to be shown, but don't rank high
+    ACTION_CONTEXTUAL_CARD_NOT_SHOW = 1664;
+
+    // ACTION: Settings > long press a card, and click dismiss
+    // Contextual card is dismissed
+    ACTION_CONTEXTUAL_CARD_DISMISS = 1665;
+
+    // ACTION: Settings > click a card
+    // Contextual card is clicked
+    ACTION_CONTEXTUAL_CARD_CLICK = 1666;
+
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
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/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 1cca813..245e2c9 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -70,6 +70,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.infra.AbstractRemoteService;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
@@ -109,6 +110,8 @@
     private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN = '[';
     private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_END = ']';
 
+    private static final int DEFAULT_AUGMENTED_AUTOFILL_REQUEST_TIMEOUT_MILLIS = 5_000;
+
     /**
      * Maximum number of partitions that can be allowed in a session.
      *
@@ -162,6 +165,11 @@
     @GuardedBy("mLock")
     private int mSupportedSmartSuggestionModes;
 
+    @GuardedBy("mLock")
+    int mAugmentedServiceIdleUnbindTimeoutMs;
+    @GuardedBy("mLock")
+    int mAugmentedServiceRequestTimeoutMs;
+
     public AutofillManagerService(Context context) {
         super(context,
                 new SecureSettingsServiceNameResolver(context, Settings.Secure.AUTOFILL_SERVICE),
@@ -171,12 +179,12 @@
 
         DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_AUTOFILL,
                 ActivityThread.currentApplication().getMainExecutor(),
-                (namespace, name, value) -> setSmartSuggestionModesFromDeviceConfig(value));
+                (namespace, key, value) -> onDeviceConfigChange(key, value));
 
         setLogLevelFromSettings();
         setMaxPartitionsFromSettings();
         setMaxVisibleDatasetsFromSettings();
-        setSmartSuggestionModesFromDeviceConfig();
+        setDeviceConfigProperties();
 
         final IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -227,6 +235,18 @@
         }
     }
 
+    private void onDeviceConfigChange(@NonNull String key, @Nullable String value) {
+        switch (key) {
+            case AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES:
+            case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT:
+            case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT:
+                setDeviceConfigProperties();
+                break;
+            default:
+                Slog.i(mTag, "Ignoring change on " + key);
+        }
+    }
+
     @Override // from AbstractMasterSystemService
     protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId,
             boolean disabled) {
@@ -457,27 +477,24 @@
         }
     }
 
-    private void setSmartSuggestionModesFromDeviceConfig() {
-        final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_AUTOFILL,
-                AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES);
-        setSmartSuggestionModesFromDeviceConfig(value);
-    }
-
-    private void setSmartSuggestionModesFromDeviceConfig(@Nullable String value) {
-        if (sDebug) Slog.d(TAG, "setSmartSuggestionEmulationFromDeviceConfig(): value=" + value);
-        final int flags;
-        if (value == null) {
-            flags = AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
-        } else {
-            try {
-                flags = Integer.parseInt(value);
-            } catch (Exception e) {
-                Slog.w(TAG, "setSmartSuggestionEmulationFromDeviceConfig(): NAN:" + value);
-                return;
-            }
-        }
+    private void setDeviceConfigProperties() {
         synchronized (mLock) {
-            mSupportedSmartSuggestionModes = flags;
+            mAugmentedServiceIdleUnbindTimeoutMs = Helper.getIntDeviceConfigProperty(
+                    AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT,
+                    (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS);
+            mAugmentedServiceRequestTimeoutMs = Helper.getIntDeviceConfigProperty(
+                    AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT,
+                    DEFAULT_AUGMENTED_AUTOFILL_REQUEST_TIMEOUT_MILLIS);
+            mSupportedSmartSuggestionModes = Helper.getIntDeviceConfigProperty(
+                    AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES,
+                    AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM);
+            if (verbose) {
+                Slog.v(mTag, "setDeviceConfigProperties(): "
+                        + "augmentedIdleTimeout=" + mAugmentedServiceIdleUnbindTimeoutMs
+                        + ", augmentedRequestTimeout=" + mAugmentedServiceRequestTimeoutMs
+                        + ", smartSuggestionMode="
+                        + getSmartSuggestionModeToString(mSupportedSmartSuggestionModes));
+            }
         }
     }
 
@@ -1280,6 +1297,10 @@
                         pw.print("Smart Suggestion modes: ");
                         pw.println(getSmartSuggestionModeToString(mSupportedSmartSuggestionModes));
                     }
+                    pw.print("Augmented Service Idle Unbind Timeout: ");
+                    pw.println(mAugmentedServiceIdleUnbindTimeoutMs);
+                    pw.print("Augmented Service Request Timeout: ");
+                    pw.println(mAugmentedServiceRequestTimeoutMs);
                     if (showHistory) {
                         pw.println(); pw.println("Requests history:"); pw.println();
                         mRequestsHistory.reverseDump(fd, pw, args);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 2e99654..3f33813 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -98,7 +98,7 @@
     private static final int MAX_SESSION_ID_CREATE_TRIES = 2048;
 
     /** Minimum interval to prune abandoned sessions */
-    private static final int MAX_ABANDONED_SESSION_MILLIS = 30000;
+    private static final int MAX_ABANDONED_SESSION_MILLIS = 30_000;
 
     private final AutoFillUI mUi;
     private final MetricsLogger mMetricsLogger = new MetricsLogger();
@@ -1087,7 +1087,9 @@
                             }
                             mRemoteAugmentedAutofillService = null;
                         }
-                    }, mMaster.isInstantServiceAllowed(), mMaster.verbose);
+                    }, mMaster.isInstantServiceAllowed(), mMaster.verbose,
+                    mMaster.mAugmentedServiceIdleUnbindTimeoutMs,
+                    mMaster.mAugmentedServiceRequestTimeoutMs);
         }
 
         return mRemoteAugmentedAutofillService;
@@ -1097,14 +1099,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/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 3c0da7d..d300bf2 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -22,9 +22,11 @@
 import android.app.assist.AssistStructure.ViewNode;
 import android.content.ComponentName;
 import android.metrics.LogMaker;
+import android.provider.DeviceConfig;
 import android.service.autofill.Dataset;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.Slog;
 import android.view.WindowManager;
 import android.view.autofill.AutofillId;
@@ -205,6 +207,21 @@
         }
     }
 
+    /**
+     * Gets the value of a device config property from the Autofill namespace.
+     */
+    static int getIntDeviceConfigProperty(@NonNull String key, int defaultValue) {
+        final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_AUTOFILL, key);
+        if (value == null) return defaultValue;
+
+        try {
+            return Integer.parseInt(value);
+        } catch (Exception e) {
+            Log.w(TAG, "error parsing value (" + value + ") of property " + key + ": " + e);
+            return defaultValue;
+        }
+    }
+
     private interface ViewNodeFilter {
         boolean matches(ViewNode node);
     }
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 88228fb..a38c3cf 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -31,7 +31,6 @@
 import android.service.autofill.augmented.AugmentedAutofillService;
 import android.service.autofill.augmented.IAugmentedAutofillService;
 import android.service.autofill.augmented.IFillCallback;
-import android.text.format.DateUtils;
 import android.util.Pair;
 import android.util.Slog;
 import android.view.autofill.AutofillId;
@@ -48,13 +47,17 @@
 
     private static final String TAG = RemoteAugmentedAutofillService.class.getSimpleName();
 
-    private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
+    private final int mIdleUnbindTimeoutMs;
+    private final int mRequestTimeoutMs;
 
     RemoteAugmentedAutofillService(Context context, ComponentName serviceName,
             int userId, RemoteAugmentedAutofillServiceCallbacks callbacks,
-            boolean bindInstantServiceAllowed, boolean verbose) {
+            boolean bindInstantServiceAllowed, boolean verbose, int idleUnbindTimeoutMs,
+            int requestTimeoutMs) {
         super(context, AugmentedAutofillService.SERVICE_INTERFACE, serviceName, userId, callbacks,
                 bindInstantServiceAllowed, verbose);
+        mIdleUnbindTimeoutMs = idleUnbindTimeoutMs;
+        mRequestTimeoutMs = requestTimeoutMs;
 
         // Bind right away.
         scheduleBind();
@@ -108,12 +111,12 @@
 
     @Override // from AbstractRemoteService
     protected long getTimeoutIdleBindMillis() {
-        return PERMANENT_BOUND_TIMEOUT_MS;
+        return mIdleUnbindTimeoutMs;
     }
 
     @Override // from AbstractRemoteService
     protected long getRemoteRequestMillis() {
-        return TIMEOUT_REMOTE_REQUEST_MILLIS;
+        return mRequestTimeoutMs;
     }
 
     /**
@@ -209,7 +212,7 @@
         protected void onTimeout(RemoteAugmentedAutofillService remoteService) {
             // TODO(b/122858578): must update the logged AUTOFILL_AUGMENTED_REQUEST with the
             // timeout
-            Slog.w(TAG, "PendingAutofillRequest timed out (" + TIMEOUT_REMOTE_REQUEST_MILLIS
+            Slog.w(TAG, "PendingAutofillRequest timed out (" + remoteService.mRequestTimeoutMs
                     + "ms) for " + remoteService);
             // NOTE: so far we don't need notify RemoteAugmentedAutofillServiceCallbacks
             finish();
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..9f7a940 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;
+    @GuardedBy("mLock") int mDevCfgLoggingLevel;
+    @GuardedBy("mLock") int mDevCfgMaxBufferSize;
+    @GuardedBy("mLock") int mDevCfgIdleFlushingFrequencyMs;
+    @GuardedBy("mLock") int mDevCfgTextChangeFlushingFrequencyMs;
+    @GuardedBy("mLock") int mDevCfgLogHistorySize;
+    @GuardedBy("mLock") 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:
@@ -246,22 +249,29 @@
     }
 
     private void setFineTuneParamsFromDeviceConfig() {
-        mDevCfgMaxBufferSize = ContentCaptureHelper.getIntDeviceConfigProperty(
-                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE,
-                ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE);
-        mDevCfgIdleFlushingFrequencyMs = ContentCaptureHelper.getIntDeviceConfigProperty(
-                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY,
-                ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS);
-        mDevCfgTextChangeFlushingFrequencyMs = ContentCaptureHelper.getIntDeviceConfigProperty(
-                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY,
-                ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS);
-        mDevCfgLogHistorySize = ContentCaptureHelper.getIntDeviceConfigProperty(
-                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE, 20);
-        if (verbose) {
-            Slog.v(mTag, "setFineTuneParamsFromDeviceConfig(): bufferSize=" + mDevCfgMaxBufferSize
-                    + ", idleFlush=" + mDevCfgIdleFlushingFrequencyMs
-                    + ", textFluxh=" + mDevCfgTextChangeFlushingFrequencyMs
-                    + ", logHistory=" + mDevCfgLogHistorySize);
+        synchronized (mLock) {
+            mDevCfgMaxBufferSize = ContentCaptureHelper.getIntDeviceConfigProperty(
+                    ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE,
+                    ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE);
+            mDevCfgIdleFlushingFrequencyMs = ContentCaptureHelper.getIntDeviceConfigProperty(
+                    ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY,
+                    ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS);
+            mDevCfgTextChangeFlushingFrequencyMs = ContentCaptureHelper.getIntDeviceConfigProperty(
+                    ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY,
+                    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
+                        + ", idleUnbindTimeoutMs=" + mDevCfgIdleUnbindTimeoutMs);
+            }
         }
     }
 
@@ -472,6 +482,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/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index fd946cd..5633082c 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -177,8 +177,6 @@
 
     private ServiceState[] mServiceState;
 
-    private int[] mNetworkType;
-
     private int[] mVoiceActivationState;
 
     private int[] mDataActivationState;
@@ -213,6 +211,9 @@
     private CallAttributes mCallAttributes = new CallAttributes(new PreciseCallState(),
             TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality());
 
+    // network type of the call associated with the mCallAttributes and mCallQuality
+    private int mCallNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+
     private int[] mSrvccState;
 
     private int mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -375,7 +376,6 @@
         mDataConnectionNetworkType = new int[numPhones];
         mCallIncomingNumber = new String[numPhones];
         mServiceState = new ServiceState[numPhones];
-        mNetworkType = new int[numPhones];
         mVoiceActivationState = new int[numPhones];
         mDataActivationState = new int[numPhones];
         mUserMobileDataState = new boolean[numPhones];
@@ -396,7 +396,6 @@
             mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
             mCallIncomingNumber[i] =  "";
             mServiceState[i] =  new ServiceState();
-            mNetworkType[i] = mServiceState[i].getVoiceNetworkType();
             mSignalStrength[i] =  new SignalStrength();
             mUserMobileDataState[i] = false;
             mMessageWaiting[i] =  false;
@@ -998,21 +997,6 @@
             if (validatePhoneId(phoneId)) {
                 mServiceState[phoneId] = state;
 
-                boolean notifyCallAttributes = true;
-                if (mNetworkType[phoneId] != mServiceState[phoneId].getVoiceNetworkType()) {
-                    mNetworkType[phoneId] = state.getVoiceNetworkType();
-                    mCallAttributes = new CallAttributes(mPreciseCallState, mNetworkType[phoneId],
-                            mCallQuality);
-                } else {
-                    // No change to network type, so no need to notify call attributes
-                    notifyCallAttributes = false;
-                }
-
-                if (mCallQuality == null) {
-                    // No call quality reported yet, so no need to notify call attributes
-                    notifyCallAttributes = false;
-                }
-
                 for (Record r : mRecords) {
                     if (VDBG) {
                         log("notifyServiceStateForSubscriber: r=" + r + " subId=" + subId
@@ -1040,14 +1024,6 @@
                             mRemoveList.add(r.binder);
                         }
                     }
-                    if (notifyCallAttributes && r.matchPhoneStateListenerEvent(
-                                    PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED)) {
-                        try {
-                            r.callback.onCallAttributesChanged(mCallAttributes);
-                        } catch (RemoteException ex) {
-                            mRemoveList.add(r.binder);
-                        }
-                    }
                 }
             } else {
                 log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId);
@@ -1574,7 +1550,7 @@
                 log("notifyPreciseCallState: mCallQuality is null, skipping call attributes");
                 notifyCallAttributes = false;
             } else {
-                mCallAttributes = new CallAttributes(mPreciseCallState, mNetworkType[phoneId],
+                mCallAttributes = new CallAttributes(mPreciseCallState, mCallNetworkType,
                         mCallQuality);
             }
 
@@ -1840,16 +1816,16 @@
     }
 
     @Override
-    public void notifyCallQualityChanged(CallQuality callQuality, int phoneId) {
+    public void notifyCallQualityChanged(CallQuality callQuality, int phoneId,
+            int callNetworkType) {
         if (!checkNotifyPermission("notifyCallQualityChanged()")) {
             return;
         }
 
         // merge CallQuality with PreciseCallState and network type
         mCallQuality = callQuality;
-        mCallAttributes = new CallAttributes(mPreciseCallState,
-                mNetworkType[phoneId],
-                callQuality);
+        mCallNetworkType = callNetworkType;
+        mCallAttributes = new CallAttributes(mPreciseCallState, callNetworkType, callQuality);
 
         synchronized (mRecords) {
             TelephonyManager tm = (TelephonyManager) mContext.getSystemService(
@@ -1886,7 +1862,6 @@
                 pw.println("mCallState=" + mCallState[i]);
                 pw.println("mCallIncomingNumber=" + mCallIncomingNumber[i]);
                 pw.println("mServiceState=" + mServiceState[i]);
-                pw.println("mNetworkType=" + mNetworkType[i]);
                 pw.println("mVoiceActivationState= " + mVoiceActivationState[i]);
                 pw.println("mDataActivationState= " + mDataActivationState[i]);
                 pw.println("mUserMobileDataState= " + mUserMobileDataState[i]);
@@ -1900,6 +1875,7 @@
                 pw.println("mImsCallDisconnectCause=" + mImsReasonInfo.get(i).toString());
                 pw.decreaseIndent();
             }
+            pw.println("mCallNetworkType=" + mCallNetworkType);
             pw.println("mPreciseDataConnectionState=" + mPreciseDataConnectionState);
             pw.println("mPreciseCallState=" + mPreciseCallState);
             pw.println("mCallDisconnectCause=" + mCallDisconnectCause);
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/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 708de73..4485a54 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -144,7 +144,7 @@
      * Whether history is enabled.
      */
     @GuardedBy("mInMemoryLock")
-    private int mMode = AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE;
+    private int mMode = AppOpsManager.HISTORICAL_MODE_DISABLED;
 
     /**
      * This granularity has been chosen to allow clean delineation for intervals
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/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..2026957 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -31,6 +31,8 @@
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.tv.TvContract;
+import android.media.tv.TvInputInfo;
+import android.media.tv.TvInputManager.TvInputCallback;
 import android.os.SystemProperties;
 import android.provider.Settings.Global;
 import android.util.Slog;
@@ -84,10 +86,13 @@
             .get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT, "0").contains("tvinput");
 
     // Keeps the mapping (HDMI port ID to TV input URI) to keep track of the TV inputs ready to
-    // accept input switching request from HDMI devices. Requests for which the corresponding
-    // input ID is not yet registered by TV input framework need to be buffered for delayed
-    // processing.
-    private final HashMap<Integer, String> mTvInputs = new HashMap<>();
+    // accept input switching request from HDMI devices.
+    @GuardedBy("mLock")
+    private final HashMap<Integer, String> mPortIdToTvInputs = new HashMap<>();
+
+    // A map from TV input id to HDMI device info.
+    @GuardedBy("mLock")
+    private final HashMap<String, HdmiDeviceInfo> mTvInputsToDeviceInfo = new HashMap<>();
 
     // Copy of mDeviceInfos to guarantee thread-safety.
     @GuardedBy("mLock")
@@ -103,14 +108,57 @@
             mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, false);
         mSystemAudioControlFeatureEnabled =
             mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);
-        // TODO(amyjojo): Maintain a portId to TvinputId map.
-        mTvInputs.put(2, "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5");
-        mTvInputs.put(4, "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6");
-        mTvInputs.put(1, "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7");
     }
 
     private static final String SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH = "/vendor/etc/sadConfig.xml";
 
+    private final TvInputCallback mTvInputCallback = new TvInputCallback() {
+        @Override
+        public void onInputAdded(String inputId) {
+            addOrUpdateTvInput(inputId);
+        }
+
+        @Override
+        public void onInputRemoved(String inputId) {
+            removeTvInput(inputId);
+        }
+
+        @Override
+        public void onInputUpdated(String inputId) {
+            addOrUpdateTvInput(inputId);
+        }
+    };
+
+    @ServiceThreadOnly
+    private void addOrUpdateTvInput(String inputId) {
+        assertRunOnServiceThread();
+        synchronized (mLock) {
+            TvInputInfo tvInfo = mService.getTvInputManager().getTvInputInfo(inputId);
+            if (tvInfo == null) {
+                return;
+            }
+            HdmiDeviceInfo info = tvInfo.getHdmiDeviceInfo();
+            if (info == null) {
+                return;
+            }
+            mPortIdToTvInputs.put(info.getPortId(), inputId);
+            mTvInputsToDeviceInfo.put(inputId, info);
+        }
+    }
+
+    @ServiceThreadOnly
+    private void removeTvInput(String inputId) {
+        assertRunOnServiceThread();
+        synchronized (mLock) {
+            if (mTvInputsToDeviceInfo.get(inputId) == null) {
+                return;
+            }
+            int portId = mTvInputsToDeviceInfo.get(inputId).getPortId();
+            mPortIdToTvInputs.remove(portId);
+            mTvInputsToDeviceInfo.remove(inputId);
+        }
+    }
+
     /**
      * Called when a device is newly added or a new device is detected or
      * an existing device is updated.
@@ -248,17 +296,29 @@
         }
         if (mService.getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) {
             mCecMessageCache.flushAll();
-        } else {
-            if (connected) {
-                launchDeviceDiscovery();
-            } else {
-                // TODO(amyjojo): remove device from mDeviceInfo
+        } else if (!connected && mPortIdToTvInputs.get(portId) != null) {
+            String tvInputId = mPortIdToTvInputs.get(portId);
+            HdmiDeviceInfo info = mTvInputsToDeviceInfo.get(tvInputId);
+            if (info == null) {
+                return;
             }
+            // Update with TIF on the device removal. TIF callback will update
+            // mPortIdToTvInputs and mPortIdToTvInputs.
+            removeCecDevice(info.getLogicalAddress());
         }
     }
 
     @Override
     @ServiceThreadOnly
+    protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) {
+        super.disableDevice(initiatedByCec, callback);
+        assertRunOnServiceThread();
+        mService.unregisterTvInputCallback(mTvInputCallback);
+        // TODO(amyjojo): check disableDevice and onStandby behaviors per spec
+    }
+
+    @Override
+    @ServiceThreadOnly
     protected void onStandby(boolean initiatedByCec, int standbyAction) {
         assertRunOnServiceThread();
         mTvSystemAudioModeSupport = false;
@@ -284,6 +344,7 @@
                         mAddress, mService.getPhysicalAddress(), mDeviceType));
         mService.sendCecCommand(
                 HdmiCecMessageBuilder.buildDeviceVendorIdCommand(mAddress, mService.getVendorId()));
+        mService.registerTvInputCallback(mTvInputCallback);
         int systemAudioControlOnPowerOnProp =
                 SystemProperties.getInt(
                         PROPERTY_SYSTEM_AUDIO_CONTROL_ON_POWER_ON,
@@ -996,6 +1057,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() {
@@ -1064,9 +1136,9 @@
             setLocalActivePort(portId);
             return;
         } else {
-            String uri = mTvInputs.get(portId);
+            String uri = mPortIdToTvInputs.get(portId);
             if (uri != null) {
-                switchToTvInput(mTvInputs.get(portId));
+                switchToTvInput(uri);
             } else {
                 HdmiLogger.debug("Port number does not match any Tv Input.");
                 return;
@@ -1215,7 +1287,8 @@
         pw.println("mArcIntentUsed: " + mArcIntentUsed);
         pw.println("mRoutingPort: " + getRoutingPort());
         pw.println("mLocalActivePort: " + getLocalActivePort());
-        HdmiUtils.dumpMap(pw, "mTvInputs:", mTvInputs);
+        HdmiUtils.dumpMap(pw, "mPortIdToTvInputs:", mPortIdToTvInputs);
+        HdmiUtils.dumpMap(pw, "mTvInputsToDeviceInfo:", mTvInputsToDeviceInfo);
         HdmiUtils.dumpSparseArray(pw, "mDeviceInfos:", mDeviceInfos);
         pw.decreaseIndent();
         super.dump(pw);
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 072238e..f5adb01 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -576,7 +576,8 @@
                 Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
                 Global.MHL_INPUT_SWITCHING_ENABLED,
                 Global.MHL_POWER_CHARGE_ENABLED,
-                Global.HDMI_CEC_SWITCH_ENABLED
+                Global.HDMI_CEC_SWITCH_ENABLED,
+                Global.DEVICE_NAME
         };
         for (String s : settings) {
             resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver,
@@ -642,6 +643,10 @@
                 case Global.MHL_POWER_CHARGE_ENABLED:
                     mMhlController.setOption(OPTION_MHL_POWER_CHARGE, toInt(enabled));
                     break;
+                case Global.DEVICE_NAME:
+                    String deviceName = readStringSetting(option, Build.MODEL);
+                    setDisplayName(deviceName);
+                    break;
             }
         }
     }
@@ -670,6 +675,15 @@
         return SystemProperties.getBoolean(key, defVal);
     }
 
+    String readStringSetting(String key, String defVal) {
+        ContentResolver cr = getContext().getContentResolver();
+        String content = Global.getString(cr, key);
+        if (TextUtils.isEmpty(content)) {
+            return defVal;
+        }
+        return content;
+    }
+
     private void initializeCec(int initiatedBy) {
         mAddressAllocated = false;
         mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
@@ -1178,13 +1192,29 @@
     }
 
     private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) {
-        // TODO: find better name instead of model name.
-        String displayName = Build.MODEL;
+        String displayName = readStringSetting(Global.DEVICE_NAME, Build.MODEL);
         return new HdmiDeviceInfo(logicalAddress,
                 getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType,
                 getVendorId(), displayName, powerStatus);
     }
 
+    // Set the display name in HdmiDeviceInfo of the current devices to content provided by
+    // Global.DEVICE_NAME. Only set and broadcast if the new name is different.
+    private void setDisplayName(String newDisplayName) {
+        for (HdmiCecLocalDevice device : getAllLocalDevices()) {
+            HdmiDeviceInfo deviceInfo = device.getDeviceInfo();
+            if (deviceInfo.getDisplayName().equals(newDisplayName)) {
+                continue;
+            }
+            device.setDeviceInfo(new HdmiDeviceInfo(
+                    deviceInfo.getLogicalAddress(), deviceInfo.getPhysicalAddress(),
+                    deviceInfo.getPortId(), deviceInfo.getDeviceType(), deviceInfo.getVendorId(),
+                    newDisplayName, deviceInfo.getDevicePowerStatus()));
+            sendCecCommand(HdmiCecMessageBuilder.buildSetOsdNameCommand(
+                    device.mAddress, Constants.ADDR_TV, newDisplayName));
+        }
+    }
+
     @ServiceThreadOnly
     void handleMhlHotplugEvent(int portId, boolean connected) {
         assertRunOnServiceThread();
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/job/controllers/StorageController.java b/services/core/java/com/android/server/job/controllers/StorageController.java
index c2ae53f..51187df 100644
--- a/services/core/java/com/android/server/job/controllers/StorageController.java
+++ b/services/core/java/com/android/server/job/controllers/StorageController.java
@@ -81,20 +81,16 @@
         synchronized (mLock) {
             for (int i = mTrackedTasks.size() - 1; i >= 0; i--) {
                 final JobStatus ts = mTrackedTasks.valueAt(i);
-                boolean previous = ts.setStorageNotLowConstraintSatisfied(storageNotLow);
-                if (previous != storageNotLow) {
-                    reportChange = true;
-                }
+                reportChange |= ts.setStorageNotLowConstraintSatisfied(storageNotLow);
             }
         }
-        // Let the scheduler know that state has changed. This may or may not result in an
-        // execution.
-        if (reportChange) {
-            mStateChangedListener.onControllerStateChanged();
-        }
-        // Also tell the scheduler that any ready jobs should be flushed.
         if (storageNotLow) {
+            // Tell the scheduler that any ready jobs should be flushed.
             mStateChangedListener.onRunJobNow(null);
+        } else if (reportChange) {
+            // Let the scheduler know that state has changed. This may or may not result in an
+            // execution.
+            mStateChangedListener.onControllerStateChanged();
         }
     }
 
@@ -143,9 +139,10 @@
                             + sElapsedRealtimeClock.millis());
                 }
                 mStorageLow = true;
+                maybeReportNewStorageState();
             } else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
                 if (DEBUG) {
-                    Slog.d(TAG, "Available stoage high enough to do work. @ "
+                    Slog.d(TAG, "Available storage high enough to do work. @ "
                             + sElapsedRealtimeClock.millis());
                 }
                 mStorageLow = false;
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/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index aa85c83..d83eb08 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1966,7 +1966,8 @@
         } catch (RemoteException ex) {
             Slog.w(TAG, "unable to clear GK secure user id");
         }
-        if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
+        UserInfo userInfo = mUserManager.getUserInfo(userId);
+        if (unknownUser || userInfo == null || userInfo.isManagedProfile()) {
             removeKeystoreProfileKey(userId);
         }
     }
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 4dd58e0..46dfd13 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -22,6 +22,10 @@
 import android.apex.ApexInfoList;
 import android.apex.ApexSessionInfo;
 import android.apex.IApexService;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageParserException;
@@ -49,17 +53,29 @@
 class ApexManager {
     static final String TAG = "ApexManager";
     private final IApexService mApexService;
+    private final Context mContext;
     private final Object mLock = new Object();
     @GuardedBy("mLock")
     private Map<String, PackageInfo> mActivePackagesCache;
 
-    ApexManager() {
+    ApexManager(Context context) {
         try {
             mApexService = IApexService.Stub.asInterface(
                 ServiceManager.getServiceOrThrow("apexservice"));
         } catch (ServiceNotFoundException e) {
             throw new IllegalStateException("Required service apexservice not available");
         }
+        mContext = context;
+    }
+
+    void systemReady() {
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                onBootCompleted();
+                mContext.unregisterReceiver(this);
+            }
+        }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
     }
 
     private void populateActivePackagesCacheIfNeeded() {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index cced0f4..eeb4812 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -28,10 +28,8 @@
 import android.app.PackageDeleteObserver;
 import android.app.PackageInstallObserver;
 import android.app.admin.DevicePolicyManagerInternal;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
 import android.content.pm.ApplicationInfo;
@@ -141,7 +139,7 @@
 
     private final Callbacks mCallbacks;
 
-    private volatile boolean mBootCompleted = false;
+    private volatile boolean mOkToSendBroadcasts = false;
 
     /**
      * File storing persisted {@link #mSessions} metadata.
@@ -209,26 +207,13 @@
         mStagingManager = new StagingManager(pm, this, am);
     }
 
-    private void onBootCompleted()  {
-        mBootCompleted = true;
-        // Tell APEX manager about it as well
-        mApexManager.onBootCompleted();
-    }
-
-    boolean isBootCompleted()  {
-        return mBootCompleted;
+    boolean okToSendBroadcasts()  {
+        return mOkToSendBroadcasts;
     }
 
     public void systemReady() {
         mAppOps = mContext.getSystemService(AppOpsManager.class);
 
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                onBootCompleted();
-                mContext.unregisterReceiver(this);
-            }
-        }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
         synchronized (mSessions) {
             readSessionsLocked();
 
@@ -271,6 +256,16 @@
         for (PackageInstallerSession session : stagedSessionsToRestore) {
             mStagingManager.restoreSession(session);
         }
+        // Broadcasts are not sent while we restore sessions on boot, since no processes would be
+        // ready to listen to them. From now on, we greedily assume that broadcasts requests are
+        // safe to send out. The worst that can happen is that a broadcast is attempted before
+        // ActivityManagerService completes its own systemReady(), in which case it will be rejected
+        // with an otherwise harmless exception.
+        // A more appropriate way to do this would be to wait until the correct  boot phase is
+        // reached, but since we are not a SystemService we can't override onBootPhase.
+        // Waiting on the BOOT_COMPLETED broadcast can take several minutes, so that's not a viable
+        // way either.
+        mOkToSendBroadcasts = true;
     }
 
     @GuardedBy("mSessions")
@@ -1189,7 +1184,7 @@
 
         public void onStagedSessionChanged(PackageInstallerSession session) {
             writeSessionsAsync();
-            if (mBootCompleted) {
+            if (mOkToSendBroadcasts) {
                 mPm.sendSessionUpdatedBroadcast(session.generateInfo(false),
                         session.userId);
             }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 7ed49fc..dbf8a4b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2008,7 +2008,7 @@
 
         // Send broadcast to default launcher only if it's a new install
         final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
-        if (success && isNewInstall && mPm.mInstallerService.isBootCompleted()) {
+        if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()) {
             mPm.sendSessionCommitBroadcast(generateInfo(), userId);
         }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e7e3e83..20829b5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3101,7 +3101,7 @@
                 }
             }
 
-            mApexManager = new ApexManager();
+            mApexManager = new ApexManager(context);
             mInstallerService = new PackageInstallerService(context, this, mApexManager);
             final Pair<ComponentName, String> instantAppResolverComponent =
                     getInstantAppResolverLPr();
@@ -20706,6 +20706,7 @@
         storage.registerListener(mStorageListener);
 
         mInstallerService.systemReady();
+        mApexManager.systemReady();
         mPackageDexOptimizer.systemReady();
 
         getStorageManagerInternal().addExternalStoragePolicy(
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/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/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java
index cf026e9..0db3d78 100644
--- a/services/core/java/com/android/server/policy/DisplayFoldController.java
+++ b/services/core/java/com/android/server/policy/DisplayFoldController.java
@@ -35,10 +35,12 @@
 
 /**
  * Controls the behavior of foldable devices whose screen can literally bend and fold.
+ * TODO(b/126160895): Move DisplayFoldController from PhoneWindowManager to DisplayPolicy.
  */
 class DisplayFoldController {
 
     private static final String TAG = "DisplayFoldController";
+
     private final WindowManagerInternal mWindowManagerInternal;
     private final DisplayManagerInternal mDisplayManagerInternal;
     private final int mDisplayId;
@@ -52,6 +54,8 @@
     private final DisplayInfo mNonOverrideDisplayInfo = new DisplayInfo();
     private final RemoteCallbackList<IDisplayFoldListener> mListeners = new RemoteCallbackList<>();
     private Boolean mFolded;
+    private String mFocusedApp;
+    private final DisplayFoldDurationLogger mDurationLogger = new DisplayFoldDurationLogger();
 
     DisplayFoldController(WindowManagerInternal windowManagerInternal,
             DisplayManagerInternal displayManagerInternal, int displayId, Rect foldedArea,
@@ -63,6 +67,14 @@
         mHandler = handler;
     }
 
+    void finishedGoingToSleep() {
+        mDurationLogger.onFinishedGoingToSleep();
+    }
+
+    void finishedWakingUp() {
+        mDurationLogger.onFinishedWakingUp(mFolded);
+    }
+
     void requestDeviceFolded(boolean folded) {
         mHandler.post(() -> setDeviceFolded(folded));
     }
@@ -97,6 +109,8 @@
             mWindowManagerInternal.clearForcedDisplaySize(mDisplayId);
             mDisplayManagerInternal.setDisplayOffsets(mDisplayId, 0, 0);
         }
+        mDurationLogger.setDeviceFolded(folded);
+        mDurationLogger.logFocusedAppWithFoldState(folded, mFocusedApp);
         mFolded = folded;
 
         final int n = mListeners.beginBroadcast();
@@ -167,6 +181,10 @@
         return result;
     }
 
+    void onDefaultDisplayFocusChanged(String pkg) {
+        mFocusedApp = pkg;
+    }
+
     static DisplayFoldController create(Context context, int displayId) {
         final DisplayManagerInternal displayService =
                 LocalServices.getService(DisplayManagerInternal.class);
diff --git a/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java b/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java
new file mode 100644
index 0000000..bdcd2cd
--- /dev/null
+++ b/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.annotation.IntDef;
+import android.metrics.LogMaker;
+import android.os.SystemClock;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Logger for tracking duration of usage in folded vs unfolded state.
+ */
+class DisplayFoldDurationLogger {
+    static final int SCREEN_STATE_UNKNOWN = -1;
+    static final int SCREEN_STATE_OFF = 0;
+    static final int SCREEN_STATE_ON_UNFOLDED = 1;
+    static final int SCREEN_STATE_ON_FOLDED = 2;
+
+    @IntDef(flag = true, prefix = {"SCREEN_STATE_"}, value = {
+            SCREEN_STATE_UNKNOWN,
+            SCREEN_STATE_OFF,
+            SCREEN_STATE_ON_UNFOLDED,
+            SCREEN_STATE_ON_FOLDED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ScreenState {}
+
+    private @ScreenState int mScreenState = SCREEN_STATE_UNKNOWN;
+    private Long mLastChanged = null;
+
+    private static final int LOG_SUBTYPE_UNFOLDED = 0;
+    private static final int LOG_SUBTYPE_FOLDED = 1;
+    private static final int LOG_SUBTYPE_DURATION_MASK = 0x80000000;
+
+    private final MetricsLogger mLogger = new MetricsLogger();
+
+    void onFinishedWakingUp(Boolean folded) {
+        if (folded == null) {
+            mScreenState = SCREEN_STATE_UNKNOWN;
+        } else if (folded) {
+            mScreenState = SCREEN_STATE_ON_FOLDED;
+        } else {
+            mScreenState = SCREEN_STATE_ON_UNFOLDED;
+        }
+        mLastChanged = SystemClock.uptimeMillis();
+    }
+
+    void onFinishedGoingToSleep() {
+        log();
+        mScreenState = SCREEN_STATE_OFF;
+        mLastChanged = null;
+    }
+
+    void setDeviceFolded(boolean folded) {
+        // This function is called even when the screen is in ADO mode, but we're only
+        // interested in the case that the screen is actually on.
+        if (!isOn()) {
+            return;
+        }
+        log();
+        mScreenState = folded ? SCREEN_STATE_ON_FOLDED : SCREEN_STATE_ON_UNFOLDED;
+        mLastChanged = SystemClock.uptimeMillis();
+    }
+
+    void logFocusedAppWithFoldState(boolean folded, String packageName) {
+        mLogger.write(
+                new LogMaker(MetricsProto.MetricsEvent.ACTION_DISPLAY_FOLD)
+                        .setType(MetricsProto.MetricsEvent.TYPE_ACTION)
+                        .setSubtype(folded ? LOG_SUBTYPE_FOLDED : LOG_SUBTYPE_UNFOLDED)
+                        .setPackageName(packageName));
+    }
+
+    private void log() {
+        if (mLastChanged == null) {
+            return;
+        }
+        int subtype;
+        switch (mScreenState) {
+            case SCREEN_STATE_ON_UNFOLDED:
+                subtype = LOG_SUBTYPE_UNFOLDED | LOG_SUBTYPE_DURATION_MASK;
+                break;
+            case SCREEN_STATE_ON_FOLDED:
+                subtype = LOG_SUBTYPE_FOLDED | LOG_SUBTYPE_DURATION_MASK;
+                break;
+            default:
+                return;
+        }
+        mLogger.write(
+                new LogMaker(MetricsProto.MetricsEvent.ACTION_DISPLAY_FOLD)
+                        .setType(MetricsProto.MetricsEvent.TYPE_ACTION)
+                        .setSubtype(subtype)
+                        .setLatency(SystemClock.uptimeMillis() - mLastChanged));
+    }
+
+    private boolean isOn() {
+        return mScreenState == SCREEN_STATE_ON_UNFOLDED || mScreenState == SCREEN_STATE_ON_FOLDED;
+    }
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0759419..c0e5974 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3241,6 +3241,14 @@
     }
 
     @Override
+    public void onDefaultDisplayFocusChangedLw(WindowState newFocus) {
+        if (mDisplayFoldController != null) {
+            mDisplayFoldController.onDefaultDisplayFocusChanged(
+                    newFocus != null ? newFocus.getOwningPackage() : null);
+        }
+    }
+
+    @Override
     public void registerShortcutKey(long shortcutCode, IShortcutService shortcutService)
             throws RemoteException {
         synchronized (mLock) {
@@ -4440,6 +4448,9 @@
             mKeyguardDelegate.onFinishedGoingToSleep(why,
                     mCameraGestureTriggeredDuringGoingToSleep);
         }
+        if (mDisplayFoldController != null) {
+            mDisplayFoldController.finishedGoingToSleep();
+        }
         mCameraGestureTriggeredDuringGoingToSleep = false;
     }
 
@@ -4480,6 +4491,9 @@
         if (mKeyguardDelegate != null) {
             mKeyguardDelegate.onFinishedWakingUp();
         }
+        if (mDisplayFoldController != null) {
+            mDisplayFoldController.finishedWakingUp();
+        }
     }
 
     private void wakeUpFromPowerKey(long eventTime) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 5cd0014..d58707c 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1489,6 +1489,11 @@
     }
 
     /**
+     * A new window on default display has been focused.
+     */
+    default void onDefaultDisplayFocusChangedLw(WindowState newFocus) {}
+
+    /**
      * Updates the flag about whether AOD is showing.
      *
      * @return whether the value was changed.
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index ae1090c..c408549 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -209,11 +209,8 @@
             mKeyguardState.reset();
             mHandler.post(() -> {
                 try {
-                    // There are no longer any keyguard windows on secondary displays, so pass
-                    // {@code null}. All that means is that showWhenLocked activities on
-                    // external displays now get to show.
                     ActivityTaskManager.getService().setLockScreenShown(true /* keyguardShowing */,
-                            false /* aodShowing */, null /* secondaryDisplaysShowing */);
+                            false /* aodShowing */);
                 } catch (RemoteException e) {
                     // Local call.
                 }
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/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 087de69..e976975 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2751,7 +2751,9 @@
                 final Configuration srcConfig = task.getConfiguration();
                 overrideConfig.colorMode = srcConfig.colorMode;
                 overrideConfig.densityDpi = srcConfig.densityDpi;
-                overrideConfig.screenLayout = srcConfig.screenLayout;
+                overrideConfig.screenLayout = srcConfig.screenLayout
+                        & (Configuration.SCREENLAYOUT_LONG_MASK
+                                | Configuration.SCREENLAYOUT_SIZE_MASK);
                 // The smallest screen width is the short side of screen bounds. Because the bounds
                 // and density won't be changed, smallestScreenWidthDp is also fixed.
                 overrideConfig.smallestScreenWidthDp = srcConfig.smallestScreenWidthDp;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index cb4664f..486a4ea 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3098,8 +3098,7 @@
     }
 
     @Override
-    public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing,
-            int[] secondaryDisplaysShowing) {
+    public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing) {
         if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires permission "
@@ -3116,8 +3115,7 @@
                 mH.sendMessage(msg);
             }
             try {
-                mKeyguardController.setKeyguardShown(keyguardShowing, aodShowing,
-                        secondaryDisplaysShowing);
+                mKeyguardController.setKeyguardShown(keyguardShowing, aodShowing);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index f3f507f..b028569 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2787,6 +2787,9 @@
     public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
         mFocusedWindow = newFocus;
         mLastFocusedWindow = lastFocus;
+        if (mDisplayContent.isDefaultDisplay) {
+            mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
+        }
         if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
             // If the navigation bar has been hidden or shown, we need to do another
             // layout pass to update that window.
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index b5be2ac5..feb711a 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -49,7 +49,6 @@
 import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
 
 import java.io.PrintWriter;
-import java.util.Arrays;
 
 /**
  * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
@@ -120,18 +119,15 @@
     /**
      * Update the Keyguard showing state.
      */
-    void setKeyguardShown(boolean keyguardShowing, boolean aodShowing,
-            int[] secondaryDisplaysShowing) {
+    void setKeyguardShown(boolean keyguardShowing, boolean aodShowing) {
         boolean showingChanged = keyguardShowing != mKeyguardShowing || aodShowing != mAodShowing;
         // If keyguard is going away, but SystemUI aborted the transition, need to reset state.
         showingChanged |= mKeyguardGoingAway && keyguardShowing;
-        if (!showingChanged && Arrays.equals(secondaryDisplaysShowing,
-                mSecondaryDisplayIdsShowing)) {
+        if (!showingChanged) {
             return;
         }
         mKeyguardShowing = keyguardShowing;
         mAodShowing = aodShowing;
-        mSecondaryDisplayIdsShowing = secondaryDisplaysShowing;
         mWindowManager.setAodShowing(aodShowing);
         if (showingChanged) {
             dismissDockedStackIfNeeded();
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/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index 3b17abc..48b9340 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -208,6 +208,7 @@
                 pw.println("  frame: Log trace once per frame");
                 pw.println("  transaction: Log each transaction");
                 pw.println("  size: Set the maximum log size (in KB)");
+                pw.println("  status: Print trace status");
                 pw.println("  level [lvl]: Set the log level between");
                 pw.println("    lvl may be one of:");
                 pw.println("      critical: Only visible windows with reduced information");
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/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index a1db3e8..1319bad 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -406,7 +406,7 @@
     }
 
     @Test
-    public void testFixedScreenConfigurationWhenMovingToDisplay() {
+    public void testSizeCompatMode_FixedScreenConfigurationWhenMovingToDisplay() {
         // Initialize different bounds on a new display.
         final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
         newDisplay.setBounds(0, 0, 1000, 2000);
@@ -431,7 +431,7 @@
     }
 
     @Test
-    public void testFixedScreenBoundsWhenDisplaySizeChanged() {
+    public void testSizeCompatMode_FixedScreenBoundsWhenDisplaySizeChanged() {
         when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
                 ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
         mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
@@ -446,4 +446,28 @@
 
         assertEquals(originalBounds, mActivity.getBounds());
     }
+
+    @Test
+    public void testSizeCompatMode_FixedScreenLayoutSizeBits() {
+        final int fixedScreenLayout = Configuration.SCREENLAYOUT_LONG_NO
+                | Configuration.SCREENLAYOUT_SIZE_NORMAL;
+        mTask.getConfiguration().screenLayout = fixedScreenLayout
+                | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR;
+        mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
+        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+        mActivity.info.maxAspectRatio = 1.5f;
+        ensureActivityConfiguration();
+
+        // The initial configuration should inherit from parent.
+        assertEquals(mTask.getConfiguration().screenLayout,
+                mActivity.getConfiguration().screenLayout);
+
+        mTask.getConfiguration().screenLayout = Configuration.SCREENLAYOUT_LAYOUTDIR_RTL
+                | Configuration.SCREENLAYOUT_LONG_YES | Configuration.SCREENLAYOUT_SIZE_LARGE;
+        mActivity.onConfigurationChanged(mTask.getConfiguration());
+
+        // The size and aspect ratio bits don't change, but the layout direction should be updated.
+        assertEquals(fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_RTL,
+                mActivity.getConfiguration().screenLayout);
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index e007c86..a98a604 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -29,7 +29,6 @@
 import android.platform.test.annotations.Presubmit;
 import android.view.SurfaceControl;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import com.android.server.wm.WindowTestUtils.TestAppWindowToken;
@@ -49,7 +48,6 @@
  */
 @SmallTest
 @Presubmit
-@FlakyTest(bugId = 124357362)
 public class AppWindowTokenAnimationTests extends WindowTestsBase {
 
     private TestAppWindowToken mToken;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 69f7ced..b26aa05 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -68,7 +68,6 @@
 import android.view.ViewRootImpl;
 import android.view.test.InsetsModeSession;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
@@ -97,7 +96,6 @@
 public class DisplayContentTests extends WindowTestsBase {
 
     @Test
-    @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
     public void testForAllWindows() {
         final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
                 mDisplayContent, "exiting app");
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index b1f942e..70ed62a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -175,10 +175,14 @@
     @Test
     public void testStackOutset() {
         final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
-        spyOn(stack);
-
         final int stackOutset = 10;
-        doReturn(stackOutset).when(stack).getStackOutset();
+        // Clear the handler and hold the lock for mock, to prevent multi-thread issue.
+        waitUntilHandlersIdle();
+        synchronized (mWm.mGlobalLock) {
+            spyOn(stack);
+
+            doReturn(stackOutset).when(stack).getStackOutset();
+        }
 
         final Rect stackBounds = new Rect(200, 200, 800, 1000);
         // Update surface position and size by the given bounds.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index b0e20b8..b03f63b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -110,8 +110,11 @@
         // TODO: Let the insets source with new mode keep the visibility control, and remove this
         // setup code. Now mTopFullscreenOpaqueWindowState will take back the control of insets
         // visibility.
-        spyOn(mDisplayContent);
-        doNothing().when(mDisplayContent).layoutAndAssignWindowLayersIfNeeded();
+        // Hold the lock to protect the mock from accesssing by other threads.
+        synchronized (mWm.mGlobalLock) {
+            spyOn(mDisplayContent);
+            doNothing().when(mDisplayContent).layoutAndAssignWindowLayersIfNeeded();
+        }
     }
 
     @Test
diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java
index e6182ed..740b970 100644
--- a/telephony/java/android/telephony/CellSignalStrength.java
+++ b/telephony/java/android/telephony/CellSignalStrength.java
@@ -119,7 +119,7 @@
     /** @hide */
     protected static final int getAsuFromRssiDbm(int dbm) {
         if (dbm == CellInfo.UNAVAILABLE) return 99;
-        return (dbm / 2) + 113;
+        return (dbm + 113) / 2;
     }
 
     // Range for RSCP in ASU (0-96, 255) as defined in TS 27.007 8.69
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/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index a922ab6..6de608e 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -84,6 +84,6 @@
     void notifyActiveDataSubIdChanged(int activeDataSubId);
     void notifyRadioPowerStateChanged(in int state);
     void notifyEmergencyNumberList();
-    void notifyCallQualityChanged(in CallQuality callQuality, int phoneId);
+    void notifyCallQualityChanged(in CallQuality callQuality, int phoneId, int callNetworkType);
     void notifyImsDisconnectCause(int subId, in ImsReasonInfo imsReasonInfo);
 }
diff --git a/test-base/Android.bp b/test-base/Android.bp
index 157609c..8aa0aaf 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -44,7 +44,7 @@
 // ==========================================
 // This is only intended for inclusion in the android.test.runner-minus-junit,
 // robolectric_android-all-stub and repackaged.android.test.* libraries.
-// Must not be used elewhere.
+// Must not be used elsewhere.
 java_library_static {
     name: "android.test.base_static",
     installable: false,
@@ -61,19 +61,6 @@
     sdk_version: "current",
 }
 
-// Build the legacy-test library
-// =============================
-// This contains the junit.framework and android.test classes that were in
-// Android API level 25 excluding those from android.test.runner.
-// Also contains the com.android.internal.util.Predicate[s] classes.
-java_library {
-    name: "legacy-test",
-    installable: true,
-
-    sdk_version: "current",
-    static_libs: ["android.test.base_static"],
-}
-
 // Build the repackaged.android.test.base library
 // ==============================================
 // This contains repackaged versions of the classes from
@@ -93,8 +80,8 @@
 // ===============================================
 // This contains the android.test classes from android.test.base plus
 // the com.android.internal.util.Predicate[s] classes. This is only
-// intended for inclusion in the android.test.legacy and
-// legacy-android-test static libraries and must not be used elsewhere.
+// intended for inclusion in android.test.legacy and must not be used
+// elsewhere.
 java_library_static {
     name: "android.test.base-minus-junit",
 
diff --git a/test-legacy/Android.bp b/test-legacy/Android.bp
deleted file mode 100644
index a69f422..0000000
--- a/test-legacy/Android.bp
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-// Build the legacy-android-test library
-// =====================================
-// This contains the android.test classes that were in Android API level 25,
-// including those from android.test.runner.
-// Also contains the com.android.internal.util.Predicate[s] classes.
-java_library_static {
-    name: "legacy-android-test",
-
-    static_libs: [
-        "android.test.base-minus-junit",
-        "android.test.runner-minus-junit",
-        "android.test.mock_static",
-    ],
-
-    no_framework_libs: true,
-    libs: [
-        "framework",
-        "junit",
-    ],
-}
diff --git a/test-legacy/Android.mk b/test-legacy/Android.mk
index da47de0..af26c5b 100644
--- a/test-legacy/Android.mk
+++ b/test-legacy/Android.mk
@@ -24,35 +24,16 @@
 # Built against the SDK so that it can be statically included in APKs
 # without breaking link type checks.
 #
-# This builds directly from the source rather than simply statically
-# including the android.test.base-minus-junit and
-# android.test.runner-minus-junit libraries because the latter library
-# cannot itself be built against the SDK. That is because it uses on
-# an internal method (setTestContext) on the AndroidTestCase class.
-# That class is provided by both the android.test.base-minus-junit and
-# the current SDK and as the latter is first on the classpath its
-# version is used. Unfortunately, it does not provide the internal
-# method and so compilation fails.
-#
-# Building from source avoids that because the compiler will use the
-# source version of AndroidTestCase instead of the one from the current
-# SDK.
-#
-# The use of the internal method does not prevent this from being
-# statically included because the class that provides the method is
-# also included in this library.
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := android.test.legacy
 
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, ../test-base/src/android) \
-    $(call all-java-files-under, ../test-base/src/com) \
-    $(call all-java-files-under, ../test-runner/src/android) \
-
 LOCAL_SDK_VERSION := current
 
 LOCAL_JAVA_LIBRARIES := junit android.test.mock.stubs
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android.test.base-minus-junit \
+    android.test.runner-minus-junit \
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 43b765d..e1d6e01 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -30,19 +30,3 @@
     srcs_lib_whitelist_pkgs: ["android"],
     compile_dex: true,
 }
-
-// Build the android.test.mock_static library
-// ==========================================
-// This is only intended for inclusion in the legacy-android-test.
-// Must not be used elewhere.
-java_library_static {
-    name: "android.test.mock_static",
-
-    java_version: "1.8",
-    srcs: ["src/**/*.java"],
-
-    no_framework_libs: true,
-    libs: [
-        "framework",
-    ],
-}
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index db5053e..3521202 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -45,7 +45,7 @@
 
 // Build the android.test.runner-minus-junit library
 // =================================================
-// This is only intended for inclusion in the legacy-android-test static
+// This is only intended for inclusion in the android.test.legacy static
 // library and must not be used elsewhere.
 java_library {
     name: "android.test.runner-minus-junit",
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/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(&current_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