Merge "Update View#getAttributeResolutionStack to take @AttrRes"
diff --git a/Android.bp b/Android.bp
index 0848d2b..183121b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -602,6 +602,7 @@
         "telephony/java/com/android/internal/telephony/IOnSubscriptionsChangedListener.aidl",
         "telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl",
         "telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl",
+        "telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl",
         "telephony/java/com/android/internal/telephony/ISms.aidl",
         "telephony/java/com/android/internal/telephony/ISub.aidl",
         "telephony/java/com/android/internal/telephony/IOns.aidl",
@@ -741,10 +742,8 @@
 
     static_libs: [
         "apex_aidl_interface-java",
-        "networkstack-aidl-interfaces-java",
         "framework-protos",
         "game-driver-protos",
-        "mediaplayer2-protos",
         "android.hidl.base-V1.0-java",
         "android.hardware.cas-V1.1-java",
         "android.hardware.cas-V1.0-java",
@@ -1188,58 +1187,12 @@
     "org/apache/http/params",
 ]
 
-// The since flag (-since N.xml API_LEVEL) is used to add API Level information
-// to the reference documentation. Must be in order of oldest to newest.
-//
-// Conscrypt (com.android.org.conscrypt) is an implementation detail and should
-// not be referenced in the documentation.
-framework_docs_args = "-android -manifest $(location core/res/AndroidManifest.xml) " +
-     "-hidePackage com.android.internal " +
-     "-hidePackage com.android.internal.util " +
-     "-hidePackage com.android.okhttp " +
-     "-hidePackage com.android.org.conscrypt " +
-     "-hidePackage com.android.server " +
-     "-since $(location 1/public/api/android.xml) 1 " +
-     "-since $(location 2/public/api/android.xml) 2 " +
-     "-since $(location 3/public/api/android.xml) 3 " +
-     "-since $(location 4/public/api/android.xml) 4 " +
-     "-since $(location 5/public/api/android.xml) 5 " +
-     "-since $(location 6/public/api/android.xml) 6 " +
-     "-since $(location 7/public/api/android.xml) 7 " +
-     "-since $(location 8/public/api/android.xml) 8 " +
-     "-since $(location 9/public/api/android.xml) 9 " +
-     "-since $(location 10/public/api/android.xml) 10 " +
-     "-since $(location 11/public/api/android.xml) 11 " +
-     "-since $(location 12/public/api/android.xml) 12 " +
-     "-since $(location 13/public/api/android.xml) 13 " +
-     "-since $(location 14/public/api/android.txt) 14 " +
-     "-since $(location 15/public/api/android.txt) 15 " +
-     "-since $(location 16/public/api/android.txt) 16 " +
-     "-since $(location 17/public/api/android.txt) 17 " +
-     "-since $(location 18/public/api/android.txt) 18 " +
-     "-since $(location 19/public/api/android.txt) 19 " +
-     "-since $(location 20/public/api/android.txt) 20 " +
-     "-since $(location 21/public/api/android.txt) 21 " +
-     "-since $(location 22/public/api/android.txt) 22 " +
-     "-since $(location 23/public/api/android.txt) 23 " +
-     "-since $(location 24/public/api/android.txt) 24 " +
-     "-since $(location 25/public/api/android.txt) 25 " +
-     "-since $(location 26/public/api/android.txt) 26 " +
-     "-since $(location 27/public/api/android.txt) 27 " +
-     "-since $(location 28/public/api/android.txt) 28 " +
-     "-since $(location api/current.txt) Q " +
-     "-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " +
-     "-overview $(location core/java/overview.html) " +
-     // Federate Support Library references against local API file.
-     "-federate SupportLib https://developer.android.com " +
-     "-federationapi SupportLib $(location current/support-api.txt) "
-
 framework_docs_only_args = " -android -manifest $(location core/res/AndroidManifest.xml) " +
      "-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " +
      "-overview $(location core/java/overview.html) " +
      // Federate Support Library references against local API file.
      "-federate SupportLib https://developer.android.com " +
-     "-federationapi SupportLib $(location current/support-api.txt) "
+     "-federationapi SupportLib $(location :current-support-api) "
 
 framework_docs_only_libs = [
     "voip-common",
diff --git a/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java b/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
index 9234849..0c30302 100644
--- a/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
@@ -40,7 +40,7 @@
     public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private final KernelCpuThreadReader mKernelCpuThreadReader =
-            KernelCpuThreadReader.create(8, uid -> 1000 <= uid && uid < 2000);
+            KernelCpuThreadReader.create(8, uid -> 1000 <= uid && uid < 2000, 0);
 
     @Test
     public void timeReadCurrentProcessCpuUsage() {
diff --git a/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java b/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java
index ec46a75..c506aec 100644
--- a/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java
+++ b/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java
@@ -64,7 +64,7 @@
         Context context = InstrumentationRegistry.getTargetContext();
         TextClassificationManager textClassificationManager =
                 context.getSystemService(TextClassificationManager.class);
-        mTextClassifier = textClassificationManager.getTextClassifier();
+        mTextClassifier = textClassificationManager.getLocalTextClassifier();
     }
 
     @Test
diff --git a/api/current.txt b/api/current.txt
index ff2e472..4238ca6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -80,7 +80,6 @@
     field public static final String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE";
     field public static final String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
-    field public static final String GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY = "android.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY";
     field public static final String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
     field @Deprecated public static final String GET_TASKS = "android.permission.GET_TASKS";
     field public static final String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
@@ -131,6 +130,7 @@
     field public static final String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES";
     field public static final String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
     field public static final String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
+    field public static final String REQUEST_SCREEN_LOCK_COMPLEXITY = "android.permission.REQUEST_SCREEN_LOCK_COMPLEXITY";
     field @Deprecated public static final String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
     field public static final String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
     field public static final String SEND_SMS = "android.permission.SEND_SMS";
@@ -6646,7 +6646,7 @@
     method @Nullable public CharSequence getOrganizationName(@NonNull android.content.ComponentName);
     method public java.util.List<android.telephony.data.ApnSetting> getOverrideApns(@NonNull android.content.ComponentName);
     method @NonNull public android.app.admin.DevicePolicyManager getParentProfileInstance(@NonNull android.content.ComponentName);
-    method @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY) public int getPasswordComplexity();
+    method @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY) public int getPasswordComplexity();
     method public long getPasswordExpiration(@Nullable android.content.ComponentName);
     method public long getPasswordExpirationTimeout(@Nullable android.content.ComponentName);
     method public int getPasswordHistoryLength(@Nullable android.content.ComponentName);
@@ -6684,7 +6684,7 @@
     method public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate, @NonNull String);
     method public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate[], @NonNull String, boolean);
     method public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate[], @NonNull String, int);
-    method public void installSystemUpdate(@NonNull android.content.ComponentName, @NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.app.admin.DevicePolicyManager.InstallUpdateCallback);
+    method public void installSystemUpdate(@NonNull android.content.ComponentName, @NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback);
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(@NonNull android.content.ComponentName);
     method public boolean isAffiliatedUser();
@@ -6840,7 +6840,7 @@
     field public static final String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
     field public static final String EXTRA_DELEGATION_SCOPES = "android.app.extra.DELEGATION_SCOPES";
     field public static final String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
-    field @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY) public static final String EXTRA_PASSWORD_COMPLEXITY = "android.app.extra.PASSWORD_COMPLEXITY";
+    field @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY) public static final String EXTRA_PASSWORD_COMPLEXITY = "android.app.extra.PASSWORD_COMPLEXITY";
     field public static final String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
     field public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
     field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
@@ -6951,8 +6951,8 @@
     field public static final int WIPE_SILENTLY = 8; // 0x8
   }
 
-  public abstract static class DevicePolicyManager.InstallUpdateCallback {
-    ctor public DevicePolicyManager.InstallUpdateCallback();
+  public abstract static class DevicePolicyManager.InstallSystemUpdateCallback {
+    ctor public DevicePolicyManager.InstallSystemUpdateCallback();
     method public void onInstallUpdateError(int, String);
     field public static final int UPDATE_ERROR_BATTERY_LOW = 5; // 0x5
     field public static final int UPDATE_ERROR_FILE_NOT_FOUND = 4; // 0x4
@@ -9517,7 +9517,6 @@
     method public static void cancelSync(android.content.SyncRequest);
     method @Nullable public final android.net.Uri canonicalize(@NonNull android.net.Uri);
     method public final int delete(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable String, @Nullable String[]);
-    method public android.os.Bundle getCache(android.net.Uri);
     method @Deprecated public static android.content.SyncInfo getCurrentSync();
     method public static java.util.List<android.content.SyncInfo> getCurrentSyncs();
     method public static int getIsSyncable(android.accounts.Account, String);
@@ -9548,7 +9547,6 @@
     method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle) throws java.io.FileNotFoundException;
     method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public void putCache(android.net.Uri, android.os.Bundle);
     method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String);
     method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable android.os.CancellationSignal);
     method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal);
@@ -11482,7 +11480,6 @@
     method public void setOriginatingUri(@Nullable android.net.Uri);
     method public void setReferrerUri(@Nullable android.net.Uri);
     method public void setSize(long);
-    method public void setStaged();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionParams> CREATOR;
     field public static final int MODE_FULL_INSTALL = 1; // 0x1
@@ -15409,28 +15406,38 @@
     method public float getGradientCenterY();
     method public float getGradientRadius();
     method public int getGradientType();
+    method public int getInnerRadius();
+    method public float getInnerRadiusRatio();
     method public int getOpacity();
     method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
     method public int getShape();
+    method public int getThickness();
+    method public float getThicknessRatio();
     method public boolean getUseLevel();
     method public void setAlpha(int);
     method public void setColor(@ColorInt int);
     method public void setColor(@Nullable android.content.res.ColorStateList);
     method public void setColorFilter(@Nullable android.graphics.ColorFilter);
     method public void setColors(@ColorInt int[]);
+    method public void setColors(@ColorInt int[], @Nullable float[]);
     method public void setCornerRadii(@Nullable float[]);
     method public void setCornerRadius(float);
     method public void setDither(boolean);
     method public void setGradientCenter(float, float);
     method public void setGradientRadius(float);
     method public void setGradientType(int);
+    method public void setInnerRadius(int);
+    method public void setInnerRadiusRatio(float);
     method public void setOrientation(android.graphics.drawable.GradientDrawable.Orientation);
+    method public void setPadding(int, int, int, int);
     method public void setShape(int);
     method public void setSize(int, int);
     method public void setStroke(int, @ColorInt int);
     method public void setStroke(int, android.content.res.ColorStateList);
     method public void setStroke(int, @ColorInt int, float, float);
     method public void setStroke(int, android.content.res.ColorStateList, float, float);
+    method public void setThickness(int);
+    method public void setThicknessRatio(float);
     method public void setUseLevel(boolean);
     field public static final int LINE = 2; // 0x2
     field public static final int LINEAR_GRADIENT = 0; // 0x0
@@ -22667,6 +22674,7 @@
     field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
     field public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2; // 0x2
     field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+    field public static final int STATE_2ND_CODE_LOCK = 65536; // 0x10000
     field public static final int STATE_BDS_D2_BIT_SYNC = 256; // 0x100
     field public static final int STATE_BDS_D2_SUBFRAME_SYNC = 512; // 0x200
     field public static final int STATE_BIT_SYNC = 2; // 0x2
@@ -44373,6 +44381,7 @@
     method public int getChannelNumber();
     method public String getMccString();
     method public String getMncString();
+    method public long getNci();
     method public int getPci();
     method public int getTac();
     method public void writeToParcel(android.os.Parcel, int);
@@ -45207,7 +45216,6 @@
     field public static final String EXTRA_STATE_RINGING;
     field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID";
     field public static final String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
-    field public static final int INVALID_CARD_ID = -1; // 0xffffffff
     field public static final String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
     field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
     field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
@@ -45233,6 +45241,9 @@
     field public static final int PHONE_TYPE_GSM = 1; // 0x1
     field public static final int PHONE_TYPE_NONE = 0; // 0x0
     field public static final int PHONE_TYPE_SIP = 3; // 0x3
+    field public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2; // 0x2
+    field public static final int SET_OPPORTUNISTIC_SUB_SUCCESS = 0; // 0x0
+    field public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1; // 0x1
     field public static final int SIM_STATE_ABSENT = 1; // 0x1
     field public static final int SIM_STATE_CARD_IO_ERROR = 8; // 0x8
     field public static final int SIM_STATE_CARD_RESTRICTED = 9; // 0x9
@@ -45243,7 +45254,9 @@
     field public static final int SIM_STATE_PUK_REQUIRED = 3; // 0x3
     field public static final int SIM_STATE_READY = 5; // 0x5
     field public static final int SIM_STATE_UNKNOWN = 0; // 0x0
+    field public static final int UNINITIALIZED_CARD_ID = -2; // 0xfffffffe
     field public static final int UNKNOWN_CARRIER_ID = -1; // 0xffffffff
+    field public static final int UNSUPPORTED_CARD_ID = -1; // 0xffffffff
     field public static final int USSD_ERROR_SERVICE_UNAVAIL = -2; // 0xfffffffe
     field public static final int USSD_RETURN_FAILURE = -1; // 0xffffffff
     field public static final String VVM_TYPE_CVVM = "vvm_type_cvvm";
@@ -50842,6 +50855,8 @@
     method public void getHitRect(android.graphics.Rect);
     method public int getHorizontalFadingEdgeLength();
     method protected int getHorizontalScrollbarHeight();
+    method @Nullable public android.graphics.drawable.Drawable getHorizontalScrollbarThumbDrawable();
+    method @Nullable public android.graphics.drawable.Drawable getHorizontalScrollbarTrackDrawable();
     method @android.view.ViewDebug.CapturedViewProperty @IdRes public int getId();
     method @android.view.ViewDebug.ExportedProperty(category="accessibility", mapping={@android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO, to="auto"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES, to="yes"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO, to="no"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, to="noHideDescendants")}) public int getImportantForAccessibility();
     method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_AUTO, to="auto"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_YES, to="yes"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_NO, to="no"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, to="yesExcludeDescendants"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, to="noExcludeDescendants")}) public int getImportantForAutofill();
@@ -50932,6 +50947,8 @@
     method public long getUniqueDrawingId();
     method public int getVerticalFadingEdgeLength();
     method public int getVerticalScrollbarPosition();
+    method @Nullable public android.graphics.drawable.Drawable getVerticalScrollbarThumbDrawable();
+    method @Nullable public android.graphics.drawable.Drawable getVerticalScrollbarTrackDrawable();
     method public int getVerticalScrollbarWidth();
     method public android.view.ViewTreeObserver getViewTreeObserver();
     method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.VISIBLE, to="VISIBLE"), @android.view.ViewDebug.IntToString(from=android.view.View.INVISIBLE, to="INVISIBLE"), @android.view.ViewDebug.IntToString(from=android.view.View.GONE, to="GONE")}) public int getVisibility();
@@ -51175,6 +51192,8 @@
     method public void setHasTransientState(boolean);
     method public void setHorizontalFadingEdgeEnabled(boolean);
     method public void setHorizontalScrollBarEnabled(boolean);
+    method public void setHorizontalScrollbarThumbDrawable(@Nullable android.graphics.drawable.Drawable);
+    method public void setHorizontalScrollbarTrackDrawable(@Nullable android.graphics.drawable.Drawable);
     method public void setHovered(boolean);
     method public void setId(@IdRes int);
     method public void setImportantForAccessibility(int);
@@ -51264,6 +51283,8 @@
     method public void setVerticalFadingEdgeEnabled(boolean);
     method public void setVerticalScrollBarEnabled(boolean);
     method public void setVerticalScrollbarPosition(int);
+    method public void setVerticalScrollbarThumbDrawable(@Nullable android.graphics.drawable.Drawable);
+    method public void setVerticalScrollbarTrackDrawable(@Nullable android.graphics.drawable.Drawable);
     method public void setVisibility(int);
     method @Deprecated public void setWillNotCacheDrawing(boolean);
     method public void setWillNotDraw(boolean);
@@ -51722,6 +51743,7 @@
     method public android.view.View getChildAt(int);
     method public int getChildCount();
     method protected int getChildDrawingOrder(int, int);
+    method public final int getChildDrawingOrder(int);
     method public static int getChildMeasureSpec(int, int, int);
     method protected boolean getChildStaticTransformation(android.view.View, android.view.animation.Transformation);
     method public boolean getChildVisibleRect(android.view.View, android.graphics.Rect, android.graphics.Point);
@@ -56691,6 +56713,8 @@
     method public int getMaxValue();
     method public int getMinValue();
     method public int getSelectionDividerHeight();
+    method @ColorInt public int getTextColor();
+    method @FloatRange(from=0.0, fromInclusive=false) public float getTextSize();
     method public int getValue();
     method public boolean getWrapSelectorWheel();
     method public void setDisplayedValues(String[]);
@@ -56701,6 +56725,8 @@
     method public void setOnScrollListener(android.widget.NumberPicker.OnScrollListener);
     method public void setOnValueChangedListener(android.widget.NumberPicker.OnValueChangeListener);
     method public void setSelectionDividerHeight(@IntRange(from=0) @Px int);
+    method public void setTextColor(@ColorInt int);
+    method public void setTextSize(@FloatRange(from=0.0, fromInclusive=false) float);
     method public void setValue(int);
     method public void setWrapSelectorWheel(boolean);
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index f673827..48a450a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -641,7 +641,7 @@
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String);
     method @Deprecated @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
-    method public void setProfileOwnerCanAccessDeviceIdsForUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
+    method @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIdsForUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
     field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
     field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
     field public static final String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION";
@@ -1283,7 +1283,9 @@
   }
 
   public abstract class ContentResolver implements android.content.ContentInterface {
+    method public android.os.Bundle getCache(android.net.Uri);
     method public android.graphics.drawable.Drawable getTypeDrawable(String);
+    method public void putCache(android.net.Uri, android.os.Bundle);
   }
 
   public abstract class Context {
@@ -1535,6 +1537,7 @@
     method @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) public void setGrantedRuntimePermissions(String[]);
     method public void setInstallAsInstantApp(boolean);
     method public void setInstallAsVirtualPreload();
+    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
   }
 
   public class PackageItemInfo {
@@ -5779,6 +5782,11 @@
     field public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
   }
 
+  public static interface DeviceConfig.Rollback {
+    field public static final String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
+    field public static final String NAMESPACE = "rollback";
+  }
+
   public static interface DeviceConfig.Runtime {
     field public static final String NAMESPACE = "runtime";
     field public static final String USE_PRECOMPILED_LAYOUT = "view.precompiled_layout_enabled";
@@ -7759,6 +7767,7 @@
     method public void requestEmbeddedSubscriptionInfoListRefresh(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultDataSubId(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultSmsSubId(int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPreferredDataSubscriptionId(int, boolean, @NonNull java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSubscriptionEnabled(int, boolean);
     field public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI;
     field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff
diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc
index 1b3c32b..469c964 100644
--- a/cmds/bootanimation/bootanim.rc
+++ b/cmds/bootanimation/bootanim.rc
@@ -2,7 +2,6 @@
     class core animation
     user graphics
     group graphics audio
-    updatable
     disabled
     oneshot
     writepid /dev/stune/top-app/tasks
diff --git a/cmds/statsd/benchmark/metric_util.cpp b/cmds/statsd/benchmark/metric_util.cpp
index 067b6ed..cca6d52 100644
--- a/cmds/statsd/benchmark/metric_util.cpp
+++ b/cmds/statsd/benchmark/metric_util.cpp
@@ -367,7 +367,8 @@
     sp<AlarmMonitor> periodicAlarmMonitor;
     sp<StatsLogProcessor> processor =
             new StatsLogProcessor(uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-                                  timeBaseSec * NS_PER_SEC, [](const ConfigKey&) { return true; });
+                                  timeBaseSec * NS_PER_SEC, [](const ConfigKey&) { return true; },
+                                  [](const int&, const vector<int64_t>&) { return true; });
     processor->OnConfigUpdated(timeBaseSec * NS_PER_SEC, key, config);
     return processor;
 }
@@ -393,4 +394,4 @@
 
 }  // namespace statsd
 }  // namespace os
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index dd18bd4..653ef2e 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -88,12 +88,15 @@
                                      const sp<AlarmMonitor>& anomalyAlarmMonitor,
                                      const sp<AlarmMonitor>& periodicAlarmMonitor,
                                      const int64_t timeBaseNs,
-                                     const std::function<bool(const ConfigKey&)>& sendBroadcast)
+                                     const std::function<bool(const ConfigKey&)>& sendBroadcast,
+                                     const std::function<bool(
+                                            const int&, const vector<int64_t>&)>& activateBroadcast)
     : mUidMap(uidMap),
       mPullerManager(pullerManager),
       mAnomalyAlarmMonitor(anomalyAlarmMonitor),
       mPeriodicAlarmMonitor(periodicAlarmMonitor),
       mSendBroadcast(sendBroadcast),
+      mSendActivationBroadcast(activateBroadcast),
       mTimeBaseNs(timeBaseNs),
       mLargestTimestampSeen(0),
       mLastTimestampSeen(0) {
@@ -223,11 +226,73 @@
         mapIsolatedUidToHostUidIfNecessaryLocked(event);
     }
 
+    std::unordered_set<int> uidsWithActiveConfigsChanged;
+    std::unordered_map<int, std::vector<int64_t>> activeConfigsPerUid;
     // pass the event to metrics managers.
     for (auto& pair : mMetricsManagers) {
+        int uid = pair.first.GetUid();
+        int64_t configId = pair.first.GetId();
+        bool isPrevActive = pair.second->isActive();
         pair.second->onLogEvent(*event);
+        bool isCurActive = pair.second->isActive();
+        // Map all active configs by uid.
+        if (isCurActive) {
+            auto activeConfigs = activeConfigsPerUid.find(uid);
+            if (activeConfigs != activeConfigsPerUid.end()) {
+                activeConfigs->second.push_back(configId);
+            } else {
+                vector<int64_t> newActiveConfigs;
+                newActiveConfigs.push_back(configId);
+                activeConfigsPerUid[uid] = newActiveConfigs;
+            }
+        }
+        // The activation state of this config changed.
+        if (isPrevActive != isCurActive) {
+            VLOG("Active status changed for uid  %d", uid);
+            uidsWithActiveConfigsChanged.insert(uid);
+            StatsdStats::getInstance().noteActiveStatusChanged(pair.first, isCurActive);
+        }
         flushIfNecessaryLocked(event->GetElapsedTimestampNs(), pair.first, *(pair.second));
     }
+
+    for (int uid : uidsWithActiveConfigsChanged) {
+        // Send broadcast so that receivers can pull data.
+        auto lastBroadcastTime = mLastActivationBroadcastTimes.find(uid);
+        if (lastBroadcastTime != mLastActivationBroadcastTimes.end()) {
+            if (currentTimestampNs - lastBroadcastTime->second <
+                    StatsdStats::kMinActivationBroadcastPeriodNs) {
+                VLOG("StatsD would've sent an activation broadcast but the rate limit stopped us.");
+                return;
+            }
+        }
+        auto activeConfigs = activeConfigsPerUid.find(uid);
+        if (activeConfigs != activeConfigsPerUid.end()) {
+            if (mSendActivationBroadcast(uid, activeConfigs->second)) {
+                VLOG("StatsD sent activation notice for uid %d", uid);
+                mLastActivationBroadcastTimes[uid] = currentTimestampNs;
+            }
+        } else {
+            std::vector<int64_t> emptyActiveConfigs;
+            if (mSendActivationBroadcast(uid, emptyActiveConfigs)) {
+                VLOG("StatsD sent EMPTY activation notice for uid %d", uid);
+                mLastActivationBroadcastTimes[uid] = currentTimestampNs;
+            }
+        }
+    }
+}
+
+void StatsLogProcessor::GetActiveConfigs(const int uid, vector<int64_t>& outActiveConfigs) {
+    std::lock_guard<std::mutex> lock(mMetricsMutex);
+    GetActiveConfigsLocked(uid, outActiveConfigs);
+}
+
+void StatsLogProcessor::GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs) {
+    outActiveConfigs.clear();
+    for (auto& pair : mMetricsManagers) {
+        if (pair.first.GetUid() == uid && pair.second->isActive()) {
+            outActiveConfigs.push_back(pair.first.GetId());
+        }
+    }
 }
 
 void StatsLogProcessor::OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
@@ -444,6 +509,18 @@
 
     mLastBroadcastTimes.erase(key);
 
+    int uid = key.GetUid();
+    bool lastConfigForUid = true;
+    for (auto it : mMetricsManagers) {
+        if (it.first.GetUid() == uid) {
+            lastConfigForUid = false;
+            break;
+        }
+    }
+    if (lastConfigForUid) {
+        mLastActivationBroadcastTimes.erase(uid);
+    }
+
     if (mMetricsManagers.empty()) {
         mPullerManager->ForceClearPullerCache();
     }
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index caf1a71..ea9c6e7 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -49,7 +49,9 @@
                       const sp<AlarmMonitor>& anomalyAlarmMonitor,
                       const sp<AlarmMonitor>& subscriberTriggerAlarmMonitor,
                       const int64_t timeBaseNs,
-                      const std::function<bool(const ConfigKey&)>& sendBroadcast);
+                      const std::function<bool(const ConfigKey&)>& sendBroadcast,
+                      const std::function<bool(const int&,
+                                               const vector<int64_t>&)>& sendActivationBroadcast);
     virtual ~StatsLogProcessor();
 
     void OnLogEvent(LogEvent* event);
@@ -60,6 +62,8 @@
 
     size_t GetMetricsSize(const ConfigKey& key) const;
 
+    void GetActiveConfigs(const int uid, vector<int64_t>& outActiveConfigs);
+
     void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
                       const bool include_current_partial_bucket, const bool erase_data,
                       const DumpReportReason dumpReportReason, vector<uint8_t>* outData);
@@ -125,6 +129,9 @@
 
     std::unordered_map<ConfigKey, long> mLastBroadcastTimes;
 
+    // Last time we sent a broadcast to this uid that the active configs had changed.
+    std::unordered_map<int, long> mLastActivationBroadcastTimes;
+
     // Tracks when we last checked the bytes consumed for each config key.
     std::unordered_map<ConfigKey, long> mLastByteSizeTimes;
 
@@ -144,6 +151,8 @@
     void OnConfigUpdatedLocked(
         const int64_t currentTimestampNs, const ConfigKey& key, const StatsdConfig& config);
 
+    void GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs);
+
     void WriteDataToDiskLocked(const DumpReportReason dumpReportReason);
     void WriteDataToDiskLocked(const ConfigKey& key, const int64_t timestampNs,
                                const DumpReportReason dumpReportReason);
@@ -174,6 +183,10 @@
     // to retrieve the stored data.
     std::function<bool(const ConfigKey& key)> mSendBroadcast;
 
+    // Function used to send a broadcast so that receiver can be notified of which configs
+    // are currently active.
+    std::function<bool(const int& uid, const vector<int64_t>& configIds)> mSendActivationBroadcast;
+
     const int64_t mTimeBaseNs;
 
     // Largest timestamp of the events that we have processed.
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index bd21a95..b478fed 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -176,6 +176,21 @@
                     sc->sendDataBroadcast(receiver, mProcessor->getLastReportTimeNs(key));
                     return true;
                 }
+            },
+            [this](const int& uid, const vector<int64_t>& activeConfigs) {
+                auto receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid);
+                sp<IStatsCompanionService> sc = getStatsCompanionService();
+                if (sc == nullptr) {
+                    VLOG("Could not access statsCompanion");
+                    return false;
+                } else if (receiver == nullptr) {
+                    VLOG("Could not find receiver for uid %d", uid);
+                    return false;
+                } else {
+                    sc->sendActiveConfigsChangedBroadcast(receiver, activeConfigs);
+                    VLOG("StatsService::active configs broadcast succeeded for uid %d" , uid);
+                    return true;
+                }
             });
 
     mConfigManager->AddListener(mProcessor);
@@ -357,6 +372,9 @@
         if (!args[0].compare(String8("print-logs"))) {
             return cmd_print_logs(out, args);
         }
+        if (!args[0].compare(String8("send-active-configs"))) {
+            return cmd_trigger_active_config_broadcast(out, args);
+        }
         if (!args[0].compare(String8("data-subscribe"))) {
             if (mShellSubscriber == nullptr) {
                 mShellSubscriber = new ShellSubscriber(mUidMap, mPullerManager);
@@ -449,6 +467,19 @@
     dprintf(out, "  NAME          The name of the configuration\n");
     dprintf(out, "\n");
     dprintf(out, "\n");
+    dprintf(out,
+            "usage: adb shell cmd stats send-active-configs [--uid=UID] [--configs] "
+            "[NAME1] [NAME2] [NAME3..]\n");
+    dprintf(out, "  Send a broadcast that informs the subscriber of the current active configs.\n");
+    dprintf(out, "  --uid=UID     The uid of the configurations. It is only possible to pass\n");
+    dprintf(out, "                the UID parameter on eng builds. If UID is omitted the\n");
+    dprintf(out, "                calling uid is used.\n");
+    dprintf(out, "  --configs     Send the list of configs in the name list instead of\n");
+    dprintf(out, "                the currently active configs\n");
+    dprintf(out, "  NAME LIST     List of configuration names to be included in the broadcast.\n");
+
+    dprintf(out, "\n");
+    dprintf(out, "\n");
     dprintf(out, "usage: adb shell cmd stats print-stats\n");
     dprintf(out, "  Prints some basic stats.\n");
     dprintf(out, "  --proto       Print proto binary instead of string format.\n");
@@ -499,6 +530,59 @@
     return NO_ERROR;
 }
 
+status_t StatsService::cmd_trigger_active_config_broadcast(int out, Vector<String8>& args) {
+    const int argCount = args.size();
+    int uid;
+    vector<int64_t> configIds;
+    if (argCount == 1) {
+        // Automatically pick the uid and send a broadcast that has no active configs.
+        uid = IPCThreadState::self()->getCallingUid();
+        mProcessor->GetActiveConfigs(uid, configIds);
+    } else {
+        int curArg = 1;
+        if(args[curArg].find("--uid=") == 0) {
+            string uidArgStr(args[curArg].c_str());
+            string uidStr = uidArgStr.substr(6);
+            if (!getUidFromString(uidStr.c_str(), uid)) {
+                dprintf(out, "Invalid UID. Note that the config can only be set for "
+                             "other UIDs on eng or userdebug builds.\n");
+                return UNKNOWN_ERROR;
+            }
+            curArg++;
+        } else {
+            uid = IPCThreadState::self()->getCallingUid();
+        }
+        if (curArg == argCount || args[curArg] != "--configs") {
+            VLOG("Reached end of args, or specify configs not set. Sending actual active configs,");
+            mProcessor->GetActiveConfigs(uid, configIds);
+        } else {
+            // Flag specified, use the given list of configs.
+            curArg++;
+            for (int i = curArg; i < argCount; i++) {
+                char* endp;
+                int64_t configID = strtoll(args[i].c_str(), &endp, 10);
+                if (endp == args[i].c_str() || *endp != '\0') {
+                    dprintf(out, "Error parsing config ID.\n");
+                    return UNKNOWN_ERROR;
+                }
+                VLOG("Adding config id %ld", static_cast<long>(configID));
+                configIds.push_back(configID);
+            }
+        }
+    }
+    auto receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid);
+    sp<IStatsCompanionService> sc = getStatsCompanionService();
+    if (sc == nullptr) {
+        VLOG("Could not access statsCompanion");
+    } else if (receiver == nullptr) {
+        VLOG("Could not find receiver for uid %d", uid);
+    } else {
+        sc->sendActiveConfigsChangedBroadcast(receiver, configIds);
+        VLOG("StatsService::trigger active configs changed broadcast succeeded for uid %d" , uid);
+    }
+    return NO_ERROR;
+}
+
 status_t StatsService::cmd_config(int in, int out, int err, Vector<String8>& args) {
     const int argCount = args.size();
     if (argCount >= 2) {
@@ -762,7 +846,10 @@
 }
 
 bool StatsService::getUidFromArgs(const Vector<String8>& args, size_t uidArgIndex, int32_t& uid) {
-    const char* s = args[uidArgIndex].c_str();
+    return getUidFromString(args[uidArgIndex].c_str(), uid);
+}
+
+bool StatsService::getUidFromString(const char* s, int32_t& uid) {
     if (*s == '\0') {
         return false;
     }
@@ -998,8 +1085,13 @@
     ENFORCE_DUMP_AND_USAGE_STATS(packageName);
 
     IPCThreadState* ipc = IPCThreadState::self();
-    mConfigManager->SetActiveConfigsChangedReceiver(ipc->getCallingUid(), intentSender);
-    //TODO: Return the list of configs that are already active
+    int uid = ipc->getCallingUid();
+    mConfigManager->SetActiveConfigsChangedReceiver(uid, intentSender);
+    if (output != nullptr) {
+        mProcessor->GetActiveConfigs(uid, *output);
+    } else {
+        ALOGW("StatsService::setActiveConfigsChanged output was nullptr");
+    }
     return Status::ok();
 }
 
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 941ed46..7f10d74 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -275,6 +275,12 @@
      */
     status_t cmd_trigger_broadcast(int outFd, Vector<String8>& args);
 
+
+    /**
+     * Trigger an active configs changed broadcast.
+     */
+    status_t cmd_trigger_active_config_broadcast(int outFd, Vector<String8>& args);
+
     /**
      * Handle the config sub-command.
      */
@@ -341,6 +347,15 @@
     bool getUidFromArgs(const Vector<String8>& args, size_t uidArgIndex, int32_t& uid);
 
     /**
+     * Writes the value of uidSting into uid.
+     * Returns whether the uid is reasonable (type uid_t) and whether
+     * 1. it is equal to the calling uid, or
+     * 2. the device is mEngBuild, or
+     * 3. the caller is AID_ROOT and the uid is AID_SHELL (i.e. ROOT can impersonate SHELL).
+     */
+     bool getUidFromString(const char* uidString, int32_t& uid);
+
+    /**
      * Adds a configuration after checking permissions and obtaining UID from binder call.
      */
     bool addConfigurationChecked(int uid, int64_t key, const vector<uint8_t>& config);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index da7e4da..29f67c7 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -31,6 +31,7 @@
 import "frameworks/base/core/proto/android/bluetooth/smp/enums.proto";
 import "frameworks/base/core/proto/android/debug/enums.proto";
 import "frameworks/base/core/proto/android/hardware/biometrics/enums.proto";
+import "frameworks/base/core/proto/android/hardware/sensor/assist/enums.proto";
 import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
 import "frameworks/base/core/proto/android/os/enums.proto";
 import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto";
@@ -241,6 +242,9 @@
         BluetoothSocketConnectionStateChanged bluetooth_socket_connection_state_changed = 171;
         DeviceIdentifierAccessDenied device_identifier_access_denied = 172;
         BubbleDeveloperErrorReported bubble_developer_error_reported = 173;
+        AssistGestureStageReported assist_gesture_stage_reported = 174;
+        AssistGestureFeedbackReported assist_gesture_feedback_reported = 175;
+        AssistGestureProgressReported assist_gesture_progress_reported = 176;
     }
 
     // Pulled events will start at field 10000.
@@ -5522,3 +5526,35 @@
 
     optional TrainExperimentIds train_experiment_id = 2;
 }
+
+/**
+ * Logs the gesture stage changed event.
+ *
+ * Logged from:
+ *   frameworks/base/packages/SystemUI/
+ */
+message AssistGestureStageReported {
+  optional android.hardware.sensor.assist.AssistGestureStageEnum gesture_stage = 1;
+}
+
+/**
+ * Logs the feedback type.
+ *
+ * Logged from:
+ *   frameworks/base/packages/SystemUI/
+ */
+message AssistGestureFeedbackReported {
+  // Whether or not the gesture was used.
+  optional android.hardware.sensor.assist.AssistGestureFeedbackEnum feedback_type = 1;
+}
+
+/**
+ * Logs the progress.
+ *
+ * Logged from:
+ *   frameworks/base/packages/SystemUI/
+ */
+message AssistGestureProgressReported {
+  // [0,100] progress for the assist gesture.
+  optional int32 progress = 1;
+}
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index aa22333..fc949b4 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -144,10 +144,20 @@
     {
         lock_guard <mutex> lock(mMutex);
 
-        auto uidIt = mConfigs.find(key.GetUid());
+        auto uid = key.GetUid();
+        auto uidIt = mConfigs.find(uid);
         if (uidIt != mConfigs.end() && uidIt->second.find(key) != uidIt->second.end()) {
             // Remove from map
             uidIt->second.erase(key);
+
+            // No more configs for this uid, lets remove the active configs callback.
+            if (uidIt->second.empty()) {
+                auto itActiveConfigsChangedReceiver = mActiveConfigsChangedReceivers.find(uid);
+                    if (itActiveConfigsChangedReceiver != mActiveConfigsChangedReceivers.end()) {
+                        mActiveConfigsChangedReceivers.erase(itActiveConfigsChangedReceiver);
+                    }
+            }
+
             for (const sp<ConfigListener>& listener : mListeners) {
                 broadcastList.push_back(listener);
             }
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 40329b7..b433c41 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -82,6 +82,8 @@
 const int FIELD_ID_CONFIG_STATS_ALERT_STATS = 16;
 const int FIELD_ID_CONFIG_STATS_METRIC_DIMENSION_IN_CONDITION_STATS = 17;
 const int FIELD_ID_CONFIG_STATS_ANNOTATION = 18;
+const int FIELD_ID_CONFIG_STATS_ACTIVATION = 22;
+const int FIELD_ID_CONFIG_STATS_DEACTIVATION = 23;
 const int FIELD_ID_CONFIG_STATS_ANNOTATION_INT64 = 1;
 const int FIELD_ID_CONFIG_STATS_ANNOTATION_INT32 = 2;
 
@@ -206,6 +208,25 @@
     it->second->broadcast_sent_time_sec.push_back(timeSec);
 }
 
+void StatsdStats::noteActiveStatusChanged(const ConfigKey& key, bool activated) {
+    noteActiveStatusChanged(key, activated, getWallClockSec());
+}
+
+void StatsdStats::noteActiveStatusChanged(const ConfigKey& key, bool activated, int32_t timeSec) {
+    lock_guard<std::mutex> lock(mLock);
+    auto it = mConfigStats.find(key);
+    if (it == mConfigStats.end()) {
+        ALOGE("Config key %s not found!", key.ToString().c_str());
+        return;
+    }
+    auto& vec = activated ? it->second->activation_time_sec
+                          : it->second->deactivation_time_sec;
+    if (vec.size() == kMaxTimestampCount) {
+        vec.pop_front();
+    }
+    vec.push_back(timeSec);
+}
+
 void StatsdStats::noteDataDropped(const ConfigKey& key, const size_t totalBytes) {
     noteDataDropped(key, totalBytes, getWallClockSec());
 }
@@ -501,6 +522,8 @@
     mLogLossStats.clear();
     for (auto& config : mConfigStats) {
         config.second->broadcast_sent_time_sec.clear();
+        config.second->activation_time_sec.clear();
+        config.second->deactivation_time_sec.clear();
         config.second->data_drop_time_sec.clear();
         config.second->data_drop_bytes.clear();
         config.second->dump_report_stats.clear();
@@ -558,6 +581,14 @@
             dprintf(out, "\tbroadcast time: %d\n", broadcastTime);
         }
 
+        for (const int& activationTime : configStats->activation_time_sec) {
+            dprintf(out, "\tactivation time: %d\n", activationTime);
+        }
+
+        for (const int& deactivationTime : configStats->deactivation_time_sec) {
+            dprintf(out, "\tdeactivation time: %d\n", deactivationTime);
+        }
+
         auto dropTimePtr = configStats->data_drop_time_sec.begin();
         auto dropBytesPtr = configStats->data_drop_bytes.begin();
         for (int i = 0; i < (int)configStats->data_drop_time_sec.size();
@@ -586,6 +617,14 @@
                     (long long)broadcastTime);
         }
 
+        for (const int& activationTime : configStats->activation_time_sec) {
+            dprintf(out, "\tactivation time: %d\n", activationTime);
+        }
+
+        for (const int& deactivationTime : configStats->deactivation_time_sec) {
+            dprintf(out, "\tdeactivation time: %d\n", deactivationTime);
+        }
+
         auto dropTimePtr = configStats->data_drop_time_sec.begin();
         auto dropBytesPtr = configStats->data_drop_bytes.begin();
         for (int i = 0; i < (int)configStats->data_drop_time_sec.size();
@@ -696,6 +735,16 @@
                      broadcast);
     }
 
+    for (const auto& activation : configStats.activation_time_sec) {
+        proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_ACTIVATION | FIELD_COUNT_REPEATED,
+                     activation);
+    }
+
+    for (const auto& deactivation : configStats.deactivation_time_sec) {
+        proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DEACTIVATION | FIELD_COUNT_REPEATED,
+                     deactivation);
+    }
+
     for (const auto& drop_time : configStats.data_drop_time_sec) {
         proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DATA_DROP_TIME | FIELD_COUNT_REPEATED,
                      drop_time);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 65e8a32..5275c8f 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -42,6 +42,13 @@
     bool is_valid;
 
     std::list<int32_t> broadcast_sent_time_sec;
+
+    // Times at which this config is activated.
+    std::list<int32_t> activation_time_sec;
+
+    // Times at which this config is deactivated.
+    std::list<int32_t> deactivation_time_sec;
+
     std::list<int32_t> data_drop_time_sec;
     // Number of bytes dropped at corresponding time.
     std::list<int64_t> data_drop_bytes;
@@ -132,6 +139,9 @@
     /* Min period between two checks of byte size per config key in nanoseconds. */
     static const int64_t kMinByteSizeCheckPeriodNs = 60 * NS_PER_SEC;
 
+    /* Minimum period between two activation broadcasts in nanoseconds. */
+    static const int64_t kMinActivationBroadcastPeriodNs = 10 * NS_PER_SEC;
+
     // Maximum age (30 days) that files on disk can exist in seconds.
     static const int kMaxAgeSecond = 60 * 60 * 24 * 30;
 
@@ -175,6 +185,13 @@
     void noteBroadcastSent(const ConfigKey& key);
 
     /**
+     * Report that a config has become activated or deactivated.
+     * This can be different from whether or not a broadcast is sent if the
+     * guardrail prevented the broadcast from being sent.
+     */
+    void noteActiveStatusChanged(const ConfigKey& key, bool activate);
+
+    /**
      * Report a config's metrics data has been dropped.
      */
     void noteDataDropped(const ConfigKey& key, const size_t totalBytes);
@@ -507,6 +524,8 @@
 
     void noteBroadcastSent(const ConfigKey& key, int32_t timeSec);
 
+    void noteActiveStatusChanged(const ConfigKey& key, bool activate, int32_t timeSec);
+
     void addToIceBoxLocked(std::shared_ptr<ConfigStats>& stats);
 
     /**
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 495138e..1107568 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -94,7 +94,7 @@
 void MetricProducer::addActivation(int activationTrackerIndex, int64_t ttl_seconds) {
     std::lock_guard<std::mutex> lock(mMutex);
     // When a metric producer does not depend on any activation, its mIsActive is true.
-    // Therefor, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not
+    // Therefore, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not
     // change.
     if  (mEventActivationMap.empty()) {
         mIsActive = false;
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 6ed6ab50..4851a8d 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -118,6 +118,16 @@
         ALOGE("This config has too many alerts! Reject!");
         mConfigValid = false;
     }
+
+    mIsAlwaysActive = (mMetricIndexesWithActivation.size() != mAllMetricProducers.size()) ||
+            (mAllMetricProducers.size() == 0);
+    bool isActive = mIsAlwaysActive;
+    for (int metric : mMetricIndexesWithActivation) {
+        isActive |= mAllMetricProducers[metric]->isActive();
+    }
+    mIsActive = isActive;
+    VLOG("mIsActive is initialized to %d", mIsActive)
+
     // no matter whether this config is valid, log it in the stats.
     StatsdStats::getInstance().noteConfigReceived(
             key, mAllMetricProducers.size(), mAllConditionTrackers.size(), mAllAtomMatchers.size(),
@@ -332,12 +342,14 @@
     int tagId = event.GetTagId();
     int64_t eventTimeNs = event.GetElapsedTimestampNs();
 
-    bool isActive = false;
+    bool isActive = mIsAlwaysActive;
     for (int metric : mMetricIndexesWithActivation) {
         mAllMetricProducers[metric]->flushIfExpire(eventTimeNs);
         isActive |= mAllMetricProducers[metric]->isActive();
     }
 
+    mIsActive = isActive;
+
     if (mTagIds.find(tagId) == mTagIds.end()) {
         // not interesting...
         return;
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index cb1cefb..eab1f76 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -128,6 +128,8 @@
     // Does not change the state.
     virtual size_t byteSize();
 
+    // Returns whether or not this config is active.
+    // The config is active if any metric in the config is active.
     inline bool isActive() const {
         return mIsActive;
     }
@@ -241,9 +243,12 @@
     // The metrics that don't need to be uploaded or even reported.
     std::set<int64_t> mNoReportMetricIds;
 
-    // Any metric active means the config is active.
+   // The config is active if any metric in the config is active.
     bool mIsActive;
 
+    // The config is always active if any metric in the config does not have an activation signal.
+    bool mIsAlwaysActive;
+
     FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions);
     FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
     FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 863261a..f7428a5 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -367,6 +367,8 @@
             optional int32 field_int32 = 2;
         }
         repeated Annotation annotation = 18;
+        repeated int32 activation_time_sec = 22;
+        repeated int32 deactivation_time_sec = 23;
     }
 
     repeated ConfigStats config_stats = 3;
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index 0ebf2ca..01043a2 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -493,7 +493,7 @@
                                   util::ProtoOutputStream *protoOutput) {
     uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOM_METRIC_STATS |
                                         FIELD_COUNT_REPEATED);
-    protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, (int32_t)pair.first);
+    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_ID, (int32_t)pair.first);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_HARD_DIMENSION_LIMIT_REACHED,
                        (long long)pair.second.hardDimensionLimitReached);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_LATE_LOG_EVENT_SKIPPED,
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index 60df165..5f3aae3 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -65,7 +65,8 @@
     sp<AlarmMonitor> periodicAlarmMonitor;
     // Construct the processor with a dummy sendBroadcast function that does nothing.
     StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, 0,
-                        [](const ConfigKey& key) { return true; });
+                        [](const ConfigKey& key) { return true; },
+                        [](const int&, const vector<int64_t>&) {return true;});
 
     MockMetricsManager mockMetricsManager;
 
@@ -88,7 +89,8 @@
                         [&broadcastCount](const ConfigKey& key) {
                             broadcastCount++;
                             return true;
-                        });
+                        },
+                        [](const int&, const vector<int64_t>&) {return true;});
 
     MockMetricsManager mockMetricsManager;
 
@@ -118,7 +120,8 @@
                         [&broadcastCount](const ConfigKey& key) {
                             broadcastCount++;
                             return true;
-                        });
+                        },
+                        [](const int&, const vector<int64_t>&) {return true;});
 
     MockMetricsManager mockMetricsManager;
 
@@ -162,7 +165,8 @@
                         [&broadcastCount](const ConfigKey& key) {
                             broadcastCount++;
                             return true;
-                        });
+                        },
+                        [](const int&, const vector<int64_t>&) {return true;});
     ConfigKey key(3, 4);
     StatsdConfig config = MakeConfig(true);
     p.OnConfigUpdated(0, key, config);
@@ -192,7 +196,8 @@
                         [&broadcastCount](const ConfigKey& key) {
                             broadcastCount++;
                             return true;
-                        });
+                        },
+                        [](const int&, const vector<int64_t>&) {return true;});
     ConfigKey key(3, 4);
     StatsdConfig config = MakeConfig(false);
     p.OnConfigUpdated(0, key, config);
@@ -218,7 +223,8 @@
                         [&broadcastCount](const ConfigKey& key) {
                             broadcastCount++;
                             return true;
-                        });
+                        },
+                        [](const int&, const vector<int64_t>&) {return true;});
     ConfigKey key(3, 4);
     StatsdConfig config;
     auto annotation = config.add_annotation();
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index f0d9cf1..c04a40c 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -45,7 +45,8 @@
     sp<AlarmMonitor> subscriberAlarmMonitor;
     // Construct the processor with a dummy sendBroadcast function that does nothing.
     StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
-                        [](const ConfigKey& key) { return true; });
+                        [](const ConfigKey& key) { return true; },
+                        [](const int&, const vector<int64_t>&) {return true;});
     LogEvent addEvent(android::util::ISOLATED_UID_CHANGED, 1);
     addEvent.write(100);  // parent UID
     addEvent.write(101);  // isolated UID
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index 44a88f0..1ff7982 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -133,6 +133,13 @@
     stats.noteMetricsReportSent(key, 0);
     stats.noteMetricsReportSent(key, 0);
 
+    // activation_time_sec -> 2
+    stats.noteActiveStatusChanged(key, true);
+    stats.noteActiveStatusChanged(key, true);
+
+    // deactivation_time_sec -> 1
+    stats.noteActiveStatusChanged(key, false);
+
     vector<uint8_t> output;
     stats.dumpStats(&output, true);  // Dump and reset stats
     StatsdStatsReport report;
@@ -146,6 +153,8 @@
     EXPECT_EQ(123, configReport.data_drop_bytes(0));
     EXPECT_EQ(3, configReport.dump_report_time_sec_size());
     EXPECT_EQ(3, configReport.dump_report_data_size_size());
+    EXPECT_EQ(2, configReport.activation_time_sec_size());
+    EXPECT_EQ(1, configReport.deactivation_time_sec_size());
     EXPECT_EQ(1, configReport.annotation_size());
     EXPECT_EQ(123, configReport.annotation(0).field_int64());
     EXPECT_EQ(456, configReport.annotation(0).field_int32());
@@ -344,6 +353,8 @@
         stats.noteDataDropped(key, timestamps[i]);
         stats.noteBroadcastSent(key, timestamps[i]);
         stats.noteMetricsReportSent(key, 0, timestamps[i]);
+        stats.noteActiveStatusChanged(key, true, timestamps[i]);
+        stats.noteActiveStatusChanged(key, false, timestamps[i]);
     }
 
     int32_t newTimestamp = 10000;
@@ -352,6 +363,8 @@
     stats.noteDataDropped(key, 123, 10000);
     stats.noteBroadcastSent(key, 10000);
     stats.noteMetricsReportSent(key, 0, 10000);
+    stats.noteActiveStatusChanged(key, true, 10000);
+    stats.noteActiveStatusChanged(key, false, 10000);
 
     EXPECT_TRUE(stats.mConfigStats.find(key) != stats.mConfigStats.end());
     const auto& configStats = stats.mConfigStats[key];
@@ -360,17 +373,23 @@
     EXPECT_EQ(maxCount, configStats->broadcast_sent_time_sec.size());
     EXPECT_EQ(maxCount, configStats->data_drop_time_sec.size());
     EXPECT_EQ(maxCount, configStats->dump_report_stats.size());
+    EXPECT_EQ(maxCount, configStats->activation_time_sec.size());
+    EXPECT_EQ(maxCount, configStats->deactivation_time_sec.size());
 
     // the oldest timestamp is the second timestamp in history
     EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
-    EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
-    EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
+    EXPECT_EQ(1, configStats->data_drop_bytes.front());
+    EXPECT_EQ(1, configStats->dump_report_stats.front().first);
+    EXPECT_EQ(1, configStats->activation_time_sec.front());
+    EXPECT_EQ(1, configStats->deactivation_time_sec.front());
 
     // the last timestamp is the newest timestamp.
     EXPECT_EQ(newTimestamp, configStats->broadcast_sent_time_sec.back());
     EXPECT_EQ(newTimestamp, configStats->data_drop_time_sec.back());
     EXPECT_EQ(123, configStats->data_drop_bytes.back());
     EXPECT_EQ(newTimestamp, configStats->dump_report_stats.back().first);
+    EXPECT_EQ(newTimestamp, configStats->activation_time_sec.back());
+    EXPECT_EQ(newTimestamp, configStats->deactivation_time_sec.back());
 }
 
 TEST(StatsdStatsTest, TestSystemServerCrash) {
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index b8b1a1d..2c4f3c7 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -461,7 +461,8 @@
                 [](const sp<IStatsCompanionService>&){});
     sp<StatsLogProcessor> processor =
             new StatsLogProcessor(uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-                                  timeBaseNs, [](const ConfigKey&) { return true; });
+                                  timeBaseNs, [](const ConfigKey&) { return true; },
+                                  [](const int&, const vector<int64_t>&) {return true;});
     processor->OnConfigUpdated(currentTimeNs, key, config);
     return processor;
 }
@@ -826,4 +827,4 @@
 
 }  // namespace statsd
 }  // namespace os
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 010e447..b72ce89 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -2439,7 +2439,6 @@
 Lcom/android/internal/telephony/cat/CatService;->mCmdIf:Lcom/android/internal/telephony/CommandsInterface;
 Lcom/android/internal/telephony/cat/CatService;->mContext:Landroid/content/Context;
 Lcom/android/internal/telephony/cat/CatService;->mCurrntCmd:Lcom/android/internal/telephony/cat/CatCmdMessage;
-Lcom/android/internal/telephony/cat/CatService;->mHandlerThread:Landroid/os/HandlerThread;
 Lcom/android/internal/telephony/cat/CatService;->mMenuCmd:Lcom/android/internal/telephony/cat/CatCmdMessage;
 Lcom/android/internal/telephony/cat/CatService;->mMsgDecoder:Lcom/android/internal/telephony/cat/RilMessageDecoder;
 Lcom/android/internal/telephony/cat/CatService;->mSlotId:I
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0eadd1d..5f778da 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -65,6 +65,7 @@
 import android.os.BadParcelableException;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.GraphicsEnvironment;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -7708,6 +7709,8 @@
             }
         }
 
+        GraphicsEnvironment.getInstance().showAngleInUseDialogBox(this);
+
         mActivityTransitionState.enterReady(this);
         dispatchActivityPostStarted();
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index db3b720..ca3c726 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2019,8 +2019,9 @@
             return getTaskService().isActivityStartAllowedOnDisplay(displayId, intent,
                     intent.resolveTypeIfNeeded(context.getContentResolver()), context.getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            e.rethrowFromSystemServer();
         }
+        return false;
     }
 
     /**
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index d46dbed..5c4c005 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -870,8 +870,9 @@
             }
         }
 
-        // /vendor/lib, /odm/lib and /product/lib are added to the native lib search
-        // paths of the classloader. Note that this is done AFTER the classloader is
+        // /aepx/com.android.runtime/lib, /vendor/lib, /odm/lib and /product/lib
+        // are added to the native lib search paths of the classloader.
+        // Note that this is done AFTER the classloader is
         // created by ApplicationLoaders.getDefault().getClassLoader(...). The
         // reason is because if we have added the paths when creating the classloader
         // above, the paths are also added to the search path of the linker namespace
@@ -888,8 +889,11 @@
         // System.loadLibrary(). In order to prevent the problem, we explicitly
         // add the paths only to the classloader, and not to the native loader
         // (linker namespace).
-        List<String> extraLibPaths = new ArrayList<>(3);
+        List<String> extraLibPaths = new ArrayList<>(4);
         String abiSuffix = VMRuntime.getRuntime().is64Bit() ? "64" : "";
+        if (!defaultSearchPaths.contains("/apex/com.android.runtime/lib")) {
+            extraLibPaths.add("/apex/com.android.runtime/lib" + abiSuffix);
+        }
         if (!defaultSearchPaths.contains("/vendor/lib")) {
             extraLibPaths.add("/vendor/lib" + abiSuffix);
         }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 8861151..806536b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1376,7 +1376,7 @@
      * complexity, and use this activity with extra {@link #EXTRA_PASSWORD_COMPLEXITY} to suggest
      * to users how complex the app wants the new screen lock to be. Note that both {@link
      * #getPasswordComplexity()} and the extra {@link #EXTRA_PASSWORD_COMPLEXITY} require the
-     * calling app to have the permission {@link permission#GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY}.
+     * calling app to have the permission {@link permission#REQUEST_SCREEN_LOCK_COMPLEXITY}.
      *
      * <p>If the intent is launched from within a managed profile with a profile
      * owner built against {@link android.os.Build.VERSION_CODES#M} or before,
@@ -1404,7 +1404,7 @@
      *
      * <p>If an invalid value is used, it will be treated as {@link #PASSWORD_COMPLEXITY_NONE}.
      */
-    @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY)
+    @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY)
     public static final String EXTRA_PASSWORD_COMPLEXITY =
             "android.app.extra.PASSWORD_COMPLEXITY";
 
@@ -2125,7 +2125,7 @@
      * Callback used in {@link #installSystemUpdate} to indicate that there was an error while
      * trying to install an update.
      */
-    public abstract static class InstallUpdateCallback {
+    public abstract static class InstallSystemUpdateCallback {
         /** Represents an unknown error while trying to install an update. */
         public static final int UPDATE_ERROR_UNKNOWN = 1;
 
@@ -2144,7 +2144,12 @@
         /** Represents the battery being too low to apply an update. */
         public static final int UPDATE_ERROR_BATTERY_LOW = 5;
 
-        /** Method invoked when there was an error while installing an update. */
+        /**
+         * Method invoked when there was an error while installing an update.
+         *
+         * <p>The given error message is not intended to be user-facing. It is intended to be
+         * reported back to the IT admin to be read.
+         */
         public void onInstallUpdateError(
                 @InstallUpdateCallbackErrorConstants int errorCode, String errorMessage) {
         }
@@ -2154,11 +2159,11 @@
      * @hide
      */
     @IntDef(prefix = { "UPDATE_ERROR_" }, value = {
-            InstallUpdateCallback.UPDATE_ERROR_UNKNOWN,
-            InstallUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION,
-            InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
-            InstallUpdateCallback.UPDATE_ERROR_FILE_NOT_FOUND,
-            InstallUpdateCallback.UPDATE_ERROR_BATTERY_LOW
+            InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN,
+            InstallSystemUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION,
+            InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
+            InstallSystemUpdateCallback.UPDATE_ERROR_FILE_NOT_FOUND,
+            InstallSystemUpdateCallback.UPDATE_ERROR_BATTERY_LOW
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface InstallUpdateCallbackErrorConstants {}
@@ -3346,10 +3351,10 @@
      *
      * @throws IllegalStateException if the user is not unlocked.
      * @throws SecurityException if the calling application does not have the permission
-     *                           {@link permission#GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY}
+     *                           {@link permission#REQUEST_SCREEN_LOCK_COMPLEXITY}
      */
     @PasswordComplexity
-    @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY)
+    @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY)
     public int getPasswordComplexity() {
         throwIfParentInstance("getPasswordComplexity");
         if (mService == null) {
@@ -10431,9 +10436,9 @@
      * doesn't necessarily mean that the update has been applied successfully. The caller should
      * additionally check the system version with {@link android.os.Build#FINGERPRINT} or {@link
      * android.os.Build.VERSION}. If an error occurs during processing the OTA before the reboot,
-     * the caller will be notified by {@link InstallUpdateCallback}. If device does not have
+     * the caller will be notified by {@link InstallSystemUpdateCallback}. If device does not have
      * sufficient battery level, the installation will fail with error {@link
-     * InstallUpdateCallback#UPDATE_ERROR_BATTERY_LOW}.
+     * InstallSystemUpdateCallback#UPDATE_ERROR_BATTERY_LOW}.
      *
      * @param admin The {@link DeviceAdminReceiver} that this request is associated with.
      * @param updateFilePath An Uri of the file that contains the update. The file should be
@@ -10445,7 +10450,7 @@
     public void installSystemUpdate(
             @NonNull ComponentName admin, @NonNull Uri updateFilePath,
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull InstallUpdateCallback callback) {
+            @NonNull InstallSystemUpdateCallback callback) {
         throwIfParentInstance("installUpdate");
         if (mService == null) {
             return;
@@ -10465,19 +10470,20 @@
         } catch (FileNotFoundException e) {
             Log.w(TAG, e);
             executeCallback(
-                    InstallUpdateCallback.UPDATE_ERROR_FILE_NOT_FOUND, Log.getStackTraceString(e),
+                    InstallSystemUpdateCallback.UPDATE_ERROR_FILE_NOT_FOUND,
+                    Log.getStackTraceString(e),
                     executor, callback);
         } catch (IOException e) {
             Log.w(TAG, e);
             executeCallback(
-                    InstallUpdateCallback.UPDATE_ERROR_UNKNOWN, Log.getStackTraceString(e),
+                    InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN, Log.getStackTraceString(e),
                     executor, callback);
         }
     }
 
     private void executeCallback(int errorCode, String errorMessage,
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull InstallUpdateCallback callback) {
+            @NonNull InstallSystemUpdateCallback callback) {
         executor.execute(() -> callback.onInstallUpdateError(errorCode, errorMessage));
     }
 
@@ -10537,6 +10543,8 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(value = android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS,
+            conditional = true)
     public void setProfileOwnerCanAccessDeviceIdsForUser(
             @NonNull ComponentName who, @NonNull UserHandle userHandle) {
         if (mService == null) {
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index f1bfe86..7672ccf 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2998,7 +2998,9 @@
      *
      * @param key the key to add
      * @param value the value to add
+     * {@hide}
      */
+    @SystemApi
     public void putCache(Uri key, Bundle value) {
         try {
             getContentService().putCache(mContext.getPackageName(), key, value,
@@ -3014,7 +3016,9 @@
      * @param key the key to get the value
      * @return the matched value. If the key doesn't exist, will return null.
      * @see #putCache(Uri, Bundle)
+     * {@hide}
      */
+    @SystemApi
     public Bundle getCache(Uri key) {
         try {
             final Bundle bundle = getContentService().getCache(mContext.getPackageName(), key,
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 0ac4f64..8095473 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -791,11 +791,6 @@
      * individual session IDs can be added with {@link #addChildSessionId(int)}
      * and commit of the multi-package session will result in all child sessions
      * being committed atomically.
-     * <p>
-     * If a package requires to be installed only at reboot, the session should
-     * be marked as a staged session by calling {@link SessionParams#setStaged()}
-     * with {@code true}. This can also apply to a multi-package session, in
-     * which case all the packages in the session will be applied at reboot.
      */
     public static class Session implements Closeable {
         /** {@hide} */
@@ -1539,7 +1534,11 @@
          * Staged sessions are scheduled to be installed at next reboot. Staged sessions can also be
          * multi-package. In that case, if any of the children sessions fail to install at reboot,
          * all the other children sessions are aborted as well.
+         *
+         * {@hide}
          */
+        @SystemApi
+        @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
         public void setStaged() {
             this.isStaged = true;
         }
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index fe68b8a..b155325 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -2273,7 +2273,8 @@
             CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName,
             Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras,
             long lastChangedTimestamp,
-            int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason) {
+            int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason,
+            Person[] persons) {
         mUserId = userId;
         mId = id;
         mPackageName = packageName;
@@ -2299,5 +2300,6 @@
         mIconResName = iconResName;
         mBitmapPath = bitmapPath;
         mDisabledReason = disabledReason;
+        mPersons = persons;
     }
 }
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index f3ebd7f..ac44fe9 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -16,6 +16,8 @@
 
 package android.hardware.display;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
@@ -229,7 +231,17 @@
         return getCompatibleDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
     }
 
-    public void registerDisplayListener(DisplayListener listener, Handler handler) {
+    /**
+     * Register a listener for display-related changes.
+     *
+     * @param listener The listener that will be called when display changes occur.
+     * @param handler Handler for the thread that will be receiving the callbacks. May be null.
+     * If null, listener will use the handler for the current thread, and if still null,
+     * the handler for the main thread.
+     * If that is still null, a runtime exception will be thrown.
+     */
+    public void registerDisplayListener(@NonNull DisplayListener listener,
+            @Nullable Handler handler) {
         if (listener == null) {
             throw new IllegalArgumentException("listener must not be null");
         }
@@ -237,7 +249,8 @@
         synchronized (mLock) {
             int index = findDisplayListenerLocked(listener);
             if (index < 0) {
-                mDisplayListeners.add(new DisplayListenerDelegate(listener, handler));
+                Looper looper = getLooperForHandler(handler);
+                mDisplayListeners.add(new DisplayListenerDelegate(listener, looper));
                 registerCallbackIfNeededLocked();
             }
         }
@@ -258,6 +271,17 @@
         }
     }
 
+    private static Looper getLooperForHandler(@Nullable Handler handler) {
+        Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
+        if (looper == null) {
+            looper = Looper.getMainLooper();
+        }
+        if (looper == null) {
+            throw new RuntimeException("Could not get Looper for the UI thread.");
+        }
+        return looper;
+    }
+
     private int findDisplayListenerLocked(DisplayListener listener) {
         final int numListeners = mDisplayListeners.size();
         for (int i = 0; i < numListeners; i++) {
@@ -636,8 +660,8 @@
     private static final class DisplayListenerDelegate extends Handler {
         public final DisplayListener mListener;
 
-        public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
-            super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
+        DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper) {
+            super(looper, null, true /*async*/);
             mListener = listener;
         }
 
diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java
index 7a4c9bc..ca49438 100644
--- a/core/java/android/net/NetworkStack.java
+++ b/core/java/android/net/NetworkStack.java
@@ -15,6 +15,7 @@
  */
 package android.net;
 
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
 
@@ -27,6 +28,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
 import android.net.dhcp.DhcpServingParamsParcel;
 import android.net.dhcp.IDhcpServerCallbacks;
 import android.net.ip.IIpClientCallbacks;
@@ -201,7 +203,33 @@
         final ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
         intent.setComponent(comp);
 
-        if (comp == null || !context.bindServiceAsUser(intent, new NetworkStackConnection(),
+        if (comp == null) {
+            Slog.wtf(TAG, "Could not resolve the network stack with " + intent);
+            // TODO: crash/reboot system server ?
+            return;
+        }
+
+        final PackageManager pm = context.getPackageManager();
+        int uid = -1;
+        try {
+            uid = pm.getPackageUid(comp.getPackageName(), UserHandle.USER_SYSTEM);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.wtf("Network stack package not found", e);
+            // Fall through
+        }
+
+        if (uid != Process.NETWORK_STACK_UID) {
+            throw new SecurityException("Invalid network stack UID: " + uid);
+        }
+
+        final int hasPermission =
+                pm.checkPermission(PERMISSION_MAINLINE_NETWORK_STACK, comp.getPackageName());
+        if (hasPermission != PERMISSION_GRANTED) {
+            throw new SecurityException(
+                    "Network stack does not have permission " + PERMISSION_MAINLINE_NETWORK_STACK);
+        }
+
+        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);
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 1f33693..a851e04 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -21,13 +21,14 @@
 import android.annotation.WorkerThread;
 
 import java.util.ArrayDeque;
-import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
@@ -190,13 +191,19 @@
 public abstract class AsyncTask<Params, Progress, Result> {
     private static final String LOG_TAG = "AsyncTask";
 
-    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
-    // We want at least 2 threads and at most 4 threads in the core pool,
-    // preferring to have 1 less than the CPU count to avoid saturating
-    // the CPU with background work
-    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
-    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
-    private static final int KEEP_ALIVE_SECONDS = 30;
+    // We keep only a single pool thread around all the time.
+    // We let the pool grow to a fairly large number of threads if necessary,
+    // but let them time out quickly. In the unlikely case that we run out of threads,
+    // we fall back to a simple unbounded-queue executor.
+    // This combination ensures that:
+    // 1. We normally keep few threads (1) around.
+    // 2. We queue only after launching a significantly larger, but still bounded, set of threads.
+    // 3. We keep the total number of threads bounded, but still allow an unbounded set
+    //    of tasks to be queued.
+    private static final int CORE_POOL_SIZE = 1;
+    private static final int MAXIMUM_POOL_SIZE = 20;
+    private static final int BACKUP_POOL_SIZE = 5;
+    private static final int KEEP_ALIVE_SECONDS = 3;
 
     private static final ThreadFactory sThreadFactory = new ThreadFactory() {
         private final AtomicInteger mCount = new AtomicInteger(1);
@@ -206,8 +213,29 @@
         }
     };
 
-    private static final BlockingQueue<Runnable> sPoolWorkQueue =
-            new LinkedBlockingQueue<Runnable>(128);
+    // Used only for rejected executions.
+    // Initialization protected by sRunOnSerialPolicy lock.
+    private static ThreadPoolExecutor sBackupExecutor;
+    private static LinkedBlockingQueue<Runnable> sBackupExecutorQueue;
+
+    private static final RejectedExecutionHandler sRunOnSerialPolicy =
+            new RejectedExecutionHandler() {
+        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+            android.util.Log.w(LOG_TAG, "Exceeded ThreadPoolExecutor pool size");
+            // As a last ditch fallback, run it on an executor with an unbounded queue.
+            // Create this executor lazily, hopefully almost never.
+            synchronized (this) {
+                if (sBackupExecutor == null) {
+                    sBackupExecutorQueue = new LinkedBlockingQueue<Runnable>();
+                    sBackupExecutor = new ThreadPoolExecutor(
+                            BACKUP_POOL_SIZE, BACKUP_POOL_SIZE, KEEP_ALIVE_SECONDS,
+                            TimeUnit.SECONDS, sBackupExecutorQueue, sThreadFactory);
+                    sBackupExecutor.allowCoreThreadTimeOut(true);
+                }
+            }
+            sBackupExecutor.execute(r);
+        }
+    };
 
     /**
      * An {@link Executor} that can be used to execute tasks in parallel.
@@ -217,8 +245,8 @@
     static {
         ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                 CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
-                sPoolWorkQueue, sThreadFactory);
-        threadPoolExecutor.allowCoreThreadTimeOut(true);
+                new SynchronousQueue<Runnable>(), sThreadFactory);
+        threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
         THREAD_POOL_EXECUTOR = threadPoolExecutor;
     }
 
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 269c781..8813e40 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -30,6 +31,7 @@
 import android.provider.Settings;
 import android.util.Base64;
 import android.util.Log;
+import android.widget.Toast;
 
 import com.android.framework.protobuf.InvalidProtocolBufferException;
 
@@ -222,9 +224,17 @@
     }
 
 
-    private static List<String> getGlobalSettingsString(Bundle bundle, String globalSetting) {
-        List<String> valueList = null;
-        final String settingsValue = bundle.getString(globalSetting);
+    private static List<String> getGlobalSettingsString(ContentResolver contentResolver,
+                                                        Bundle bundle,
+                                                        String globalSetting) {
+        final List<String> valueList;
+        final String settingsValue;
+
+        if (bundle != null) {
+            settingsValue = bundle.getString(globalSetting);
+        } else {
+            settingsValue = Settings.Global.getString(contentResolver, globalSetting);
+        }
 
         if (settingsValue != null) {
             valueList = new ArrayList<>(Arrays.asList(settingsValue.split(",")));
@@ -246,17 +256,27 @@
         return -1;
     }
 
-    private static String getDriverForPkg(Bundle bundle, String packageName) {
-        final String allUseAngle =
-                bundle.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
+    private static String getDriverForPkg(Context context, Bundle bundle, String packageName) {
+        final String allUseAngle;
+        if (bundle != null) {
+            allUseAngle =
+                    bundle.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
+        } else {
+            ContentResolver contentResolver = context.getContentResolver();
+            allUseAngle = Settings.Global.getString(contentResolver,
+                    Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
+        }
         if ((allUseAngle != null) && allUseAngle.equals("1")) {
             return sDriverMap.get(OpenGlDriverChoice.ANGLE);
         }
 
-        final List<String> globalSettingsDriverPkgs = getGlobalSettingsString(
-                bundle, Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS);
-        final List<String> globalSettingsDriverValues = getGlobalSettingsString(
-                bundle, Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES);
+        final ContentResolver contentResolver = context.getContentResolver();
+        final List<String> globalSettingsDriverPkgs =
+                getGlobalSettingsString(contentResolver, bundle,
+                        Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS);
+        final List<String> globalSettingsDriverValues =
+                getGlobalSettingsString(contentResolver, bundle,
+                        Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES);
 
         // Make sure we have a good package name
         if ((packageName == null) || (packageName.isEmpty())) {
@@ -308,7 +328,7 @@
      * True: Temporary rules file was loaded.
      * False: Temporary rules file was *not* loaded.
      */
-    private boolean setupAngleWithTempRulesFile(Context context,
+    private static boolean setupAngleWithTempRulesFile(Context context,
                                                 String packageName,
                                                 String paths,
                                                 String devOptIn) {
@@ -372,7 +392,7 @@
      * True: APK rules file was loaded.
      * False: APK rules file was *not* loaded.
      */
-    private boolean setupAngleRulesApk(String anglePkgName,
+    private static boolean setupAngleRulesApk(String anglePkgName,
             ApplicationInfo angleInfo,
             PackageManager pm,
             String packageName,
@@ -405,23 +425,32 @@
     /**
      * Pull ANGLE whitelist from GlobalSettings and compare against current package
      */
-    private boolean checkAngleWhitelist(Bundle bundle, String packageName) {
+    private static boolean checkAngleWhitelist(Context context, Bundle bundle, String packageName) {
+        final ContentResolver contentResolver = context.getContentResolver();
         final List<String> angleWhitelist =
-                getGlobalSettingsString(bundle, Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST);
+                getGlobalSettingsString(contentResolver, bundle,
+                    Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST);
 
         return angleWhitelist.contains(packageName);
     }
 
     /**
      * Pass ANGLE details down to trigger enable logic
+     *
+     * @param context
+     * @param bundle
+     * @param packageName
+     * @return true: ANGLE setup successfully
+     *         false: ANGLE not setup (not on whitelist, ANGLE not present, etc.)
      */
-    public void setupAngle(Context context, Bundle bundle, PackageManager pm, String packageName) {
+    public boolean setupAngle(Context context, Bundle bundle, PackageManager pm,
+            String packageName) {
         if (packageName.isEmpty()) {
             Log.v(TAG, "No package name available yet, skipping ANGLE setup");
-            return;
+            return false;
         }
 
-        final String devOptIn = getDriverForPkg(bundle, packageName);
+        final String devOptIn = getDriverForPkg(context, bundle, packageName);
         if (DEBUG) {
             Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
                     + "set to: '" + devOptIn + "'");
@@ -439,11 +468,11 @@
         // load a driver, GraphicsEnv::shouldUseAngle() has seen the package name before
         // and can confidently answer yes/no based on the previously set developer
         // option value.
-        final boolean whitelisted = checkAngleWhitelist(bundle, packageName);
+        final boolean whitelisted = checkAngleWhitelist(context, bundle, packageName);
         final boolean defaulted = devOptIn.equals(sDriverMap.get(OpenGlDriverChoice.DEFAULT));
         final boolean rulesCheck = (whitelisted || !defaulted);
         if (!rulesCheck) {
-            return;
+            return false;
         }
 
         if (whitelisted) {
@@ -456,7 +485,7 @@
         final String anglePkgName = getAnglePackageName(pm);
         if (anglePkgName.isEmpty()) {
             Log.e(TAG, "Failed to find ANGLE package.");
-            return;
+            return false;
         }
 
         final ApplicationInfo angleInfo;
@@ -464,7 +493,7 @@
             angleInfo = pm.getApplicationInfo(anglePkgName, PackageManager.MATCH_SYSTEM_ONLY);
         } catch (PackageManager.NameNotFoundException e) {
             Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed");
-            return;
+            return false;
         }
 
         final String abi = chooseAbi(angleInfo);
@@ -480,12 +509,62 @@
 
         if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) {
             // We setup ANGLE with a temp rules file, so we're done here.
-            return;
+            return true;
         }
 
         if (setupAngleRulesApk(anglePkgName, angleInfo, pm, packageName, paths, devOptIn)) {
             // We setup ANGLE with rules from the APK, so we're done here.
-            return;
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Determine if the "ANGLE In Use" dialog box should be shown.
+     */
+    private boolean shouldShowAngleInUseDialogBox(Context context) {
+        try {
+            ContentResolver contentResolver = context.getContentResolver();
+            final int showDialogBox = Settings.Global.getInt(contentResolver,
+                    Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX);
+
+            return (showDialogBox == 1);
+        } catch (Settings.SettingNotFoundException | SecurityException e) {
+            // Do nothing and move on
+        }
+
+        // No setting, so assume false
+        return false;
+    }
+
+    /**
+     * Determine if ANGLE should be used.
+     */
+    private boolean shouldUseAngle(Context context, String packageName) {
+        // Need to make sure we are evaluating ANGLE usage for the correct circumstances
+        if (!setupAngle(context, null, context.getPackageManager(), packageName)) {
+            Log.v(TAG, "Package '" + packageName + "' should use not ANGLE");
+            return false;
+        }
+
+        final boolean useAngle = getShouldUseAngle(packageName);
+        Log.v(TAG, "Package '" + packageName + "' should use ANGLE = '" + useAngle + "'");
+
+        return useAngle;
+    }
+
+    /**
+     * Show the ANGLE in Use Dialog Box
+     * @param context
+     */
+    public void showAngleInUseDialogBox(Context context) {
+        final String packageName = context.getPackageName();
+
+        if (shouldShowAngleInUseDialogBox(context) && shouldUseAngle(context, packageName)) {
+            final String toastMsg = packageName + " is using ANGLE";
+            final Toast toast = Toast.makeText(context, toastMsg, Toast.LENGTH_LONG);
+            toast.show();
         }
     }
 
@@ -541,19 +620,19 @@
 
         if (gameDriverAllApps != 1) {
             // GAME_DRIVER_OPT_OUT_APPS has higher priority than GAME_DRIVER_OPT_IN_APPS
-            if (getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_OPT_OUT_APPS)
-                            .contains(packageName)) {
+            if (getGlobalSettingsString(null, coreSettings,
+                    Settings.Global.GAME_DRIVER_OPT_OUT_APPS).contains(packageName)) {
                 if (DEBUG) {
                     Log.w(TAG, packageName + " opts out from Game Driver.");
                 }
                 return false;
             }
             final boolean isOptIn =
-                    getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_OPT_IN_APPS)
-                            .contains(packageName);
+                    getGlobalSettingsString(null, coreSettings,
+                            Settings.Global.GAME_DRIVER_OPT_IN_APPS).contains(packageName);
             if (!isOptIn
-                    && !getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_WHITELIST)
-                                .contains(packageName)) {
+                    && !getGlobalSettingsString(null, coreSettings,
+                    Settings.Global.GAME_DRIVER_WHITELIST).contains(packageName)) {
                 if (DEBUG) {
                     Log.w(TAG, packageName + " is not on the whitelist.");
                 }
@@ -660,4 +739,5 @@
             long driverVersionCode, String appPackageName);
     private static native void setAngleInfo(String path, String appPackage, String devOptIn,
             FileDescriptor rulesFd, long rulesOffset, long rulesLength);
+    private static native boolean getShouldUseAngle(String packageName);
 }
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index dde46cd..0751b96 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -69,6 +69,12 @@
     oneway void sendDataBroadcast(in IBinder intentSender, long lastReportTimeNs);
 
     /**
+     * Send a broadcast to the specified PendingIntent's as IBinder notifying it that the list
+     * of active configs has changed.
+     */
+    oneway void sendActiveConfigsChangedBroadcast(in IBinder intentSender, in long[] configIds);
+
+    /**
      * Requests StatsCompanionService to send a broadcast using the given intentSender
      * (which should cast to an IIntentSender), along with the other information specified.
      */
diff --git a/core/java/android/os/ParcelFileDescriptor.aidl b/core/java/android/os/ParcelFileDescriptor.aidl
deleted file mode 100644
index c07b980..0000000
--- a/core/java/android/os/ParcelFileDescriptor.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/* //device/java/android/android/os/ParcelFileDescriptor.aidl
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
-
-package android.os;
-
-parcelable ParcelFileDescriptor cpp_header "binder/ParcelFileDescriptor.h";
diff --git a/core/java/android/os/connectivity/CellularBatteryStats.java b/core/java/android/os/connectivity/CellularBatteryStats.java
index 2593c85..c99ecb32 100644
--- a/core/java/android/os/connectivity/CellularBatteryStats.java
+++ b/core/java/android/os/connectivity/CellularBatteryStats.java
@@ -44,6 +44,7 @@
   private long[] mTimeInRatMs;
   private long[] mTimeInRxSignalStrengthLevelMs;
   private long[] mTxTimeMs;
+  private long mMonitoredRailChargeConsumedMaMs;
 
   public static final Parcelable.Creator<CellularBatteryStats> CREATOR = new
       Parcelable.Creator<CellularBatteryStats>() {
@@ -74,6 +75,7 @@
     out.writeLongArray(mTimeInRatMs);
     out.writeLongArray(mTimeInRxSignalStrengthLevelMs);
     out.writeLongArray(mTxTimeMs);
+    out.writeLong(mMonitoredRailChargeConsumedMaMs);
   }
 
   public void readFromParcel(Parcel in) {
@@ -90,6 +92,7 @@
     in.readLongArray(mTimeInRatMs);
     in.readLongArray(mTimeInRxSignalStrengthLevelMs);
     in.readLongArray(mTxTimeMs);
+    mMonitoredRailChargeConsumedMaMs = in.readLong();
   }
 
   public long getLoggingDurationMs() {
@@ -144,6 +147,10 @@
     return mTxTimeMs;
   }
 
+  public long getMonitoredRailChargeConsumedMaMs() {
+    return mMonitoredRailChargeConsumedMaMs;
+  }
+
   public void setLoggingDurationMs(long t) {
     mLoggingDurationMs = t;
     return;
@@ -211,6 +218,11 @@
     return;
   }
 
+  public void setMonitoredRailChargeConsumedMaMs(long monitoredRailEnergyConsumedMaMs) {
+    mMonitoredRailChargeConsumedMaMs = monitoredRailEnergyConsumedMaMs;
+    return;
+  }
+
   public int describeContents() {
     return 0;
   }
@@ -237,6 +249,7 @@
     Arrays.fill(mTimeInRxSignalStrengthLevelMs, 0);
     mTxTimeMs = new long[ModemActivityInfo.TX_POWER_LEVELS];
     Arrays.fill(mTxTimeMs, 0);
+    mMonitoredRailChargeConsumedMaMs = 0;
     return;
   }
 }
\ No newline at end of file
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 735f4f2..43c9064 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1545,7 +1545,7 @@
     public static boolean hasIsolatedStorage() {
         // Prefer to use snapshot for current boot when available
         return SystemProperties.getBoolean(PROP_ISOLATED_STORAGE_SNAPSHOT,
-                SystemProperties.getBoolean(PROP_ISOLATED_STORAGE, false));
+                SystemProperties.getBoolean(PROP_ISOLATED_STORAGE, true));
     }
 
     /**
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 18e1f59..104b61d 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -308,6 +308,21 @@
     }
 
     /**
+     * Namespace for Rollback.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface Rollback {
+        String NAMESPACE = "rollback";
+
+        /**
+         * Timeout in milliseconds for enabling package rollback.
+         */
+        String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
+    }
+
+    /**
      * Namespace for storage-related features.
      *
      * @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 22329ba..d75c5e2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12318,6 +12318,14 @@
                 "angle_whitelist";
 
         /**
+         * Show the "ANGLE In Use" dialog box to the user when ANGLE is the OpenGL driver.
+         * The value is a boolean (1 or 0).
+         * @hide
+         */
+        public static final String GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX =
+                "show_angle_in_use_dialog_box";
+
+        /**
          * Game Driver global preference for all Apps.
          * 0 = Default
          * 1 = All Apps use Game Driver
@@ -12347,6 +12355,12 @@
         public static final String GAME_DRIVER_BLACKLIST = "game_driver_blacklist";
 
         /**
+         * List of blacklists, each blacklist is a blacklist for a specific version of Game Driver.
+         * @hide
+         */
+        public static final String GAME_DRIVER_BLACKLISTS = "game_driver_blacklists";
+
+        /**
          * Apps on the whitelist that are allowed to use Game Driver.
          * The string is a list of application package names, seperated by comma.
          * i.e. <apk1>,<apk2>,...,<apkN>
@@ -14354,6 +14368,7 @@
          * <pre>
          *     num_buckets          (int)
          *     collected_uids       (string)
+         *     minimum_total_cpu_usage_millis (int)
          * </pre>
          *
          * @hide
diff --git a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
index ca6676d..bbcf7a9 100644
--- a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
+++ b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
@@ -28,7 +28,8 @@
 /**
  * Not needed anymore...
  *
- * @deprecated
+ * @deprecated ContentCaptureService should use
+ * {@code #onContentCaptureEvent(ContentCaptureSessionId, ContentCaptureEvent)} instead.
  *
  * @hide
  */
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index ffb524d..a46d047 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -76,6 +76,11 @@
  * filter with the appropriate action, the {@link #CATEGORY_EUICC_UI} category, and a non-zero
  * priority.
  *
+ * <p>Old implementations of EuiccService may support passing in slot IDs equal to
+ * {@link android.telephony.SubscriptionManager#INVALID_SIM_SLOT_INDEX}, which allows the LPA to
+ * decide which eUICC to target when there are multiple eUICCs. This behavior is not supported in
+ * Android Q or later.
+ *
  * @hide
  */
 @SystemApi
@@ -546,7 +551,7 @@
                         int resultCode = EuiccService.this.onDownloadSubscription(
                                 slotId, subscription, switchAfterDownload, forceDeactivateSim);
                         result = new DownloadSubscriptionResult(resultCode,
-                            0 /* resolvableErrors */, TelephonyManager.INVALID_CARD_ID);
+                            0 /* resolvableErrors */, TelephonyManager.UNSUPPORTED_CARD_ID);
                     }
                     try {
                         callback.onComplete(result);
diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java
index 56558d0..0eeef70 100644
--- a/core/java/android/util/MathUtils.java
+++ b/core/java/android/util/MathUtils.java
@@ -166,6 +166,26 @@
     }
 
     /**
+     * Returns the interpolation scalar (s) that satisfies the equation: {@code value = }{@link
+     * #lerp}{@code (a, b, s)}
+     *
+     * <p>If {@code a == b}, then this function will return 0.
+     */
+    public static float lerpInv(float a, float b, float value) {
+        return a != b ? ((value - a) / (b - a)) : 0.0f;
+    }
+
+    /** Returns the single argument constrained between [0.0, 1.0]. */
+    public static float saturate(float value) {
+        return constrain(value, 0.0f, 1.0f);
+    }
+
+    /** Returns the saturated (constrained between [0, 1]) result of {@link #lerpInv}. */
+    public static float lerpInvSat(float a, float b, float value) {
+        return saturate(lerpInv(a, b, value));
+    }
+
+    /**
      * Returns an interpolated angle in degrees between a set of start and end
      * angles.
      * <p>
@@ -195,6 +215,32 @@
     }
 
     /**
+     * Calculates a value in [rangeMin, rangeMax] that maps value in [valueMin, valueMax] to
+     * returnVal in [rangeMin, rangeMax].
+     * <p>
+     * Always returns a constrained value in the range [rangeMin, rangeMax], even if value is
+     * outside [valueMin, valueMax].
+     * <p>
+     * Eg:
+     *    constrainedMap(0f, 100f, 0f, 1f, 0.5f) = 50f
+     *    constrainedMap(20f, 200f, 10f, 20f, 20f) = 200f
+     *    constrainedMap(20f, 200f, 10f, 20f, 50f) = 200f
+     *    constrainedMap(10f, 50f, 10f, 20f, 5f) = 10f
+     *
+     * @param rangeMin minimum of the range that should be returned.
+     * @param rangeMax maximum of the range that should be returned.
+     * @param valueMin minimum of range to map {@code value} to.
+     * @param valueMax maximum of range to map {@code value} to.
+     * @param value to map to the range [{@code valueMin}, {@code valueMax}]. Note, can be outside
+     *              this range, resulting in a clamped value.
+     * @return the mapped value, constrained to [{@code rangeMin}, {@code rangeMax}.
+     */
+    public static float constrainedMap(
+            float rangeMin, float rangeMax, float valueMin, float valueMax, float value) {
+        return lerp(rangeMin, rangeMax, lerpInvSat(valueMin, valueMax, value));
+    }
+
+    /**
      * Perform Hermite interpolation between two values.
      * Eg:
      *   smoothStep(0, 0.5f, 0.5f) = 1f
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 49bae28..cb5100a 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -76,7 +76,7 @@
     private final int mLayerStack;
     private final int mFlags;
     private final int mType;
-    private final String mAddress;
+    private final DisplayAddress mAddress;
     private final int mOwnerUid;
     private final String mOwnerPackageName;
     private final Resources mResources;
@@ -557,7 +557,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public String getAddress() {
+    public DisplayAddress getAddress() {
         return mAddress;
     }
 
diff --git a/core/java/android/view/DisplayAddress.java b/core/java/android/view/DisplayAddress.java
new file mode 100644
index 0000000..17ea4c4
--- /dev/null
+++ b/core/java/android/view/DisplayAddress.java
@@ -0,0 +1,174 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** Display identifier that is stable across reboots.
+ *
+ * @hide
+ */
+public abstract class DisplayAddress implements Parcelable {
+    /**
+     * Creates an address for a physical display given its stable ID.
+     *
+     * A physical display ID is stable if the display can be identified using EDID information.
+     *
+     * @param physicalDisplayId A physical display ID.
+     * @return The {@link Physical} address, or {@code null} if the ID is not stable.
+     * @see SurfaceControl#getPhysicalDisplayIds
+     */
+    @Nullable
+    public static Physical fromPhysicalDisplayId(long physicalDisplayId) {
+        final Physical address = new Physical(physicalDisplayId);
+        return address.getModel() == 0 ? null : address;
+    }
+
+    /**
+     * Creates an address for a network display given its MAC address.
+     *
+     * @param macAddress A MAC address in colon notation.
+     * @return The {@link Network} address.
+     */
+    @NonNull
+    public static Network fromMacAddress(String macAddress) {
+        return new Network(macAddress);
+    }
+
+    /**
+     * Address for a physically connected display.
+     *
+     * A {@link Physical} address is represented by a 64-bit identifier combining the port and model
+     * of a display. The port, located in the least significant byte, uniquely identifies a physical
+     * connector on the device for display output like eDP or HDMI. The model, located in the upper
+     * bits, uniquely identifies a display model across manufacturers by encoding EDID information.
+     */
+    public static final class Physical extends DisplayAddress {
+        private static final int PHYSICAL_DISPLAY_ID_MODEL_SHIFT = 8;
+        private static final int PORT_MASK = 0xFF;
+
+        private final long mPhysicalDisplayId;
+
+        /**
+         * Physical port to which the display is connected.
+         */
+        public byte getPort() {
+            return (byte) mPhysicalDisplayId;
+        }
+
+        /**
+         * Model identifier unique across manufacturers.
+         */
+        public long getModel() {
+            return mPhysicalDisplayId >>> PHYSICAL_DISPLAY_ID_MODEL_SHIFT;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            return other instanceof Physical
+                    && mPhysicalDisplayId == ((Physical) other).mPhysicalDisplayId;
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder("{")
+                    .append("port=").append(getPort() & PORT_MASK)
+                    .append(", model=0x").append(Long.toHexString(getModel()))
+                    .append("}")
+                    .toString();
+        }
+
+        @Override
+        public int hashCode() {
+            return Long.hashCode(mPhysicalDisplayId);
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeLong(mPhysicalDisplayId);
+        }
+
+        private Physical(long physicalDisplayId) {
+            mPhysicalDisplayId = physicalDisplayId;
+        }
+
+        public static final Parcelable.Creator<Physical> CREATOR =
+                new Parcelable.Creator<Physical>() {
+                    @Override
+                    public Physical createFromParcel(Parcel in) {
+                        return new Physical(in.readLong());
+                    }
+
+                    @Override
+                    public Physical[] newArray(int size) {
+                        return new Physical[size];
+                    }
+                };
+    }
+
+    /**
+     * Address for a network-connected display.
+     */
+    public static final class Network extends DisplayAddress {
+        private final String mMacAddress;
+
+        @Override
+        public boolean equals(Object other) {
+            return other instanceof Network && mMacAddress.equals(((Network) other).mMacAddress);
+        }
+
+        @Override
+        public String toString() {
+            return mMacAddress;
+        }
+
+        @Override
+        public int hashCode() {
+            return mMacAddress.hashCode();
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(mMacAddress);
+        }
+
+        private Network(String macAddress) {
+            mMacAddress = macAddress;
+        }
+
+        public static final Parcelable.Creator<Network> CREATOR =
+                new Parcelable.Creator<Network>() {
+                    @Override
+                    public Network createFromParcel(Parcel in) {
+                        return new Network(in.readString());
+                    }
+
+                    @Override
+                    public Network[] newArray(int size) {
+                        return new Network[size];
+                    }
+                };
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index ad8fee9..3aa779b 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -61,7 +61,7 @@
      * Display address, or null if none.
      * Interpretation varies by display type.
      */
-    public String address;
+    public DisplayAddress address;
 
     /**
      * The human-readable name of the display.
@@ -385,7 +385,7 @@
         layerStack = source.readInt();
         flags = source.readInt();
         type = source.readInt();
-        address = source.readString();
+        address = source.readParcelable(null);
         name = source.readString();
         appWidth = source.readInt();
         appHeight = source.readInt();
@@ -432,7 +432,7 @@
         dest.writeInt(layerStack);
         dest.writeInt(this.flags);
         dest.writeInt(type);
-        dest.writeString(address);
+        dest.writeParcelable(address, flags);
         dest.writeString(name);
         dest.writeInt(appWidth);
         dest.writeInt(appHeight);
diff --git a/core/java/android/view/GhostView.java b/core/java/android/view/GhostView.java
index 74c801b..3286bd6 100644
--- a/core/java/android/view/GhostView.java
+++ b/core/java/android/view/GhostView.java
@@ -20,6 +20,7 @@
 import android.graphics.Matrix;
 import android.graphics.RecordingCanvas;
 import android.graphics.RenderNode;
+import android.os.Build;
 import android.widget.FrameLayout;
 
 import java.util.ArrayList;
@@ -135,12 +136,12 @@
         return ghostView;
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static GhostView addGhost(View view, ViewGroup viewGroup) {
         return addGhost(view, viewGroup, null);
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static void removeGhost(View view) {
         GhostView ghostView = view.mGhostView;
         if (ghostView != null) {
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index b28ac47..f13cb5a 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -129,7 +129,7 @@
     static final Class<?>[] mConstructorSignature = new Class[] {
             Context.class, AttributeSet.class};
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769490)
     private static final HashMap<String, Constructor<? extends View>> sConstructorMap =
             new HashMap<String, Constructor<? extends View>>();
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ea224cd..ba1b517 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6467,6 +6467,16 @@
         arr.recycle();
     }
 
+    private void initializeScrollBarDrawable() {
+        initScrollCache();
+
+        if (mScrollCache.scrollBar == null) {
+            mScrollCache.scrollBar = new ScrollBarDrawable();
+            mScrollCache.scrollBar.setState(getDrawableState());
+            mScrollCache.scrollBar.setCallback(this);
+        }
+    }
+
     /**
      * <p>
      * Initializes the scrollbars from a given set of styled attributes. This
@@ -6552,6 +6562,106 @@
         resolvePadding();
     }
 
+    /**
+     * Defines the vertical scrollbar thumb drawable
+     * @attr ref android.R.styleable#View_scrollbarThumbVertical
+     *
+     * @see #awakenScrollBars(int)
+     * @see #isVerticalScrollBarEnabled()
+     * @see #setVerticalScrollBarEnabled(boolean)
+     */
+    public void setVerticalScrollbarThumbDrawable(@Nullable Drawable drawable) {
+        initializeScrollBarDrawable();
+        mScrollCache.scrollBar.setVerticalThumbDrawable(drawable);
+    }
+
+    /**
+     * Defines the vertical scrollbar track drawable
+     * @attr ref android.R.styleable#View_scrollbarTrackVertical
+     *
+     * @see #awakenScrollBars(int)
+     * @see #isVerticalScrollBarEnabled()
+     * @see #setVerticalScrollBarEnabled(boolean)
+     */
+    public void setVerticalScrollbarTrackDrawable(@Nullable Drawable drawable) {
+        initializeScrollBarDrawable();
+        mScrollCache.scrollBar.setVerticalTrackDrawable(drawable);
+    }
+
+    /**
+     * Defines the horizontal thumb drawable
+     * @attr ref android.R.styleable#View_scrollbarThumbHorizontal
+     *
+     * @see #awakenScrollBars(int)
+     * @see #isHorizontalScrollBarEnabled()
+     * @see #setHorizontalScrollBarEnabled(boolean)
+     */
+    public void setHorizontalScrollbarThumbDrawable(@Nullable Drawable drawable) {
+        initializeScrollBarDrawable();
+        mScrollCache.scrollBar.setHorizontalThumbDrawable(drawable);
+    }
+
+    /**
+     * Defines the horizontal track drawable
+     * @attr ref android.R.styleable#View_scrollbarTrackHorizontal
+     *
+     * @see #awakenScrollBars(int)
+     * @see #isHorizontalScrollBarEnabled()
+     * @see #setHorizontalScrollBarEnabled(boolean)
+     */
+    public void setHorizontalScrollbarTrackDrawable(@Nullable Drawable drawable) {
+        initializeScrollBarDrawable();
+        mScrollCache.scrollBar.setHorizontalTrackDrawable(drawable);
+    }
+
+    /**
+     * Returns the currently configured Drawable for the thumb of the vertical scroll bar if it
+     * exists, null otherwise.
+     *
+     * @see #awakenScrollBars(int)
+     * @see #isVerticalScrollBarEnabled()
+     * @see #setVerticalScrollBarEnabled(boolean)
+     */
+    public @Nullable Drawable getVerticalScrollbarThumbDrawable() {
+        return mScrollCache != null ? mScrollCache.scrollBar.getVerticalThumbDrawable() : null;
+    }
+
+    /**
+     * Returns the currently configured Drawable for the track of the vertical scroll bar if it
+     * exists, null otherwise.
+     *
+     * @see #awakenScrollBars(int)
+     * @see #isVerticalScrollBarEnabled()
+     * @see #setVerticalScrollBarEnabled(boolean)
+     */
+    public @Nullable Drawable getVerticalScrollbarTrackDrawable() {
+        return mScrollCache != null ? mScrollCache.scrollBar.getVerticalTrackDrawable() : null;
+    }
+
+    /**
+     * Returns the currently configured Drawable for the thumb of the horizontal scroll bar if it
+     * exists, null otherwise.
+     *
+     * @see #awakenScrollBars(int)
+     * @see #isHorizontalScrollBarEnabled()
+     * @see #setHorizontalScrollBarEnabled(boolean)
+     */
+    public @Nullable Drawable getHorizontalScrollbarThumbDrawable() {
+        return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalThumbDrawable() : null;
+    }
+
+    /**
+     * Returns the currently configured Drawable for the track of the horizontal scroll bar if it
+     * exists, null otherwise.
+     *
+     * @see #awakenScrollBars(int)
+     * @see #isHorizontalScrollBarEnabled()
+     * @see #setHorizontalScrollBarEnabled(boolean)
+     */
+    public @Nullable Drawable getHorizontalScrollbarTrackDrawable() {
+        return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalTrackDrawable() : null;
+    }
+
     private void initializeScrollIndicatorsInternal() {
         // Some day maybe we'll break this into top/left/start/etc. and let the
         // client control it. Until then, you can have any scroll indicator you
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index aaf1d11..f2474a5 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4301,6 +4301,20 @@
         return i;
     }
 
+    /**
+     * The public version of getChildDrawingOrder().
+     *
+     * Returns the index of the child to draw for this iteration.
+     *
+     * @param i The current iteration.
+     * @return The index of the child to draw this iteration.
+     *
+     * @see #getChildDrawingOrder(int, int)}
+     */
+    public final int getChildDrawingOrder(int i) {
+        return getChildDrawingOrder(getChildCount(), i);
+    }
+
     private boolean hasChildWithZ() {
         for (int i = 0; i < mChildrenCount; i++) {
             if (mChildren[i].getZ() != 0) return true;
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 06207a9..384cdbb 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -174,7 +174,7 @@
 
     final Handler.Callback mCallback;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     boolean mIsEnabled;
 
     int mRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK;
diff --git a/core/java/android/view/textclassifier/TEST_MAPPING b/core/java/android/view/textclassifier/TEST_MAPPING
index 0d3c346..01a6ede 100644
--- a/core/java/android/view/textclassifier/TEST_MAPPING
+++ b/core/java/android/view/textclassifier/TEST_MAPPING
@@ -10,14 +10,6 @@
           "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
-    },
-    {
-      "name": "CtsViewTestCases",
-      "options": [
-        {
-          "include-filter": "android.view.textclassifier.cts"
-        }
-      ]
     }
   ]
 }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 4b7c393..f01babe 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -325,13 +325,13 @@
     /**
      * The current position of the selector in the list.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     int mSelectorPosition = INVALID_POSITION;
 
     /**
      * Defines the selector's location and dimension at drawing time
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     Rect mSelectorRect = new Rect();
 
     /**
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 9c21ba6..ded3be4e 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -6020,9 +6020,6 @@
                     }
 
                     updateSelection(event);
-                    if (mTextView.hasSelection() && mEndHandle != null) {
-                        mEndHandle.updateMagnifier(event);
-                    }
                     break;
 
                 case MotionEvent.ACTION_UP:
@@ -6030,9 +6027,6 @@
                         break;
                     }
                     updateSelection(event);
-                    if (mEndHandle != null) {
-                        mEndHandle.dismissMagnifier();
-                    }
 
                     // No longer dragging to select text, let the parent intercept events.
                     mTextView.getParent().requestDisallowInterceptTouchEvent(false);
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 89bb273..dad2669 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -17,6 +17,8 @@
 package android.widget;
 
 import android.annotation.CallSuper;
+import android.annotation.ColorInt;
+import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.Px;
@@ -340,7 +342,7 @@
     /**
      * The {@link Paint} for drawing the selector.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private final Paint mSelectorWheelPaint;
 
     /**
@@ -1718,6 +1720,44 @@
     }
 
     /**
+     * Sets the text color for all the states (normal, selected, focused) to be the given color.
+     *
+     * @param color A color value in the form 0xAARRGGBB.
+     */
+    public void setTextColor(@ColorInt int color) {
+        mSelectorWheelPaint.setColor(color);
+        mInputText.setTextColor(color);
+        invalidate();
+    }
+
+    /**
+     * @return the text color.
+     */
+    @ColorInt
+    public int getTextColor() {
+        return mSelectorWheelPaint.getColor();
+    }
+
+    /**
+     * Sets the text size to the given value. This value must be > 0
+     *
+     * @param size The size in pixel units.
+     */
+    public void setTextSize(@FloatRange(from = 0.0, fromInclusive = false) float size) {
+        mSelectorWheelPaint.setTextSize(size);
+        mInputText.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
+        invalidate();
+    }
+
+    /**
+     * @return the size (in pixels) of the text size in this NumberPicker.
+     */
+    @FloatRange(from = 0.0, fromInclusive = false)
+    public float getTextSize() {
+        return mSelectorWheelPaint.getTextSize();
+    }
+
+    /**
      * Makes a measure spec that tries greedily to use the max value.
      *
      * @param measureSpec The measure spec.
diff --git a/core/java/android/widget/ScrollBarDrawable.java b/core/java/android/widget/ScrollBarDrawable.java
index e91f87e..1bed32ec 100644
--- a/core/java/android/widget/ScrollBarDrawable.java
+++ b/core/java/android/widget/ScrollBarDrawable.java
@@ -17,12 +17,15 @@
 package android.widget;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.view.View;
 
 import com.android.internal.widget.ScrollBarUtils;
 
@@ -36,7 +39,7 @@
 public class ScrollBarDrawable extends Drawable implements Drawable.Callback {
     private Drawable mVerticalTrack;
     private Drawable mHorizontalTrack;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768422)
     private Drawable mVerticalThumb;
     private Drawable mHorizontalThumb;
 
@@ -226,7 +229,10 @@
         }
     }
 
-    @UnsupportedAppUsage
+    /**
+     * @see android.view.View#setVerticalThumbDrawable(Drawable)
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public void setVerticalThumbDrawable(Drawable thumb) {
         if (mVerticalThumb != null) {
             mVerticalThumb.setCallback(null);
@@ -236,6 +242,37 @@
         mVerticalThumb = thumb;
     }
 
+    /**
+     * @see View#getVerticalTrackDrawable()
+     */
+    public @Nullable Drawable getVerticalTrackDrawable() {
+        return mVerticalTrack;
+    }
+
+    /**
+     * @see View#getVerticalThumbDrawable()
+     */
+    public @Nullable Drawable getVerticalThumbDrawable() {
+        return mVerticalThumb;
+    }
+
+    /**
+     * @see View#getHorizontalTrackDrawable()
+     */
+    public @Nullable Drawable getHorizontalTrackDrawable() {
+        return mHorizontalTrack;
+    }
+
+    /**
+     * @see View#getHorizontalThumbDrawable()
+     */
+    public @Nullable Drawable getHorizontalThumbDrawable() {
+        return mHorizontalThumb;
+    }
+
+    /**
+     * @see android.view.View#setVerticalTrackDrawable(Drawable)
+     */
     public void setVerticalTrackDrawable(Drawable track) {
         if (mVerticalTrack != null) {
             mVerticalTrack.setCallback(null);
@@ -245,7 +282,10 @@
         mVerticalTrack = track;
     }
 
-    @UnsupportedAppUsage
+    /**
+     * @see android.view.View#setHorizontalThumbDrawable(Drawable)
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public void setHorizontalThumbDrawable(Drawable thumb) {
         if (mHorizontalThumb != null) {
             mHorizontalThumb.setCallback(null);
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 119a015..8ebcef5 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -46,6 +46,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutManager;
+import android.database.Cursor;
 import android.database.DataSetObserver;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -69,6 +70,8 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
+import android.provider.DocumentsContract;
+import android.provider.OpenableColumns;
 import android.service.chooser.ChooserTarget;
 import android.service.chooser.ChooserTargetService;
 import android.service.chooser.IChooserTargetResult;
@@ -87,7 +90,6 @@
 import android.view.ViewGroup.LayoutParams;
 import android.widget.AbsListView;
 import android.widget.BaseAdapter;
-import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ListView;
@@ -373,50 +375,6 @@
         super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
                 null, false);
 
-        Button copyButton = findViewById(R.id.copy_button);
-        copyButton.setOnClickListener(view -> {
-            Intent targetIntent = getTargetIntent();
-            if (targetIntent == null) {
-                finish();
-            } else {
-                final String action = targetIntent.getAction();
-
-                ClipData clipData = null;
-                if (Intent.ACTION_SEND.equals(action)) {
-                    String extraText = targetIntent.getStringExtra(Intent.EXTRA_TEXT);
-                    Uri extraStream = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
-
-                    if (extraText != null) {
-                        clipData = ClipData.newPlainText(null, extraText);
-                    } else if (extraStream != null) {
-                        clipData = ClipData.newUri(getContentResolver(), null, extraStream);
-                    } else {
-                        Log.w(TAG, "No data available to copy to clipboard");
-                        return;
-                    }
-                } else if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
-                    final ArrayList<Uri> streams = targetIntent.getParcelableArrayListExtra(
-                            Intent.EXTRA_STREAM);
-                    clipData = ClipData.newUri(getContentResolver(), null, streams.get(0));
-                    for (int i = 1; i < streams.size(); i++) {
-                        clipData.addItem(getContentResolver(), new ClipData.Item(streams.get(i)));
-                    }
-                } else {
-                    // expected to only be visible with ACTION_SEND or ACTION_SEND_MULTIPLE
-                    // so warn about unexpected action
-                    Log.w(TAG, "Action (" + action + ") not supported for copying to clipboard");
-                    return;
-                }
-
-                ClipboardManager clipboardManager = (ClipboardManager) getSystemService(
-                        Context.CLIPBOARD_SERVICE);
-                clipboardManager.setPrimaryClip(clipData);
-                Toast.makeText(getApplicationContext(), R.string.copied, Toast.LENGTH_SHORT).show();
-
-                finish();
-            }
-        });
-
         mChooserShownTime = System.currentTimeMillis();
         final long systemCost = mChooserShownTime - intentReceivedTime;
 
@@ -474,6 +432,10 @@
             return;
         }
 
+        if (mChooserListAdapter == null || mChooserListAdapter.getCount() == 0) {
+            return;
+        }
+
         int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
 
         getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)
@@ -481,6 +443,49 @@
         displayContentPreview(previewType, targetIntent);
     }
 
+    private void onCopyButtonClicked(View v) {
+        Intent targetIntent = getTargetIntent();
+        if (targetIntent == null) {
+            finish();
+        } else {
+            final String action = targetIntent.getAction();
+
+            ClipData clipData = null;
+            if (Intent.ACTION_SEND.equals(action)) {
+                String extraText = targetIntent.getStringExtra(Intent.EXTRA_TEXT);
+                Uri extraStream = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+
+                if (extraText != null) {
+                    clipData = ClipData.newPlainText(null, extraText);
+                } else if (extraStream != null) {
+                    clipData = ClipData.newUri(getContentResolver(), null, extraStream);
+                } else {
+                    Log.w(TAG, "No data available to copy to clipboard");
+                    return;
+                }
+            } else if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+                final ArrayList<Uri> streams = targetIntent.getParcelableArrayListExtra(
+                        Intent.EXTRA_STREAM);
+                clipData = ClipData.newUri(getContentResolver(), null, streams.get(0));
+                for (int i = 1; i < streams.size(); i++) {
+                    clipData.addItem(getContentResolver(), new ClipData.Item(streams.get(i)));
+                }
+            } else {
+                // expected to only be visible with ACTION_SEND or ACTION_SEND_MULTIPLE
+                // so warn about unexpected action
+                Log.w(TAG, "Action (" + action + ") not supported for copying to clipboard");
+                return;
+            }
+
+            ClipboardManager clipboardManager = (ClipboardManager) getSystemService(
+                    Context.CLIPBOARD_SERVICE);
+            clipboardManager.setPrimaryClip(clipData);
+            Toast.makeText(getApplicationContext(), R.string.copied, Toast.LENGTH_SHORT).show();
+
+            finish();
+        }
+    }
+
     private void displayContentPreview(@ContentPreviewType int previewType, Intent targetIntent) {
         switch (previewType) {
             case CONTENT_PREVIEW_TEXT:
@@ -501,6 +506,8 @@
         ViewGroup contentPreviewLayout = findViewById(R.id.content_preview_text_area);
         contentPreviewLayout.setVisibility(View.VISIBLE);
 
+        findViewById(R.id.copy_button).setOnClickListener(this::onCopyButtonClicked);
+
         CharSequence sharingText = targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT);
         if (sharingText == null) {
             findViewById(R.id.content_preview_text_layout).setVisibility(View.GONE);
@@ -510,7 +517,7 @@
         }
 
         String previewTitle = targetIntent.getStringExtra(Intent.EXTRA_TITLE);
-        if (previewTitle == null || previewTitle.trim().isEmpty()) {
+        if (TextUtils.isEmpty(previewTitle)) {
             findViewById(R.id.content_preview_title_layout).setVisibility(View.GONE);
         } else {
             TextView previewTitleView = findViewById(R.id.content_preview_title);
@@ -561,6 +568,7 @@
             if (imageUris.size() == 0) {
                 Log.i(TAG, "Attempted to display image preview area with zero"
                         + " available images detected in EXTRA_STREAM list");
+                contentPreviewLayout.setVisibility(View.GONE);
                 return;
             }
 
@@ -580,15 +588,95 @@
         }
     }
 
+    private static class FileInfo {
+        public final String name;
+        public final boolean hasThumbnail;
+
+        FileInfo(String name, boolean hasThumbnail) {
+            this.name = name;
+            this.hasThumbnail = hasThumbnail;
+        }
+    }
+
+    private FileInfo extractFileInfo(Uri uri, ContentResolver resolver) {
+        String fileName = null;
+        boolean hasThumbnail = false;
+        Cursor cursor = resolver.query(uri, null, null, null, null);
+        if (cursor != null && cursor.getCount() > 0) {
+            int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
+            int flagsIndex = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_FLAGS);
+
+            cursor.moveToFirst();
+            fileName = cursor.getString(nameIndex);
+            if (flagsIndex != -1) {
+                hasThumbnail = (cursor.getInt(flagsIndex)
+                        & DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
+            }
+        }
+
+        if (TextUtils.isEmpty(fileName)) {
+            fileName = uri.getPath();
+            int index = fileName.lastIndexOf('/');
+            if (index != -1) {
+                fileName = fileName.substring(index + 1);
+            }
+        }
+
+        return new FileInfo(fileName, hasThumbnail);
+    }
+
     private void displayFileContentPreview(Intent targetIntent) {
-        // support coming
+        ViewGroup contentPreviewLayout = findViewById(R.id.content_preview_file_area);
+        contentPreviewLayout.setVisibility(View.VISIBLE);
+
+        // TODO(b/120417119): Disable file copy until after moving to sysui,
+        // due to permissions issues
+        findViewById(R.id.file_copy_button).setVisibility(View.GONE);
+
+        ContentResolver resolver = getContentResolver();
+        TextView fileNameView = findViewById(R.id.content_preview_filename);
+        String action = targetIntent.getAction();
+        if (Intent.ACTION_SEND.equals(action)) {
+            Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+
+            FileInfo fileInfo = extractFileInfo(uri, resolver);
+            fileNameView.setText(fileInfo.name);
+
+            if (fileInfo.hasThumbnail) {
+                loadUriIntoView(R.id.content_preview_file_thumbnail, uri);
+            } else {
+                ImageView fileIconView = findViewById(R.id.content_preview_file_icon);
+                fileIconView.setVisibility(View.VISIBLE);
+                fileIconView.setImageResource(R.drawable.ic_doc_generic);
+            }
+        } else {
+            List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+            if (uris.size() == 0) {
+                contentPreviewLayout.setVisibility(View.GONE);
+                Log.i(TAG,
+                        "Appears to be no uris available in EXTRA_STREAM, removing preview area");
+                return;
+            }
+
+            FileInfo fileInfo = extractFileInfo(uris.get(0), resolver);
+            int remFileCount = uris.size() - 1;
+            String fileName = getResources().getQuantityString(R.plurals.file_count,
+                    remFileCount, fileInfo.name, remFileCount);
+
+            fileNameView.setText(fileName);
+            ImageView fileIconView = findViewById(R.id.content_preview_file_icon);
+            fileIconView.setVisibility(View.VISIBLE);
+            fileIconView.setImageResource(R.drawable.ic_file_copy);
+        }
     }
 
     private RoundedRectImageView loadUriIntoView(int imageResourceId, Uri uri) {
         RoundedRectImageView imageView = findViewById(imageResourceId);
-        imageView.setVisibility(View.VISIBLE);
         Bitmap bmp = loadThumbnail(uri, new Size(200, 200));
-        imageView.setImageBitmap(bmp);
+        if (bmp != null) {
+            imageView.setVisibility(View.VISIBLE);
+            imageView.setImageBitmap(bmp);
+        }
 
         return imageView;
     }
@@ -1261,9 +1349,8 @@
         }
 
         try {
-            return ImageUtils.decodeSampledBitmapFromStream(getContentResolver(),
-                uri, size.getWidth(), size.getHeight());
-        } catch (IOException | NullPointerException ex) {
+            return ImageUtils.loadThumbnail(getContentResolver(), uri, size);
+        } catch (IOException | NullPointerException | SecurityException ex) {
             Log.w(TAG, "Error loading preview thumbnail for uri: " + uri.toString(), ex);
         }
         return null;
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReader.java b/core/java/com/android/internal/os/KernelCpuThreadReader.java
index b1328e8..6bbfc2b 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReader.java
@@ -109,6 +109,12 @@
     private Predicate<Integer> mUidPredicate;
 
     /**
+     * If a thread has strictly less than {@code minimumTotalCpuUsageMillis} total CPU usage, it
+     * will not be reported
+     */
+    private int mMinimumTotalCpuUsageMillis;
+
+    /**
      * Where the proc filesystem is mounted
      */
     private final Path mProcPath;
@@ -142,10 +148,12 @@
     public KernelCpuThreadReader(
             int numBuckets,
             Predicate<Integer> uidPredicate,
+            int minimumTotalCpuUsageMillis,
             Path procPath,
             Path initialTimeInStatePath,
             Injector injector) throws IOException {
         mUidPredicate = uidPredicate;
+        mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
         mProcPath = procPath;
         mProcTimeInStateReader = new ProcTimeInStateReader(initialTimeInStatePath);
         mInjector = injector;
@@ -158,11 +166,13 @@
      * @return the reader, null if an exception was thrown during creation
      */
     @Nullable
-    public static KernelCpuThreadReader create(int numBuckets, Predicate<Integer> uidPredicate) {
+    public static KernelCpuThreadReader create(
+            int numBuckets, Predicate<Integer> uidPredicate, int minimumTotalCpuUsageMillis) {
         try {
             return new KernelCpuThreadReader(
                     numBuckets,
                     uidPredicate,
+                    minimumTotalCpuUsageMillis,
                     DEFAULT_PROC_PATH,
                     DEFAULT_INITIAL_TIME_IN_STATE_PATH,
                     new Injector());
@@ -308,6 +318,18 @@
     }
 
     /**
+     * If a thread has strictly less than {@code minimumTotalCpuUsageMillis} total CPU usage, it
+     * will not be reported
+     */
+    void setMinimumTotalCpuUsageMillis(int minimumTotalCpuUsageMillis) {
+        if (minimumTotalCpuUsageMillis < 0) {
+            Slog.w(TAG, "Negative minimumTotalCpuUsageMillis: " + minimumTotalCpuUsageMillis);
+            return;
+        }
+        mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
+    }
+
+    /**
      * Get the CPU frequencies that correspond to the times reported in
      * {@link ThreadCpuUsage#usageTimesMillis}
      */
@@ -346,6 +368,15 @@
         }
         int[] cpuUsages = mFrequencyBucketCreator.getBucketedValues(cpuUsagesLong);
 
+        // Check if the total CPU usage below the threshold
+        int totalCpuUsage = 0;
+        for (int i = 0; i < cpuUsages.length; i++) {
+            totalCpuUsage += cpuUsages[i];
+        }
+        if (totalCpuUsage < mMinimumTotalCpuUsageMillis) {
+            return null;
+        }
+
         return new ThreadCpuUsage(threadId, threadName, cpuUsages);
     }
 
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
index 77f6a17..718bcb4 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
@@ -59,6 +59,13 @@
     private static final String COLLECTED_UIDS_SETTINGS_KEY = "collected_uids";
     private static final String COLLECTED_UIDS_DEFAULT = "1000-1000";
 
+    /**
+     * Minimum total CPU usage to report
+     */
+    private static final String MINIMUM_TOTAL_CPU_USAGE_MILLIS_SETTINGS_KEY =
+            "minimum_total_cpu_usage_millis";
+    private static final int MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT = 0;
+
     private final Context mContext;
 
     @Nullable
@@ -87,7 +94,8 @@
         mContext = context;
         mKernelCpuThreadReader = KernelCpuThreadReader.create(
                 NUM_BUCKETS_DEFAULT,
-                UidPredicate.fromString(COLLECTED_UIDS_DEFAULT));
+                UidPredicate.fromString(COLLECTED_UIDS_DEFAULT),
+                MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT);
     }
 
     @Override
@@ -124,6 +132,9 @@
         mKernelCpuThreadReader.setNumBuckets(
                 parser.getInt(NUM_BUCKETS_SETTINGS_KEY, NUM_BUCKETS_DEFAULT));
         mKernelCpuThreadReader.setUidPredicate(uidPredicate);
+        mKernelCpuThreadReader.setMinimumTotalCpuUsageMillis(parser.getInt(
+                MINIMUM_TOTAL_CPU_USAGE_MILLIS_SETTINGS_KEY,
+                MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT));
     }
 
     /**
diff --git a/core/java/com/android/internal/util/ImageUtils.java b/core/java/com/android/internal/util/ImageUtils.java
index 195ae52..274a513 100644
--- a/core/java/com/android/internal/util/ImageUtils.java
+++ b/core/java/com/android/internal/util/ImageUtils.java
@@ -16,20 +16,25 @@
 
 package com.android.internal.util;
 
+import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
-import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
+import android.graphics.ImageDecoder;
+import android.graphics.ImageDecoder.ImageInfo;
+import android.graphics.ImageDecoder.Source;
 import android.graphics.Matrix;
 import android.graphics.Paint;
+import android.graphics.Point;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Bundle;
+import android.util.Size;
 
 import java.io.IOException;
-import java.io.InputStream;
 
 /**
  * Utility class for image analysis and processing.
@@ -166,21 +171,18 @@
     /**
      * @see https://developer.android.com/topic/performance/graphics/load-bitmap
      */
-    public static int calculateInSampleSize(BitmapFactory.Options options,
-            int reqWidth, int reqHeight) {
-        // Raw height and width of image
-        final int height = options.outHeight;
-        final int width = options.outWidth;
+    public static int calculateSampleSize(Size currentSize, Size requestedSize) {
         int inSampleSize = 1;
 
-        if (height > reqHeight || width > reqWidth) {
-            final int halfHeight = height / 2;
-            final int halfWidth = width / 2;
+        if (currentSize.getHeight() > requestedSize.getHeight()
+                || currentSize.getWidth() > requestedSize.getWidth()) {
+            final int halfHeight = currentSize.getHeight() / 2;
+            final int halfWidth = currentSize.getWidth() / 2;
 
             // Calculate the largest inSampleSize value that is a power of 2 and keeps both
             // height and width larger than the requested height and width.
-            while ((halfHeight / inSampleSize) >= reqHeight
-                    && (halfWidth / inSampleSize) >= reqWidth) {
+            while ((halfHeight / inSampleSize) >= requestedSize.getHeight()
+                    && (halfWidth / inSampleSize) >= requestedSize.getWidth()) {
                 inSampleSize *= 2;
             }
         }
@@ -190,27 +192,27 @@
 
     /**
      * Load a bitmap, and attempt to downscale to the required size, to save
-     * on memory.
+     * on memory. Updated to use newer and more compatible ImageDecoder.
      *
      * @see https://developer.android.com/topic/performance/graphics/load-bitmap
      */
-    public static Bitmap decodeSampledBitmapFromStream(ContentResolver resolver,
-            Uri uri, int reqWidth, int reqHeight) throws IOException {
+    public static Bitmap loadThumbnail(ContentResolver resolver, Uri uri, Size size)
+            throws IOException {
 
-        final BitmapFactory.Options options = new BitmapFactory.Options();
-        try (InputStream is = resolver.openInputStream(uri)) {
-            // First decode with inJustDecodeBounds=true to check dimensions
-            options.inJustDecodeBounds = true;
-            BitmapFactory.decodeStream(is, null, options);
+        try (ContentProviderClient client = resolver.acquireContentProviderClient(uri)) {
+            final Bundle opts = new Bundle();
+            opts.putParcelable(ContentResolver.EXTRA_SIZE, Point.convert(size));
 
-            options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
-        }
+            return ImageDecoder.decodeBitmap(ImageDecoder.createSource(() -> {
+                return client.openTypedAssetFile(uri, "image/*", opts, null);
+            }), (ImageDecoder decoder, ImageInfo info, Source source) -> {
+                    decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
 
-        // need to do this twice as the InputStream is consumed in the first call,
-        // and not all InputStreams support marks
-        try (InputStream is = resolver.openInputStream(uri)) {
-            options.inJustDecodeBounds = false;
-            return BitmapFactory.decodeStream(is, null, options);
+                    final int sample = calculateSampleSize(info.getSize(), size);
+                    if (sample > 1) {
+                        decoder.setTargetSampleSize(sample);
+                    }
+                });
         }
     }
 }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 345058b..af0b7c3 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -287,8 +287,8 @@
         "libsoundtrigger",
         "libminikin",
         "libprocessgroup",
-        "libnativebridge",
-        "libnativeloader",
+        "libnativebridge_lazy",
+        "libnativeloader_lazy",
         "libmemunreachable",
         "libhidlbase",
         "libhidltransport",
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index e2e66ce..95f99b7 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -55,6 +55,11 @@
             devOptInChars.c_str(), rulesFd_native, rulesOffset, rulesLength);
 }
 
+bool shouldUseAngle_native(JNIEnv* env, jobject clazz, jstring appName) {
+    ScopedUtfChars appNameChars(env, appName);
+    return android::GraphicsEnv::getInstance().shouldUseAngle(appNameChars.c_str());
+}
+
 void setLayerPaths_native(JNIEnv* env, jobject clazz, jobject classLoader, jstring layerPaths) {
     android::NativeLoaderNamespace* appNamespace = android::FindNativeLoaderNamespaceByClassLoader(
         env, classLoader);
@@ -81,6 +86,7 @@
     { "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) },
     { "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JLjava/lang/String;)V", reinterpret_cast<void*>(setGpuStats_native) },
     { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
+    { "getShouldUseAngle", "(Ljava/lang/String;)Z", reinterpret_cast<void*>(shouldUseAngle_native) },
     { "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
     { "setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native) },
     { "setDebugLayersGLES", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayersGLES_native) },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index d04db92..5cecf66a 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -742,7 +742,7 @@
         return;
     }
 
-    if (GetBoolProperty(kIsolatedStorageSnapshot, GetBoolProperty(kIsolatedStorage, false))) {
+    if (GetBoolProperty(kIsolatedStorageSnapshot, GetBoolProperty(kIsolatedStorage, true))) {
         if (mount_mode == MOUNT_EXTERNAL_FULL || mount_mode == MOUNT_EXTERNAL_LEGACY) {
             storageSource = (mount_mode == MOUNT_EXTERNAL_FULL)
                     ? "/mnt/runtime/full" : "/mnt/runtime/write";
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 30b9b78..5497b86 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -610,6 +610,11 @@
     // CATEGORY: SETTINGS
     // OS: Q
     ACTION_SET_NEW_PARENT_PROFILE_PASSWORD = 1646;
+
+    // ACTION: An interaction with a Slice or other component in the Panel.
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ACTION_PANEL_INTERACTION = 1658;
 }
 
 /**
@@ -2214,4 +2219,16 @@
     // CATEGORY: SETTINGS
     // OS: Q
     SET_NEW_PASSWORD_ACTIVITY = 1644;
+
+    // Panel for Internet Connectivity
+    PANEL_INTERNET_CONNECTIVITY = 1654;
+
+    // Panel for Volume
+    PANEL_VOLUME = 1655;
+
+    // Panel for NFC
+    PANEL_NFC = 1656;
+
+    // Panel for Media Output
+    PANEL_MEDIA_OUTPUT = 1657;
 }
diff --git a/core/proto/android/hardware/sensor/assist/enums.proto b/core/proto/android/hardware/sensor/assist/enums.proto
new file mode 100644
index 0000000..8c5841a
--- /dev/null
+++ b/core/proto/android/hardware/sensor/assist/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.hardware.sensor.assist;
+
+option java_outer_classname = "AssistGestureProtoEnums";
+option java_multiple_files = true;
+
+enum AssistGestureStageEnum {
+  ASSIST_GESTURE_STAGE_UNKNOWN = 0;
+  ASSIST_GESTURE_STAGE_PROGRESS = 1;
+  ASSIST_GESTURE_STAGE_PRIMED = 2;
+  ASSIST_GESTURE_STAGE_DETECTED = 3;
+}
+
+enum AssistGestureFeedbackEnum {
+  ASSIST_GESTURE_FEEDBACK_UNKNOWN = 0;
+  ASSIST_GESTURE_FEEDBACK_NOT_USED = 1;
+  ASSIST_GESTURE_FEEDBACK_USED = 2;
+}
\ No newline at end of file
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index d577653..c9957f3 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -448,6 +448,11 @@
         optional SettingProto game_driver_whitelist = 12;
         // ANGLE - List of Apps that can check ANGLE rules
         optional SettingProto angle_whitelist = 13;
+        // Game Driver - List of blacklists, each blacklist is a blacklist for
+        // a specific Game Driver version
+        optional SettingProto game_driver_blacklists = 14;
+        // ANGLE - Show a dialog box when ANGLE is selected for the currently running PKG
+        optional SettingProto show_angle_in_use_dialog = 15;
     }
     optional Gpu gpu = 59;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 34ec92e..5b74d90 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2151,13 +2151,13 @@
         android:label="@string/permlab_disableKeyguard"
         android:protectionLevel="normal" />
 
-    <!-- Allows an application to get the screen lock complexity and prompt users to update the
+    <!-- Allows an application to request the screen lock complexity and prompt users to update the
      screen lock to a certain complexity level.
      <p>Protection level: normal
     -->
-    <permission android:name="android.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY"
-                android:label="@string/permlab_getAndRequestScreenLockComplexity"
-                android:description="@string/permdesc_getAndRequestScreenLockComplexity"
+    <permission android:name="android.permission.REQUEST_SCREEN_LOCK_COMPLEXITY"
+                android:label="@string/permlab_requestScreenLockComplexity"
+                android:description="@string/permdesc_requestScreenLockComplexity"
                 android:protectionLevel="normal" />
 
     <!-- ================================== -->
diff --git a/core/res/res/drawable/bottomsheet_background.xml b/core/res/res/drawable/bottomsheet_background.xml
index bc32ba6..3a8ad71 100644
--- a/core/res/res/drawable/bottomsheet_background.xml
+++ b/core/res/res/drawable/bottomsheet_background.xml
@@ -16,7 +16,7 @@
 
 <shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
     <corners
-        android:topLeftRadius="?attr/dialogCornerRadius"
-        android:topRightRadius="?attr/dialogCornerRadius" />
+        android:topLeftRadius="@dimen/config_bottomDialogCornerRadius"
+        android:topRightRadius="@dimen/config_bottomDialogCornerRadius"/>
     <solid android:color="?attr/colorBackgroundFloating" />
 </shape>
diff --git a/core/res/res/drawable/ic_file_copy.xml b/core/res/res/drawable/ic_file_copy.xml
new file mode 100644
index 0000000..b6d5e73
--- /dev/null
+++ b/core/res/res/drawable/ic_file_copy.xml
@@ -0,0 +1,24 @@
+<!--
+    Copyright (C) 2019 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5l6,6v10c0,1.1 -0.9,2 -2,2L7.99,23C6.89,23 6,22.1 6,21l0.01,-14c0,-1.1 0.89,-2 1.99,-2h7zM14,12h5.5L14,6.5L14,12z"
+      android:fillColor="#FF737373"/>
+</vector>
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 14a5310..3683bfd 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -213,6 +213,65 @@
         </LinearLayout>
     </LinearLayout>
 
+    <!-- Layout Option 3: File preview, icon, filename, copy-->
+    <LinearLayout
+        android:id="@+id/content_preview_file_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingBottom="@dimen/chooser_view_spacing"
+        android:visibility="gone"
+        android:background="?attr/colorBackgroundFloating">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:paddingLeft="@dimen/chooser_edge_margin_normal"
+            android:paddingRight="@dimen/chooser_edge_margin_normal"
+            android:layout_marginBottom="@dimen/chooser_view_spacing"
+            android:id="@+id/content_preview_file_layout">
+
+            <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
+                  android:id="@+id/content_preview_file_thumbnail"
+                  android:layout_width="75dp"
+                  android:layout_height="75dp"
+                  android:layout_marginRight="16dp"
+                  android:adjustViewBounds="true"
+                  android:layout_gravity="center_vertical"
+                  android:gravity="center"
+                  android:scaleType="centerCrop"
+                  android:visibility="gone"/>
+            <ImageView
+                  android:id="@+id/content_preview_file_icon"
+                  android:layout_width="36dp"
+                  android:layout_height="36dp"
+                  android:layout_marginRight="16dp"
+                  android:adjustViewBounds="true"
+                  android:layout_gravity="center_vertical"
+                  android:gravity="center"
+                  android:scaleType="fitCenter"
+                  android:visibility="gone"/>
+            <TextView
+                android:id="@+id/content_preview_filename"
+                android:layout_width="0dp"
+                android:layout_weight="1"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:ellipsize="middle"
+                android:gravity="start|top"
+                android:paddingRight="24dp"
+                android:singleLine="true"/>
+            <Button
+                android:id="@+id/file_copy_button"
+                android:layout_width="24dp"
+                android:layout_height="24dp"
+                android:gravity="center"
+                android:layout_gravity="center_vertical"
+                android:background="@drawable/ic_content_copy_gm2"/>
+        </LinearLayout>
+    </LinearLayout>
+
     <ListView
         android:layout_width="match_parent"
         android:layout_height="match_parent"
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 64d91ad..13fef67 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -66,7 +66,7 @@
                 android:id="@+id/media_actions"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_gravity="bottom|end"
+                android:layout_gravity="top|end"
                 android:layout_marginStart="10dp"
                 android:layoutDirection="ltr"
                 android:orientation="horizontal"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 18eb7e9..d14164f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3903,4 +3903,22 @@
          The ambient color temperature (in cct) to which we fall back when the ambient brightness
          drops beneath a certain threshold. -->
     <item name="config_displayWhiteBalanceLowLightAmbientColorTemperature" format="float" type="dimen">6500.0</item>
+
+    <!-- See DisplayWhiteBalanceController.
+         A float array containing a list of ambient color temperatures, in Kelvin. This array,
+         together with config_displayWhiteBalanceDisplayTemperatureValues, is used to generate a
+         lookup table used in DisplayWhiteBalanceController. This lookup table is used to map
+         ambient color temperature readings to a target color temperature for the display.
+         This table is optional. If used, this array must,
+         1) Contain at least two entries
+         2) Be the same length as config_displayWhiteBalanceDisplayTemperatureValues. -->
+    <array name="config_displayWhiteBalanceAmbientTemperatureValues">
+    </array>
+
+    <!-- See DisplayWhiteBalanceController.
+         An array containing a list of display color temperatures, in Kelvin. See
+         config_displayWhiteBalanceAmbientTemperatureValues for additional details.
+         The same restrictions apply to this array. -->
+    <array name="config_displayWhiteBalanceDisplayTemperatureValues">
+    </array>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6d5bd4b..0cdf388 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1406,9 +1406,9 @@
       re-enables the keylock when the call is finished.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
-    <string name="permlab_getAndRequestScreenLockComplexity">get and request screen lock complexity</string>
+    <string name="permlab_requestScreenLockComplexity">request screen lock complexity</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
-    <string name="permdesc_getAndRequestScreenLockComplexity">Allows the app to learn the screen
+    <string name="permdesc_requestScreenLockComplexity">Allows the app to learn the screen
         lock complexity level (high, medium, low or none), which indicates the possible range of
         length and type of the screen lock. The app can also suggest to users that they update the
         screen lock to a certain level but users can freely ignore and navigate away. Note that the
@@ -5284,4 +5284,9 @@
     <!-- Strings for car -->
     <!-- String displayed when loading a user in the car [CHAR LIMIT=30] -->
     <string name="car_loading_profile">Loading</string>
+
+    <plurals name="file_count">
+        <item quantity="one"><xliff:g id="file_name">%s</xliff:g> + <xliff:g id="count">%d</xliff:g> file</item>
+        <item quantity="other"><xliff:g id="file_name">%s</xliff:g> + <xliff:g id="count">%d</xliff:g> files</item>
+    </plurals>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8e251fd..a1bafbf 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -50,6 +50,11 @@
   <java-symbol type="id" name="characterPicker" />
   <java-symbol type="id" name="clearDefaultHint" />
   <java-symbol type="id" name="contentPanel" />
+  <java-symbol type="id" name="content_preview_file_area" />
+  <java-symbol type="id" name="content_preview_file_icon" />
+  <java-symbol type="id" name="content_preview_file_layout" />
+  <java-symbol type="id" name="content_preview_file_thumbnail" />
+  <java-symbol type="id" name="content_preview_filename" />
   <java-symbol type="id" name="content_preview_image_area" />
   <java-symbol type="id" name="content_preview_image_1_large" />
   <java-symbol type="id" name="content_preview_image_2_large" />
@@ -62,6 +67,7 @@
   <java-symbol type="id" name="content_preview_title" />
   <java-symbol type="id" name="content_preview_title_layout" />
   <java-symbol type="id" name="copy_button" />
+  <java-symbol type="id" name="file_copy_button" />
   <java-symbol type="id" name="current_scene" />
   <java-symbol type="id" name="scene_layoutid_cache" />
   <java-symbol type="id" name="customPanel" />
@@ -1266,6 +1272,7 @@
   <java-symbol type="string" name="tooltip_popup_title" />
 
   <java-symbol type="plurals" name="bugreport_countdown" />
+  <java-symbol type="plurals" name="file_count" />
   <java-symbol type="plurals" name="last_num_days" />
   <java-symbol type="plurals" name="matches_found" />
   <java-symbol type="plurals" name="restr_pin_countdown" />
@@ -1307,6 +1314,7 @@
   <java-symbol type="drawable" name="default_wallpaper" />
   <java-symbol type="drawable" name="default_lock_wallpaper" />
   <java-symbol type="drawable" name="indicator_input_error" />
+  <java-symbol type="drawable" name="ic_file_copy" />
   <java-symbol type="drawable" name="popup_bottom_dark" />
   <java-symbol type="drawable" name="popup_bottom_bright" />
   <java-symbol type="drawable" name="popup_bottom_medium" />
@@ -3643,6 +3651,7 @@
   <java-symbol type="array" name="config_displayWhiteBalanceDecreaseThresholds" />
   <java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientBrightnessThreshold" />
   <java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientColorTemperature" />
-
+  <java-symbol type="array" name="config_displayWhiteBalanceAmbientTemperatureValues" />
+  <java-symbol type="array" name="config_displayWhiteBalanceDisplayTemperatureValues" />
   <java-symbol type="drawable" name="ic_action_open" />
 </resources>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 206682a..4d2f005 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -491,8 +491,10 @@
                     Settings.Global.GAME_DRIVER_ALL_APPS,
                     Settings.Global.GAME_DRIVER_OPT_IN_APPS,
                     Settings.Global.GAME_DRIVER_OPT_OUT_APPS,
+                    Settings.Global.GAME_DRIVER_BLACKLISTS,
                     Settings.Global.GAME_DRIVER_BLACKLIST,
                     Settings.Global.GAME_DRIVER_WHITELIST,
+                    Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX,
                     Settings.Global.GPU_DEBUG_LAYER_APP,
                     Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
                     Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 3d59835a..7f104b1 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -409,8 +409,7 @@
     @Test
     public void copyTextToClipboard() throws Exception {
         Intent sendIntent = createSendTextIntent();
-        List<ResolvedComponentInfo> resolvedComponentInfos =
-                createResolvedComponentsForTestWithOtherProfile(1);
+        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
 
         when(ChooserWrapperActivity.sOverrides.resolverListController.getResolversForIntent(
             Mockito.anyBoolean(),
@@ -421,6 +420,7 @@
                 .launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
 
+        onView(withId(R.id.copy_button)).check(matches(isDisplayed()));
         onView(withId(R.id.copy_button)).perform(click());
         ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(
                 Context.CLIPBOARD_SERVICE);
@@ -439,8 +439,9 @@
         ArrayList<Uri> uris = new ArrayList<>();
         uris.add(uri);
 
-        Intent sendIntent = createSendImageIntentWithPreview(uris);
+        Intent sendIntent = createSendUriIntentWithPreview(uris);
         sOverrides.previewThumbnail = createBitmap();
+        sOverrides.isImageType = true;
 
         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
 
@@ -464,8 +465,9 @@
         uris.add(uri);
         uris.add(uri);
 
-        Intent sendIntent = createSendImageIntentWithPreview(uris);
+        Intent sendIntent = createSendUriIntentWithPreview(uris);
         sOverrides.previewThumbnail = createBitmap();
+        sOverrides.isImageType = true;
 
         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
 
@@ -492,8 +494,9 @@
         uris.add(uri);
         uris.add(uri);
 
-        Intent sendIntent = createSendImageIntentWithPreview(uris);
+        Intent sendIntent = createSendUriIntentWithPreview(uris);
         sOverrides.previewThumbnail = createBitmap();
+        sOverrides.isImageType = true;
 
         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
 
@@ -538,12 +541,11 @@
         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "empty preview logger test"));
         waitForIdle();
-        verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
+
+        verify(mockLogger, Mockito.times(1)).write(logMakerCaptor.capture());
         // First invocation is from onCreate
-        assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
-                is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
-        assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
-                is(CONTENT_PREVIEW_TEXT));
+        assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
+                is(MetricsProto.MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
     }
 
     @Test
@@ -552,9 +554,17 @@
 
         MetricsLogger mockLogger = sOverrides.metricsLogger;
         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+
+        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+        when(ChooserWrapperActivity.sOverrides.resolverListController.getResolversForIntent(
+            Mockito.anyBoolean(),
+            Mockito.anyBoolean(),
+            Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
+        verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
         // First invocation is from onCreate
         assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
                 is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
@@ -570,8 +580,9 @@
         ArrayList<Uri> uris = new ArrayList<>();
         uris.add(uri);
 
-        Intent sendIntent = createSendImageIntentWithPreview(uris);
+        Intent sendIntent = createSendUriIntentWithPreview(uris);
         sOverrides.previewThumbnail = createBitmap();
+        sOverrides.isImageType = true;
 
         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
 
@@ -595,6 +606,51 @@
                 is(CONTENT_PREVIEW_IMAGE));
     }
 
+    @Test
+    public void oneVisibleFilePreview() throws InterruptedException {
+        Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf");
+
+        ArrayList<Uri> uris = new ArrayList<>();
+        uris.add(uri);
+
+        Intent sendIntent = createSendUriIntentWithPreview(uris);
+
+        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+        mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+        waitForIdle();
+        onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
+        onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf")));
+        onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
+    }
+
+
+    @Test
+    public void moreThanOneVisibleFilePreview() throws InterruptedException {
+        Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf");
+
+        ArrayList<Uri> uris = new ArrayList<>();
+        uris.add(uri);
+        uris.add(uri);
+        uris.add(uri);
+
+        Intent sendIntent = createSendUriIntentWithPreview(uris);
+
+        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+        mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+        waitForIdle();
+        onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
+        onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf + 2 files")));
+        onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
+    }
+
     private Intent createSendTextIntent() {
         Intent sendIntent = new Intent();
         sendIntent.setAction(Intent.ACTION_SEND);
@@ -615,7 +671,7 @@
         return sendIntent;
     }
 
-    private Intent createSendImageIntentWithPreview(ArrayList<Uri> uris) {
+    private Intent createSendUriIntentWithPreview(ArrayList<Uri> uris) {
         Intent sendIntent = new Intent();
 
         if (uris.size() > 1) {
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index f60467b..096b78b 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -89,11 +89,7 @@
 
     @Override
     protected boolean isImageType(String mimeType) {
-        if (sOverrides.previewThumbnail != null) {
-            return true;
-        }
-
-        return super.isImageType(mimeType);
+        return sOverrides.isImageType;
     }
 
     @Override
@@ -112,6 +108,7 @@
         public Function<TargetInfo, Boolean> onSafelyStartCallback;
         public ResolverListController resolverListController;
         public Boolean isVoiceInteraction;
+        public boolean isImageType;
         public Bitmap previewThumbnail;
         public MetricsLogger metricsLogger;
 
@@ -120,6 +117,7 @@
             isVoiceInteraction = null;
             createPackageManager = null;
             previewThumbnail = null;
+            isImageType = false;
             resolverListController = mock(ResolverListController.class);
             metricsLogger = mock(MetricsLogger.class);
         }
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
index 64b7c2c..1c84829 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
@@ -124,7 +124,7 @@
 
         // Get thread data from KernelCpuThreadReader
         final KernelCpuThreadReader kernelCpuThreadReader =
-                KernelCpuThreadReader.create(8, uid -> uid == Process.myUid());
+                KernelCpuThreadReader.create(8, uid -> uid == Process.myUid(), 0);
         assertNotNull(kernelCpuThreadReader);
         final ProcessCpuUsage currentProcessCpuUsage =
                 kernelCpuThreadReader.getCurrentProcessCpuUsage();
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
index b9744f5..442ece5 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
@@ -103,6 +103,7 @@
         final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
                 8,
                 uid -> 1000 <= uid && uid < 2000,
+                0,
                 mProcDirectory.toPath(),
                 mProcDirectory.toPath().resolve("self/task/" + THREAD_IDS[0] + "/time_in_state"),
                 processUtils);
@@ -144,6 +145,7 @@
         final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
                 8,
                 uidPredicate,
+                0,
                 mProcDirectory.toPath(),
                 mProcDirectory.toPath().resolve(uids[0] + "/task/" + uids[0] + "/time_in_state"),
                 processUtils);
@@ -162,6 +164,60 @@
         }
     }
 
+    @Test
+    public void testReader_filtersLowUsage() throws IOException {
+        int[] uids = new int[]{0, 1, 2, 3, 4};
+        int[] cpuUsage = new int[]{10, 0, 2, 100, 3};
+        int[] expectedUids = new int[]{0, 3, 4};
+        Predicate<Integer> uidPredicate = uid -> true;
+        KernelCpuThreadReader.Injector processUtils =
+                new KernelCpuThreadReader.Injector() {
+                    @Override
+                    public int myPid() {
+                        return 0;
+                    }
+
+                    @Override
+                    public int myUid() {
+                        return 0;
+                    }
+
+                    @Override
+                    public int getUidForPid(int pid) {
+                        return pid;
+                    }
+                };
+
+        for (int i = 0; i < uids.length; i++) {
+            int uid = uids[i];
+            setupDirectory(
+                    mProcDirectory.toPath().resolve(String.valueOf(uid)),
+                    new int[]{uid * 10},
+                    "process" + uid,
+                    new String[]{"thread" + uid},
+                    new int[]{1000},
+                    new int[][]{{cpuUsage[i]}});
+        }
+        final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
+                8,
+                uidPredicate,
+                30,
+                mProcDirectory.toPath(),
+                mProcDirectory.toPath().resolve(uids[0] + "/task/" + uids[0] + "/time_in_state"),
+                processUtils);
+        ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsageByUids =
+                kernelCpuThreadReader.getProcessCpuUsageByUids();
+        processCpuUsageByUids.sort(Comparator.comparing(usage -> usage.uid));
+
+        assertEquals(expectedUids.length, processCpuUsageByUids.size());
+        for (int i = 0; i < expectedUids.length; i++) {
+            KernelCpuThreadReader.ProcessCpuUsage processCpuUsage =
+                    processCpuUsageByUids.get(i);
+            assertEquals(expectedUids[i], processCpuUsage.uid);
+        }
+
+    }
+
     private void setupDirectory(Path processPath, int[] threadIds, String processName,
             String[] threadNames, int[] cpuFrequencies, int[][] cpuTimes) throws IOException {
         // Make /proc/$PID
@@ -328,7 +384,6 @@
                         new long[]{1, 1, 1, 1, 1, 1, 1, 1}));
     }
 
-
     @Test
     public void testGetBigFrequenciesStartIndex_simple() {
         assertEquals(
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 7382213..915cf95 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -328,4 +328,9 @@
         <permission name="android.permission.CONTROL_VPN"/>
     </privapp-permissions>
 
+    <privapp-permissions package="com.android.dynandroid">
+        <permission name="android.permission.REBOOT"/>
+        <permission name="android.permission.MANAGE_DYNAMIC_ANDROID"/>
+    </privapp-permissions>
+
 </permissions>
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 56be05b..ef9255f 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -127,7 +127,10 @@
     static Typeface sDefaultTypeface;
 
     // Following two fields are not used but left for hiddenapi private list
-    @UnsupportedAppUsage
+    /**
+     * Use {@link SystemFonts#getAvailableFonts()} instead.
+     */
+    @UnsupportedAppUsage(trackingBug = 123769347)
     static final Map<String, Typeface> sSystemFontMap;
 
     // We cannot support sSystemFallbackMap since we will migrate to public FontFamily API.
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 991847a..6ecb621 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -44,6 +44,7 @@
 import android.graphics.Shader;
 import android.graphics.SweepGradient;
 import android.graphics.Xfermode;
+import android.os.Build;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -156,12 +157,12 @@
     private static final float DEFAULT_INNER_RADIUS_RATIO = 3.0f;
     private static final float DEFAULT_THICKNESS_RATIO = 9.0f;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
     private GradientState mGradientState;
 
     @UnsupportedAppUsage
     private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051827)
     private Rect mPadding;
     @UnsupportedAppUsage
     private Paint mStrokePaint;   // optional, set by the caller
@@ -670,7 +671,28 @@
      * @see #setColor(int)
      */
     public void setColors(@ColorInt int[] colors) {
+        setColors(colors, null);
+    }
+
+    /**
+     * Sets the colors and offsets used to draw the gradient.
+     * <p>
+     * Each color is specified as an ARGB integer and the array must contain at
+     * least 2 colors.
+     * <p>
+     * <strong>Note</strong>: changing colors will affect all instances of a
+     * drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing the colors.
+     *
+     * @param colors an array containing 2 or more ARGB colors
+     * @param offsets optional array of floating point parameters representing the positions
+     *                of the colors. Null evenly disperses the colors
+     * @see #mutate()
+     * @see #setColors(int[])
+     */
+    public void setColors(@ColorInt int[] colors, @Nullable float[] offsets) {
         mGradientState.setGradientColors(colors);
+        mGradientState.mPositions = offsets;
         mGradientIsDirty = true;
         invalidateSelf();
     }
@@ -849,6 +871,115 @@
         }
     }
 
+    /**
+     * Inner radius of the ring expressed as a ratio of the ring's width.
+     *
+     * @see #getInnerRadiusRatio()
+     * @attr ref android.R.styleable#GradientDrawable_innerRadiusRatio
+     */
+    public void setInnerRadiusRatio(float innerRadiusRatio) {
+        mGradientState.mInnerRadiusRatio = innerRadiusRatio;
+        mPathIsDirty = true;
+        invalidateSelf();
+    }
+
+    /**
+     * Return the inner radius of the ring expressed as a ratio of the ring's width.
+     *
+     * @see #setInnerRadiusRatio(float)
+     * @attr ref android.R.styleable#GradientDrawable_innerRadiusRatio
+     */
+    public float getInnerRadiusRatio() {
+        return mGradientState.mInnerRadiusRatio;
+    }
+
+    /**
+     * Configure the inner radius of the ring.
+     *
+     * @see #getInnerRadius()
+     * @attr ref android.R.styleable#GradientDrawable_innerRadius
+     */
+    public void setInnerRadius(int innerRadius) {
+        mGradientState.mInnerRadius = innerRadius;
+        mPathIsDirty = true;
+        invalidateSelf();
+    }
+
+    /**
+     * Retrn the inner radius of the ring
+     *
+     * @see #setInnerRadius(int)
+     * @attr ref android.R.styleable#GradientDrawable_innerRadius
+     */
+    public int getInnerRadius() {
+        return mGradientState.mInnerRadius;
+    }
+
+    /**
+     * Configure the thickness of the ring expressed as a ratio of the ring's width.
+     *
+     * @see #getThicknessRatio()
+     * @attr ref android.R.styleable#GradientDrawable_thicknessRatio
+     */
+    public void setThicknessRatio(float thicknessRatio) {
+        mGradientState.mThicknessRatio = thicknessRatio;
+        mPathIsDirty = true;
+        invalidateSelf();
+    }
+
+    /**
+     * Return the thickness ratio of the ring expressed as a ratio of the ring's width.
+     *
+     * @see #setThicknessRatio(float)
+     * @attr ref android.R.styleable#GradientDrawable_thicknessRatio
+     */
+    public float getThicknessRatio() {
+        return mGradientState.mThicknessRatio;
+    }
+
+    /**
+     * Configure the thickness of the ring.
+     *
+     * @attr ref android.R.styleable#GradientDrawable_thickness
+     */
+    public void setThickness(int thickness) {
+        mGradientState.mThickness = thickness;
+        mPathIsDirty = true;
+        invalidateSelf();
+    }
+
+    /**
+     * Return the thickness of the ring
+     *
+     * @see #setThickness(int)
+     * @attr ref android.R.styleable#GradientDrawable_thickness
+     */
+    public int getThickness() {
+        return mGradientState.mThickness;
+    }
+
+    /**
+     * Configure the padding of the gradient shape
+     * @param left Left padding of the gradient shape
+     * @param top Top padding of the gradient shape
+     * @param right Right padding of the gradient shape
+     * @param bottom Bottom padding of the gradient shape
+     *
+     * @attr ref android.R.styleable#GradientDrawablePadding_left
+     * @attr ref android.R.styleable#GradientDrawablePadding_top
+     * @attr ref android.R.styleable#GradientDrawablePadding_right
+     * @attr ref android.R.styleable#GradientDrawablePadding_bottom
+     */
+    public void setPadding(int left, int top, int right, int bottom) {
+        if (mGradientState.mPadding == null) {
+            mGradientState.mPadding = new Rect();
+        }
+
+        mGradientState.mPadding.set(left, top, right, bottom);
+        mPadding = mGradientState.mPadding;
+        invalidateSelf();
+    }
+
     private Path buildRing(GradientState st) {
         if (mRingPath != null && (!st.mUseLevelForShape || !mPathIsDirty)) return mRingPath;
         mPathIsDirty = false;
@@ -1814,46 +1945,46 @@
 
     final static class GradientState extends ConstantState {
         public @Config int mChangingConfigurations;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public @Shape int mShape = RECTANGLE;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public @GradientType int mGradient = LINEAR_GRADIENT;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public int mAngle = 0;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public Orientation mOrientation;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public ColorStateList mSolidColors;
         public ColorStateList mStrokeColors;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug =  124050917)
         public @ColorInt int[] mGradientColors;
         public @ColorInt int[] mTempColors; // no need to copy
         public float[] mTempPositions; // no need to copy
         @UnsupportedAppUsage
         public float[] mPositions;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public int mStrokeWidth = -1; // if >= 0 use stroking.
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public float mStrokeDashWidth = 0.0f;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public float mStrokeDashGap = 0.0f;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public float mRadius = 0.0f; // use this if mRadiusArray is null
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public float[] mRadiusArray = null;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public Rect mPadding = null;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public int mWidth = -1;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public int mHeight = -1;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public float mInnerRadiusRatio = DEFAULT_INNER_RADIUS_RATIO;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050218)
         public float mThicknessRatio = DEFAULT_THICKNESS_RATIO;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
         public int mInnerRadius = -1;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050218)
         public int mThickness = -1;
         public boolean mDither = false;
         public Insets mOpticalInsets = Insets.NONE;
diff --git a/libs/hwui/FrameMetricsObserver.h b/libs/hwui/FrameMetricsObserver.h
index 237fc62..b93f078 100644
--- a/libs/hwui/FrameMetricsObserver.h
+++ b/libs/hwui/FrameMetricsObserver.h
@@ -23,7 +23,7 @@
 
 class FrameMetricsObserver : public VirtualLightRefBase {
 public:
-    virtual void notify(const int64_t* buffer);
+    virtual void notify(const int64_t* buffer) = 0;
 };
 
 }  // namespace uirenderer
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 59eff64..a545f2e 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -96,7 +96,7 @@
             STATE_TOW_DECODED, STATE_MSEC_AMBIGUOUS, STATE_SYMBOL_SYNC, STATE_GLO_STRING_SYNC,
             STATE_GLO_TOD_DECODED, STATE_BDS_D2_BIT_SYNC, STATE_BDS_D2_SUBFRAME_SYNC,
             STATE_GAL_E1BC_CODE_LOCK, STATE_GAL_E1C_2ND_CODE_LOCK, STATE_GAL_E1B_PAGE_SYNC,
-            STATE_SBAS_SYNC, STATE_TOW_KNOWN, STATE_GLO_TOD_KNOWN
+            STATE_SBAS_SYNC, STATE_TOW_KNOWN, STATE_GLO_TOD_KNOWN, STATE_2ND_CODE_LOCK
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface State {}
@@ -144,6 +144,9 @@
      */
     public static final int STATE_GLO_TOD_KNOWN = (1<<15);
 
+    /** This GNSS measurement's tracking state has secondary code lock. */
+    public static final int STATE_2ND_CODE_LOCK  = (1 << 16);
+
     /**
      * All the GNSS receiver state flags, for bit masking purposes (not a sensible state for any
      * individual measurement.)
@@ -517,6 +520,9 @@
         if ((mState & STATE_SBAS_SYNC) != 0) {
             builder.append("SbasSync|");
         }
+        if ((mState & STATE_2ND_CODE_LOCK) != 0) {
+            builder.append("2ndCodeLock|");
+        }
 
         int remainingStates = mState & ~STATE_ALL;
         if (remainingStates > 0) {
@@ -531,96 +537,315 @@
     /**
      * Gets the received GNSS satellite time, at the measurement time, in nanoseconds.
      *
-     * <p>For GPS &amp; QZSS, this is:
-     * <ul>
-     * <li>Received GPS Time-of-Week at the measurement time, in nanoseconds.</li>
-     * <li>The value is relative to the beginning of the current GPS week.</li>
-     * </ul>
+     * <p>The received satellite time is relative to the beginning of the system week for all
+     * constellations except for Glonass where it is relative to the beginning of the Glonass
+     * system day.
      *
-     * <p>Given the highest sync state that can be achieved, per each satellite, valid range
-     * for this field can be:
-     * <pre>
-     *     Searching       : [ 0       ]   : STATE_UNKNOWN
-     *     C/A code lock   : [ 0   1ms ]   : STATE_CODE_LOCK is set
-     *     Bit sync        : [ 0  20ms ]   : STATE_BIT_SYNC is set
-     *     Subframe sync   : [ 0    6s ]   : STATE_SUBFRAME_SYNC is set
-     *     TOW decoded     : [ 0 1week ]   : STATE_TOW_DECODED is set
-     *     TOW Known       : [ 0 1week ]   : STATE_TOW_KNOWN set</pre>
+     * <p>The table below indicates the valid range of the received GNSS satellite time. These
+     * ranges depend on the constellation and code being tracked and the state of the tracking
+     * algorithms given by the {@link #getState} method. The minimum value of this field is zero.
+     * The maximum value of this field is determined by looking across all of the state flags
+     * that are set, for the given constellation and code type, and finding the the maximum value
+     * in this table.
      *
-     * Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has
+     * <p>For example, for GPS L1 C/A, if STATE_TOW_KNOWN is set, this field can be any value from 0
+     * to 1 week (in nanoseconds), and for GAL E1B code, if only STATE_GAL_E1BC_CODE_LOCK is set,
+     * then this field can be any value from 0 to 4 milliseconds (in nanoseconds.)
+     *
+     * <table border="1">
+     *   <thead>
+     *     <tr>
+     *       <td />
+     *       <td colspan="3"><strong>GPS/QZSS</strong></td>
+     *       <td><strong>GLNS</strong></td>
+     *       <td colspan="2"><strong>BDS</strong></td>
+     *       <td colspan="3"><strong>GAL</strong></td>
+     *       <td><strong>SBAS</strong></td>
+     *     </tr>
+     *     <tr>
+     *       <td><strong>State Flag</strong></td>
+     *       <td><strong>L1 C/A</strong></td>
+     *       <td><strong>L5I</strong></td>
+     *       <td><strong>L5Q</strong></td>
+     *       <td><strong>L1OF</strong></td>
+     *       <td><strong>B1I (D1)</strong></td>
+     *       <td><strong>B1I &nbsp;(D2)</strong></td>
+     *       <td><strong>E1B</strong></td>
+     *       <td><strong>E1C</strong></td>
+     *       <td><strong>E5AQ</strong></td>
+     *       <td><strong>L1 C/A</strong></td>
+     *     </tr>
+     *   </thead>
+     *   <tbody>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_UNKNOWN</strong>
+     *       </td>
+     *       <td>0</td>
+     *       <td>0</td>
+     *       <td>0</td>
+     *       <td>0</td>
+     *       <td>0</td>
+     *       <td>0</td>
+     *       <td>0</td>
+     *       <td>0</td>
+     *       <td>0</td>
+     *       <td>0</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_CODE_LOCK</strong>
+     *       </td>
+     *       <td>1 ms</td>
+     *       <td>1 ms</td>
+     *       <td>1 ms</td>
+     *       <td>1 ms</td>
+     *       <td>1 ms</td>
+     *       <td>1 ms</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>1 ms</td>
+     *       <td>1 ms</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_SYMBOL_SYNC</strong>
+     *       </td>
+     *       <td>20 ms (optional)</td>
+     *       <td>10 ms</td>
+     *       <td>1 ms (optional)</td>
+     *       <td>10 ms</td>
+     *       <td>20 ms (optional)</td>
+     *       <td>2 ms</td>
+     *       <td>4 ms (optional)</td>
+     *       <td>4 ms (optional)</td>
+     *       <td>1 ms (optional)</td>
+     *       <td>2 ms</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_BIT_SYNC</strong>
+     *       </td>
+     *       <td>20 ms</td>
+     *       <td>20 ms</td>
+     *       <td>1 ms (optional)</td>
+     *       <td>20 ms</td>
+     *       <td>20 ms</td>
+     *       <td>-</td>
+     *       <td>8 ms</td>
+     *       <td>-</td>
+     *       <td>1 ms (optional)</td>
+     *       <td>4 ms</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_SUBFRAME_SYNC</strong>
+     *       </td>
+     *       <td>6s</td>
+     *       <td>6s</td>
+     *       <td>-</td>
+     *       <td>2 s</td>
+     *       <td>6 s</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>100 ms</td>
+     *       <td>-</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_TOW_DECODED</strong>
+     *       </td>
+     *       <td colspan="2">1 week</td>
+     *       <td>-</td>
+     *       <td>1 day</td>
+     *       <td colspan="2">1 week</td>
+     *       <td colspan="2">1 week</td>
+     *       <td>-</td>
+     *       <td>1 week</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_TOW_KNOWN</strong>
+     *       </td>
+     *       <td colspan="3">1 week</td>
+     *       <td>1 day</td>
+     *       <td colspan="2">1 week</td>
+     *       <td colspan="3">1 week</td>
+     *       <td>1 week</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_GLO_STRING_SYNC</strong>
+     *       </td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>2 s</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_GLO_TOD_DECODED</strong>
+     *       </td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>1 day</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_GLO_TOD_KNOWN</strong>
+     *       </td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>1 day</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_BDS_D2_BIT_SYNC</strong>
+     *       </td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>2 ms</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_BDS_D2_SUBFRAME_SYNC</strong>
+     *       </td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>600 ms</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_GAL_E1BC_CODE_LOCK</strong>
+     *       </td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>4 ms</td>
+     *       <td>4 ms</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_GAL_E1C_2ND_CODE_LOCK</strong>
+     *       </td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>100 ms</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_2ND_CODE_LOCK</strong>
+     *       </td>
+     *       <td>-</td>
+     *       <td>10 ms (optional)</td>
+     *       <td>20 ms</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>100 ms (optional)</td>
+     *       <td>100 ms</td>
+     *       <td>-</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_GAL_E1B_PAGE_SYNC</strong>
+     *       </td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>2 s</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <strong>STATE_SBAS_SYNC</strong>
+     *       </td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>-</td>
+     *       <td>1 s</td>
+     *     </tr>
+     *   </tbody>
+     * </table>
+     *
+     * <p>Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has
      * been determined from other sources. If TOW decoded is set then TOW Known must also be set.
      *
-     * <p>Note well: if there is any ambiguity in integer millisecond, {@code STATE_MSEC_AMBIGUOUS}
-     * must be set accordingly, in the 'state' field.
+     * <p>Note well: if there is any ambiguity in integer millisecond, STATE_MSEC_AMBIGUOUS must be
+     * set accordingly, in the 'state' field. This value must be populated, unless the 'state' ==
+     * STATE_UNKNOWN.
      *
-     * <p>This value must be populated if 'state' != {@code STATE_UNKNOWN}.
-     *
-     * <p>For Glonass, this is:
+     * <p>Note on optional flags:
      * <ul>
-     * <li>Received Glonass time of day, at the measurement time in nanoseconds.</li>
+     *     <li> For L1 C/A and B1I, STATE_SYMBOL_SYNC is optional since the symbol length is the
+     *     same as the bit length.
+     *     <li> For L5Q and E5aQ, STATE_BIT_SYNC and STATE_SYMBOL_SYNC are optional since they are
+     *     implied by STATE_CODE_LOCK.
+     *     <li> STATE_2ND_CODE_LOCK for L5I is optional since it is implied by STATE_SYMBOL_SYNC.
+     *     <li> STATE_2ND_CODE_LOCK for E1C is optional since it is implied by
+     *     STATE_GAL_E1C_2ND_CODE_LOCK.
+     *     <li> For E1B and E1C, STATE_SYMBOL_SYNC is optional, because it is implied by
+     *     STATE_GAL_E1BC_CODE_LOCK.
      * </ul>
-     *
-     * <p>Given the highest sync state that can be achieved, per each satellite, valid range for
-     * this field can be:
-     * <pre>
-     *     Searching           : [ 0       ]   : STATE_UNKNOWN
-     *     C/A code lock       : [ 0   1ms ]   : STATE_CODE_LOCK is set
-     *     Symbol sync         : [ 0  10ms ]   : STATE_SYMBOL_SYNC is set
-     *     Bit sync            : [ 0  20ms ]   : STATE_BIT_SYNC is set
-     *     String sync         : [ 0    2s ]   : STATE_GLO_STRING_SYNC is set
-     *     Time of day decoded : [ 0  1day ]   : STATE_GLO_TOD_DECODED is set
-     *     Time of day known   : [ 0  1day ]   : STATE_GLO_TOD_KNOWN set</pre>
-     *
-     * Note: Time of day known refers to the case where it is possibly not decoded over the air but
-     * has been determined from other sources. If Time of day decoded is set then Time of day known
-     * must also be set.
-     *
-     * <p>For Beidou, this is:
-     * <ul>
-     * <li>Received Beidou time of week, at the measurement time in nanoseconds.</li>
-     * </ul>
-     *
-     * <p>Given the highest sync state that can be achieved, per each satellite, valid range for
-     * this field can be:
-     * <pre>
-     *     Searching              : [ 0       ]   : STATE_UNKNOWN
-     *     C/A code lock          : [ 0   1ms ]   : STATE_CODE_LOCK is set
-     *     Bit sync (D2)          : [ 0   2ms ]   : STATE_BDS_D2_BIT_SYNC is set
-     *     Bit sync (D1)          : [ 0  20ms ]   : STATE_BIT_SYNC is set
-     *     Subframe (D2)          : [ 0  0.6s ]   : STATE_BDS_D2_SUBFRAME_SYNC is set
-     *     Subframe (D1)          : [ 0    6s ]   : STATE_SUBFRAME_SYNC is set
-     *     Time of week decoded   : [ 0 1week ]   : STATE_TOW_DECODED is set
-     *     Time of week known     : [ 0 1week ]   : STATE_TOW_KNOWN set</pre>
-     *
-     * Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has
-     * been determined from other sources. If TOW decoded is set then TOW Known must also be set.
-     *
-     * <p>For Galileo, this is:
-     * <ul>
-     * <li>Received Galileo time of week, at the measurement time in nanoseconds.</li>
-     * </ul>
-     * <pre>
-     *     E1BC code lock       : [ 0   4ms ]  : STATE_GAL_E1BC_CODE_LOCK is set
-     *     E1C 2nd code lock    : [ 0 100ms ]  : STATE_GAL_E1C_2ND_CODE_LOCK is set
-     *     E1B page             : [ 0    2s ]  : STATE_GAL_E1B_PAGE_SYNC is set
-     *     Time of week decoded : [ 0 1week ]  : STATE_TOW_DECODED is set
-     *     Time of week known   : [ 0 1week ]  : STATE_TOW_KNOWN set</pre>
-     *
-     * Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has
-     * been determined from other sources. If TOW decoded is set then TOW Known must also be set.
-     *
-     * <p>For SBAS, this is:
-     * <ul>
-     * <li>Received SBAS time, at the measurement time in nanoseconds.</li>
-     * </ul>
-     *
-     * <p>Given the highest sync state that can be achieved, per each satellite, valid range for
-     * this field can be:
-     * <pre>
-     *     Searching       : [ 0       ]   : STATE_UNKNOWN
-     *     C/A code lock   : [ 0   1ms ]   : STATE_CODE_LOCK is set
-     *     Symbol sync     : [ 0   2ms ]   : STATE_SYMBOL_SYNC is set
-     *     Message         : [ 0    1s ]   : STATE_SBAS_SYNC is set</pre>
      */
     public long getReceivedSvTimeNanos() {
         return mReceivedSvTimeNanos;
diff --git a/media/Android.bp b/media/Android.bp
index 141d415c..86dc509 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -3,7 +3,6 @@
 
     srcs: [
         ":updatable-media-srcs",
-        ":framework-media-annotation-srcs",
     ],
 
     aidl: {
@@ -28,7 +27,12 @@
     installable: true,
 
     // Make sure that the implementaion only relies on SDK or system APIs.
-    sdk_version: "system_current",
+    no_framework_libs: true,
+    libs: [
+        // The order matters. android_system_* library should come later.
+        "framework_media_annotation",
+        "android_system_stubs_current",
+    ],
 }
 
 filegroup {
@@ -125,3 +129,8 @@
     sdk_version: "28",
 }
 
+java_library {
+    name: "framework_media_annotation",
+    srcs: [":framework-media-annotation-srcs"],
+    installable: false,
+}
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index c38a831..89a9540 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -45,8 +45,8 @@
 import android.view.Surface;
 import android.view.SurfaceHolder;
 
-import com.android.framework.protobuf.InvalidProtocolBufferException;
 import com.android.internal.annotations.GuardedBy;
+import com.android.media.protobuf.InvalidProtocolBufferException;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
diff --git a/media/native/midi/Android.bp b/media/native/midi/Android.bp
index d069bd2..58317ed 100644
--- a/media/native/midi/Android.bp
+++ b/media/native/midi/Android.bp
@@ -16,7 +16,7 @@
     name: "libamidi",
 
     srcs: [
-        "midi.cpp",
+        "amidi.cpp",
         ":IMidiDeviceServer.aidl",
     ],
 
@@ -48,10 +48,10 @@
 
     from: "include",
 
-    to: "amidi",
+    to: "",
 
-    srcs: ["include/midi.h"],
-    license: "include/NOTICE",
+    srcs: ["include/amidi/AMidi.h"],
+    license: "include/amidi/NOTICE",
 }
 
 ndk_library {
diff --git a/media/native/midi/midi.cpp b/media/native/midi/amidi.cpp
similarity index 99%
rename from media/native/midi/midi.cpp
rename to media/native/midi/amidi.cpp
index a5bdba8..1e9a194 100644
--- a/media/native/midi/midi.cpp
+++ b/media/native/midi/amidi.cpp
@@ -28,8 +28,8 @@
 #include "android/media/midi/BpMidiDeviceServer.h"
 #include "media/MidiDeviceInfo.h"
 
-#include "include/midi.h"
-#include "midi_internal.h"
+#include "include/amidi/AMidi.h"
+#include "amidi_internal.h"
 
 using namespace android::media::midi;
 
diff --git a/media/native/midi/midi_internal.h b/media/native/midi/amidi_internal.h
similarity index 93%
rename from media/native/midi/midi_internal.h
rename to media/native/midi/amidi_internal.h
index cb3ecce..fce8596 100644
--- a/media/native/midi/midi_internal.h
+++ b/media/native/midi/amidi_internal.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_MEDIA_MIDI_INTERNAL_H_
-#define ANDROID_MEDIA_MIDI_INTERNAL_H_
+#ifndef ANDROID_MEDIA_AMIDI_INTERNAL_H_
+#define ANDROID_MEDIA_AMIDI_INTERNAL_H_
 
 #include <jni.h>
 
@@ -38,4 +38,4 @@
     AMidiDeviceInfo deviceInfo; /* Attributes of the device. */
 };
 
-#endif // ANDROID_MEDIA_MIDI_INTERNAL_H_
+#endif // ANDROID_MEDIA_AMIDI_INTERNAL_H_
diff --git a/media/native/midi/include/midi.h b/media/native/midi/include/amidi/AMidi.h
similarity index 79%
rename from media/native/midi/include/midi.h
rename to media/native/midi/include/amidi/AMidi.h
index 755d09f..0d60b0d 100644
--- a/media/native/midi/include/midi.h
+++ b/media/native/midi/include/amidi/AMidi.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_MEDIA_MIDI_H_
-#define ANDROID_MEDIA_MIDI_H_
+#ifndef ANDROID_MEDIA_AMIDI_H_
+#define ANDROID_MEDIA_AMIDI_H_
 
 #include <stdarg.h>
 #include <stdint.h>
@@ -66,9 +66,9 @@
  * @param outDevicePtrPtr  Points to the pointer to receive the AMidiDevice
  *
  * @return AMEDIA_OK on success, or a negative error value:
- *  @see AMEDIA_ERROR_INVALID_OBJECT {@link AMEDIA_ERROR_INVALID_OBJECT} - the midiDeviceObj
+ *  @see AMEDIA_ERROR_INVALID_OBJECT - the midiDeviceObj
  *    is null or already connected to a native AMidiDevice
-  *  @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - an unknown error occurred.
+  *  @see AMEDIA_ERROR_UNKNOWN - an unknown error occurred.
  */
 media_status_t AMIDI_API AMidiDevice_fromJava(
         JNIEnv *env, jobject midiDeviceObj, AMidiDevice **outDevicePtrPtr) __INTRODUCED_IN(29);
@@ -80,13 +80,10 @@
  *
  * @return AMEDIA_OK on success,
  * or a negative error value:
- *  @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER}
- *  - the device parameter is NULL.
- *  @see AMEDIA_ERROR_INVALID_OBJECT {@link AMEDIA_ERROR_INVALID_OBJECT}
- *  - the device is not consistent with the associated Java MidiDevice.
- *  @see AMEDIA_ERROR_INVALID_OBJECT {@link AMEDIA_ERROR_INVALID_OBJECT}
- *  - the JNI interface initialization to the associated java MidiDevice failed.
- *  @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - couldn't retrieve the device info.
+ *  @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
+ *  @see AMEDIA_ERROR_INVALID_OBJECT - the device is not consistent with the associated Java MidiDevice.
+ *  @see AMEDIA_ERROR_INVALID_OBJECT - the JNI interface initialization to the associated java MidiDevice failed.
+ *  @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
  */
 media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *midiDevice) __INTRODUCED_IN(29);
 
@@ -100,9 +97,8 @@
  *  AMIDI_DEVICE_TYPE_VIRTUAL
  *  AMIDI_DEVICE_TYPE_BLUETOOTH
  * or a negative error value:
- *  @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} - the device
- *  parameter is NULL.
- *  @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown error.
+ *  @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
+ *  @see AMEDIA_ERROR_UNKNOWN - Unknown error.
  */
 int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device) __INTRODUCED_IN(29);
 
@@ -113,9 +109,8 @@
  *
  * @return If successful, returns the number of MIDI input (sending) ports available on the
  * device. If an error occurs, returns a negative value indicating the error:
- *  @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} - the device
- *  parameter is NULL.
- *  @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - couldn't retrieve the device info.
+ *  @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
+ *  @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
  */
 ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
 
@@ -126,9 +121,8 @@
  *
  * @return If successful, returns the number of MIDI output (receiving) ports available on the
  * device. If an error occurs, returns a negative value indicating the error:
- *  @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} - the device
- *  parameter is NULL.
- *  @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN}- couldn't retrieve the device info.
+ *  @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
+ *  @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
  */
 ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
 
@@ -146,7 +140,7 @@
  * @param outOutputPortPtr Receives the native API port identifier of the opened port.
  *
  * @return AMEDIA_OK, or a negative error code:
- *  @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown Error.
+ *  @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
  */
 media_status_t AMIDI_API AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
                              AMidiOutputPort **outOutputPortPtr) __INTRODUCED_IN(29);
@@ -174,7 +168,7 @@
  *  (the current value of the running Java Virtual Machine's high-resolution time source,
  *  in nanoseconds)
  * @return the number of messages received (either 0 or 1), or a negative error code:
- *  @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown Error.
+ *  @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
  */
 ssize_t AMIDI_API AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
          uint8_t *buffer, size_t maxBytes, size_t* numBytesReceivedPtr, int64_t *outTimestampPtr) __INTRODUCED_IN(29);
@@ -193,7 +187,7 @@
  * @param outInputPortPtr Receives the native API port identifier of the opened port.
  *
  * @return AMEDIA_OK, or a negative error code:
- *  @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown Error.
+ *  @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
  */
 media_status_t AMIDI_API AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
                             AMidiInputPort **outInputPortPtr) __INTRODUCED_IN(29);
@@ -206,8 +200,7 @@
  * @param numBytes     Specifies the number of bytes to write.
  *
  * @return The number of bytes sent, which could be less than specified or a negative error code:
- * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} The specified port
- *   was NULL, the specified buffer was NULL.
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL, the specified buffer was NULL.
  */
 ssize_t AMIDI_API AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
                    size_t numBytes) __INTRODUCED_IN(29);
@@ -221,8 +214,7 @@
  * @param timestamp    The CLOCK_MONOTONIC time in nanoseconds to associate with the sent data.
  *
  * @return The number of bytes sent, which could be less than specified or a negative error code:
- * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} The specified port
- *   was NULL, the specified buffer was NULL.
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL, the specified buffer was NULL.
  */
 ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
         const uint8_t *buffer, size_t numBytes, int64_t timestamp) __INTRODUCED_IN(29);
@@ -233,10 +225,9 @@
  *
  * @param inputPort The identifier of the port to send the flush command to.
  *
- * @returns @see AMEDIA_OK {@link AMEDIA_OK} if successful, otherwise a negative error code:
- * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} The specified port
- *   was NULL
- * @see AMEDIA_ERROR_UNSUPPORTED {@link AMEDIA_ERROR_UNSUPPORTED} The FLUSH command couldn't
+ * @returns @see AMEDIA_OK if successful, otherwise a negative error code:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL
+ * @see AMEDIA_ERROR_UNSUPPORTED - The FLUSH command couldn't
  * be sent.
  */
 media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
@@ -252,4 +243,4 @@
 }
 #endif
 
-#endif /* ANDROID_MEDIA_MIDI_H_ */
+#endif /* ANDROID_MEDIA_AMIDI_H_ */
diff --git a/media/native/midi/include/NOTICE b/media/native/midi/include/amidi/NOTICE
similarity index 100%
rename from media/native/midi/include/NOTICE
rename to media/native/midi/include/amidi/NOTICE
diff --git a/media/proto/jarjar-rules.txt b/media/proto/jarjar-rules.txt
index 7be6e73..bfb0b27 100644
--- a/media/proto/jarjar-rules.txt
+++ b/media/proto/jarjar-rules.txt
@@ -1,2 +1,2 @@
-rule com.google.protobuf.** com.android.framework.protobuf.@1
+rule com.google.protobuf.** com.android.media.protobuf.@1
 
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 730c409..a3db2d6 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -146,6 +146,7 @@
     AHardwareBuffer_getNativeHandle; # introduced=26
     AHardwareBuffer_isSupported; # introduced=29
     AHardwareBuffer_lock; # introduced=26
+    AHardwareBuffer_lockPlanes; # introduced=29
     AHardwareBuffer_recvHandleFromUnixSocket; # introduced=26
     AHardwareBuffer_release; # introduced=26
     AHardwareBuffer_sendHandleToUnixSocket; # introduced=26
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 2dba1d5b..c5a951c 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -221,30 +221,6 @@
         }
     }
 
-    @Override
-    public void destroy() {
-        mCarBatteryController.stopListening();
-        mConnectedDeviceSignalController.stopListening();
-        mActivityManagerWrapper.unregisterTaskStackListener(mTaskStackListener);
-        mDrivingStateHelper.disconnectFromCarService();
-
-        if (mNavigationBarWindow != null) {
-            mWindowManager.removeViewImmediate(mNavigationBarWindow);
-            mNavigationBarView = null;
-        }
-
-        if (mLeftNavigationBarWindow != null) {
-            mWindowManager.removeViewImmediate(mLeftNavigationBarWindow);
-            mLeftNavigationBarView = null;
-        }
-
-        if (mRightNavigationBarWindow != null) {
-            mWindowManager.removeViewImmediate(mRightNavigationBarWindow);
-            mRightNavigationBarView = null;
-        }
-        super.destroy();
-    }
-
 
     @Override
     protected void makeStatusBarView() {
diff --git a/packages/DynamicAndroidInstallationService/Android.mk b/packages/DynamicAndroidInstallationService/Android.mk
new file mode 100644
index 0000000..13d96ac
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, res)
+
+LOCAL_USE_AAPT2 := true
+
+LOCAL_PACKAGE_NAME := DynamicAndroidInstallationService
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+
+include $(BUILD_PACKAGE)
diff --git a/packages/DynamicAndroidInstallationService/AndroidManifest.xml b/packages/DynamicAndroidInstallationService/AndroidManifest.xml
new file mode 100644
index 0000000..1c1c72c
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.dynandroid"
+        android:sharedUserId="android.uid.system">
+
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.MANAGE_DYNAMNIC_ANDROID" />
+    <uses-permission android:name="android.permission.REBOOT" />
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+
+    <application
+        android:allowBackup="false"
+        android:label="@string/app_name">
+
+        <service
+            android:name=".DynamicAndroidInstallationService"
+            android:enabled="true"
+            android:exported="true"
+            android:permission="android.permission.MANAGE_DYNAMNIC_ANDROID"
+            android:process=":dynandroid">
+            <intent-filter>
+                <action android:name="android.content.action.NOTIFY_IF_IN_USE" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </service>
+
+        <activity android:name=".VerificationActivity"
+            android:exported="true"
+            android:permission="android.permission.MANAGE_DYNAMNIC_ANDROID"
+            android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar"
+            android:process=":dynandroid">
+            <intent-filter>
+                <action android:name="android.content.action.START_INSTALL" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <receiver
+            android:name=".BootCompletedReceiver"
+            android:enabled="true"
+            android:exported="false">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED" />
+            </intent-filter>
+        </receiver>
+    </application>
+</manifest>
diff --git a/packages/DynamicAndroidInstallationService/MODULE_LICENSE_APACHE2 b/packages/DynamicAndroidInstallationService/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/MODULE_LICENSE_APACHE2
diff --git a/packages/DynamicAndroidInstallationService/NOTICE b/packages/DynamicAndroidInstallationService/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/packages/DynamicAndroidInstallationService/res/drawable/ic_system_update_googblue_24dp.xml b/packages/DynamicAndroidInstallationService/res/drawable/ic_system_update_googblue_24dp.xml
new file mode 100644
index 0000000..acf1567
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/res/drawable/ic_system_update_googblue_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14zM16,13h-3L13,8h-2v5L8,13l4,4 4,-4z"
+      android:fillColor="#4285F4"/>
+</vector>
diff --git a/packages/DynamicAndroidInstallationService/res/values/strings.xml b/packages/DynamicAndroidInstallationService/res/values/strings.xml
new file mode 100644
index 0000000..221e1d7
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/res/values/strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!-- application name [CHAR LIMIT=32] -->
+    <string name="app_name">AndroidOnTap Installer</string>
+
+    <!-- notification channel name [CHAR LIMIT=32] -->
+    <string name="notification_channel_name">AndroidOnTap Installer</string>
+
+    <!-- password page title [CHAR LIMIT=32] -->
+    <string name="keyguard_title">AndroidOnTap Installer</string>
+
+    <!-- password page description [CHAR LIMIT=128] -->
+    <string name="keyguard_description">Please enter your password and continue to AndroidOnTap installation</string>
+
+    <!-- Displayed on notification: DynAndroid installation is completed [CHAR LIMIT=128] -->
+    <string name="notification_install_completed">Installation is completed, you can reboot into the new installed system now.</string>
+    <!-- Displayed on notification: DynAndroid installation is in progress [CHAR LIMIT=128] -->
+    <string name="notification_install_inprogress">Installation is in progress.</string>
+    <!-- Displayed on notification: DynAndroid installation is in progress [CHAR LIMIT=128] -->
+    <string name="notification_install_failed">Installation Failed.</string>
+    <!-- Displayed on notification: We are running in AndroidOnTap [CHAR LIMIT=128] -->
+    <string name="notification_dynandroid_in_use">We are running in AndroidOnTap.</string>
+
+    <!-- Action on notification: Cancel installation [CHAR LIMIT=16] -->
+    <string name="notification_action_cancel">Cancel</string>
+    <!-- Action on notification: Discard installation [CHAR LIMIT=16] -->
+    <string name="notification_action_discard">Discard</string>
+    <!-- Action on notification: Uninstall AndroidOnTap [CHAR LIMIT=16] -->
+    <string name="notification_action_uninstall">Uninstall</string>
+    <!-- Action on notification: Reboot to AndroidOnTap [CHAR LIMIT=16] -->
+    <string name="notification_action_reboot_to_dynandroid">Reboot</string>
+
+</resources>
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java
new file mode 100644
index 0000000..dd1be89
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java
@@ -0,0 +1,50 @@
+/*
+ * 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.dynandroid;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DynamicAndroidClient;
+import android.content.Intent;
+import android.os.UserHandle;
+import android.util.Log;
+
+
+/**
+ * A BoardcastReceiver waiting for ACTION_BOOT_COMPLETED and ask
+ * the service to display a notification if we are currently running
+ * in DynamicAndroid.
+ */
+public class BootCompletedReceiver extends BroadcastReceiver {
+
+    private static final String TAG = "BootCompletedReceiver";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+
+        Log.d(TAG, "Broadcast received: " + action);
+
+        if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+            Intent startServiceIntent = new Intent(
+                    context, DynamicAndroidInstallationService.class);
+
+            startServiceIntent.setAction(DynamicAndroidClient.ACTION_NOTIFY_IF_IN_USE);
+            context.startServiceAsUser(startServiceIntent, UserHandle.SYSTEM);
+        }
+    }
+}
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
new file mode 100644
index 0000000..7755cbc
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
@@ -0,0 +1,483 @@
+/*
+ * 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.dynandroid;
+
+import static android.content.DynamicAndroidClient.ACTION_NOTIFY_IF_IN_USE;
+import static android.content.DynamicAndroidClient.ACTION_START_INSTALL;
+import static android.content.DynamicAndroidClient.CAUSE_ERROR_EXCEPTION;
+import static android.content.DynamicAndroidClient.CAUSE_ERROR_INVALID_URL;
+import static android.content.DynamicAndroidClient.CAUSE_ERROR_IO;
+import static android.content.DynamicAndroidClient.CAUSE_INSTALL_CANCELLED;
+import static android.content.DynamicAndroidClient.CAUSE_INSTALL_COMPLETED;
+import static android.content.DynamicAndroidClient.CAUSE_NOT_SPECIFIED;
+import static android.content.DynamicAndroidClient.STATUS_IN_PROGRESS;
+import static android.content.DynamicAndroidClient.STATUS_IN_USE;
+import static android.content.DynamicAndroidClient.STATUS_NOT_STARTED;
+import static android.content.DynamicAndroidClient.STATUS_READY;
+import static android.os.AsyncTask.Status.FINISHED;
+import static android.os.AsyncTask.Status.PENDING;
+import static android.os.AsyncTask.Status.RUNNING;
+
+import static com.android.dynandroid.InstallationAsyncTask.RESULT_ERROR_EXCEPTION;
+import static com.android.dynandroid.InstallationAsyncTask.RESULT_ERROR_INVALID_URL;
+import static com.android.dynandroid.InstallationAsyncTask.RESULT_ERROR_IO;
+import static com.android.dynandroid.InstallationAsyncTask.RESULT_OK;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.DynamicAndroidClient;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.DynamicAndroidManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+/**
+ * This class is the service in charge of DynamicAndroid installation.
+ * It also posts status to notification bar and wait for user's
+ * cancel and confirm commnands.
+ */
+public class DynamicAndroidInstallationService extends Service
+        implements InstallationAsyncTask.InstallStatusListener {
+
+    private static final String TAG = "DynAndroidInstallationService";
+
+    /*
+     * Intent actions
+     */
+    private static final String ACTION_CANCEL_INSTALL =
+            "com.android.dynandroid.ACTION_CANCEL_INSTALL";
+    private static final String ACTION_REBOOT_TO_DYN_ANDROID =
+            "com.android.dynandroid.ACTION_REBOOT_TO_DYN_ANDROID";
+    private static final String ACTION_REBOOT_TO_NORMAL =
+            "com.android.dynandroid.ACTION_REBOOT_TO_NORMAL";
+
+    /*
+     * For notification
+     */
+    private static final String NOTIFICATION_CHANNEL_ID = "com.android.dynandroid";
+    private static final int NOTIFICATION_ID = 1;
+
+    /*
+     * IPC
+     */
+    /** Keeps track of all current registered clients. */
+    ArrayList<Messenger> mClients = new ArrayList<>();
+
+    /** Handler of incoming messages from clients. */
+    final Messenger mMessenger = new Messenger(new IncomingHandler(this));
+
+    static class IncomingHandler extends Handler {
+        private final WeakReference<DynamicAndroidInstallationService> mWeakService;
+
+        IncomingHandler(DynamicAndroidInstallationService service) {
+            mWeakService = new WeakReference<>(service);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            DynamicAndroidInstallationService service = mWeakService.get();
+
+            if (service != null) {
+                service.handleMessage(msg);
+            }
+        }
+    }
+
+    private DynamicAndroidManager mDynAndroid;
+    private NotificationManager mNM;
+
+    private long mSystemSize;
+    private long mInstalledSize;
+    private boolean mJustCancelledByUser;
+
+    private PendingIntent mPiCancel;
+    private PendingIntent mPiRebootToDynamicAndroid;
+    private PendingIntent mPiUninstallAndReboot;
+
+    private InstallationAsyncTask mInstallTask;
+
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        prepareNotification();
+
+        mDynAndroid = (DynamicAndroidManager) getSystemService(Context.DYNAMIC_ANDROID_SERVICE);
+    }
+
+    @Override
+    public void onDestroy() {
+        // Cancel the persistent notification.
+        mNM.cancel(NOTIFICATION_ID);
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mMessenger.getBinder();
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        String action = intent.getAction();
+
+        Log.d(TAG, "onStartCommand(): action=" + action);
+
+        if (ACTION_START_INSTALL.equals(action)) {
+            executeInstallCommand(intent);
+        } else if (ACTION_CANCEL_INSTALL.equals(action)) {
+            executeCancelCommand();
+        } else if (ACTION_REBOOT_TO_DYN_ANDROID.equals(action)) {
+            executeRebootToDynAndroidCommand();
+        } else if (ACTION_REBOOT_TO_NORMAL.equals(action)) {
+            executeRebootToNormalCommand();
+        } else if (ACTION_NOTIFY_IF_IN_USE.equals(action)) {
+            executeNotifyIfInUseCommand();
+        }
+
+        return Service.START_NOT_STICKY;
+    }
+
+    @Override
+    public void onProgressUpdate(long installedSize) {
+        mInstalledSize = installedSize;
+        postStatus(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED);
+    }
+
+    @Override
+    public void onResult(int result) {
+        if (result == RESULT_OK) {
+            postStatus(STATUS_READY, CAUSE_INSTALL_COMPLETED);
+            return;
+        }
+
+        // if it's not successful, reset the task and stop self.
+        resetTaskAndStop();
+
+        switch (result) {
+            case RESULT_ERROR_IO:
+                postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_IO);
+                break;
+
+            case RESULT_ERROR_INVALID_URL:
+                postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_INVALID_URL);
+                break;
+
+            case RESULT_ERROR_EXCEPTION:
+                postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_EXCEPTION);
+                break;
+        }
+    }
+
+    @Override
+    public void onCancelled() {
+        resetTaskAndStop();
+        postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED);
+    }
+
+    private void executeInstallCommand(Intent intent) {
+        if (!verifyRequest(intent)) {
+            Log.e(TAG, "Verification failed. Did you use VerificationActivity?");
+            return;
+        }
+
+        if (mInstallTask != null) {
+            Log.e(TAG, "There is already an install task running");
+            return;
+        }
+
+        if (isInDynamicAndroid()) {
+            Log.e(TAG, "We are already running in DynamicAndroid");
+            return;
+        }
+
+        String url = intent.getStringExtra(DynamicAndroidClient.KEY_SYSTEM_URL);
+        mSystemSize = intent.getLongExtra(DynamicAndroidClient.KEY_SYSTEM_SIZE, 0);
+        long userdata = intent.getLongExtra(DynamicAndroidClient.KEY_USERDATA_SIZE, 0);
+
+        mInstallTask = new InstallationAsyncTask(url, mSystemSize, userdata, mDynAndroid, this);
+        mInstallTask.execute();
+
+        // start fore ground
+        startForeground(NOTIFICATION_ID,
+                buildNotification(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED));
+    }
+
+    private void executeCancelCommand() {
+        if (mInstallTask == null || mInstallTask.getStatus() == PENDING) {
+            Log.e(TAG, "Cancel command triggered, but there is no task running");
+            mNM.cancel(NOTIFICATION_ID);
+
+            return;
+        }
+
+        mJustCancelledByUser = true;
+
+        if (mInstallTask.cancel(false)) {
+            // Will cleanup and post status in onCancelled()
+            Log.d(TAG, "Cancel request filed successfully");
+        } else {
+            Log.d(TAG, "Requested cancel, completed task will be discarded");
+
+            resetTaskAndStop();
+            postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED);
+        }
+
+    }
+
+    private void executeRebootToDynAndroidCommand() {
+        if (mInstallTask == null || mInstallTask.getStatus() != FINISHED) {
+            Log.e(TAG, "Trying to reboot to DynamicAndroid, but there is no complete installation");
+            return;
+        }
+
+        if (!mInstallTask.commit()) {
+            // TODO: b/123673280 better UI response
+            Log.e(TAG, "Failed to commit installation because of native runtime error.");
+            mNM.cancel(NOTIFICATION_ID);
+
+            return;
+        }
+
+        PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+
+        if (powerManager != null) {
+            powerManager.reboot("dynandroid");
+        }
+    }
+
+    private void executeRebootToNormalCommand() {
+        mDynAndroid.remove();
+
+        PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+
+        if (powerManager != null) {
+            powerManager.reboot(null);
+        }
+    }
+
+    private void executeNotifyIfInUseCommand() {
+        if (isInDynamicAndroid()) {
+            startForeground(NOTIFICATION_ID,
+                    buildNotification(STATUS_IN_USE, CAUSE_NOT_SPECIFIED));
+        }
+    }
+
+    private void resetTaskAndStop() {
+        mInstallTask = null;
+
+        stopForeground(true);
+
+        // stop self, but this service is not destroyed yet if it's still bound
+        stopSelf();
+    }
+
+    private void prepareNotification() {
+        NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
+                getString(R.string.notification_channel_name),
+                NotificationManager.IMPORTANCE_LOW);
+
+        mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+
+        if (mNM != null) {
+            mNM.createNotificationChannel(chan);
+        }
+
+        Intent intentCancel = new Intent(this, DynamicAndroidInstallationService.class);
+        intentCancel.setAction(ACTION_CANCEL_INSTALL);
+        mPiCancel = PendingIntent.getService(this, 0, intentCancel, 0);
+
+        Intent intentRebootToDyn = new Intent(this, DynamicAndroidInstallationService.class);
+        intentRebootToDyn.setAction(ACTION_REBOOT_TO_DYN_ANDROID);
+        mPiRebootToDynamicAndroid = PendingIntent.getService(this, 0, intentRebootToDyn, 0);
+
+        Intent intentUninstallAndReboot = new Intent(this, DynamicAndroidInstallationService.class);
+        intentUninstallAndReboot.setAction(ACTION_REBOOT_TO_NORMAL);
+        mPiUninstallAndReboot = PendingIntent.getService(this, 0, intentUninstallAndReboot, 0);
+    }
+
+    private Notification buildNotification(int status, int cause) {
+        Notification.Builder builder = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
+                .setSmallIcon(R.drawable.ic_system_update_googblue_24dp)
+                .setProgress(0, 0, false);
+
+        switch (status) {
+            case STATUS_IN_PROGRESS:
+                builder.setContentText(getString(R.string.notification_install_inprogress));
+
+                int max = (int) Math.max(mSystemSize >> 20, 1);
+                int progress = (int) mInstalledSize >> 20;
+
+                builder.setProgress(max, progress, false);
+
+                builder.addAction(new Notification.Action.Builder(
+                        null, getString(R.string.notification_action_cancel),
+                        mPiCancel).build());
+
+                break;
+
+            case STATUS_READY:
+                builder.setContentText(getString(R.string.notification_install_completed));
+
+                builder.addAction(new Notification.Action.Builder(
+                        null, getString(R.string.notification_action_reboot_to_dynandroid),
+                        mPiRebootToDynamicAndroid).build());
+
+                builder.addAction(new Notification.Action.Builder(
+                        null, getString(R.string.notification_action_cancel),
+                        mPiCancel).build());
+
+                break;
+
+            case STATUS_IN_USE:
+                builder.setContentText(getString(R.string.notification_dynandroid_in_use));
+
+                builder.addAction(new Notification.Action.Builder(
+                        null, getString(R.string.notification_action_uninstall),
+                        mPiUninstallAndReboot).build());
+
+                break;
+
+            case STATUS_NOT_STARTED:
+                if (cause != CAUSE_NOT_SPECIFIED && cause != CAUSE_INSTALL_CANCELLED) {
+                    builder.setContentText(getString(R.string.notification_install_failed));
+                } else {
+                    // no need to notify the user if the task is not started, or cancelled.
+                }
+                break;
+
+            default:
+                throw new IllegalStateException("status is invalid");
+        }
+
+        return builder.build();
+    }
+
+    private boolean verifyRequest(Intent intent) {
+        String url = intent.getStringExtra(DynamicAndroidClient.KEY_SYSTEM_URL);
+
+        return VerificationActivity.isVerified(url);
+    }
+
+    private void postStatus(int status, int cause) {
+        Log.d(TAG, "postStatus(): statusCode=" + status + ", causeCode=" + cause);
+
+        boolean notifyOnNotificationBar = true;
+
+        if (status == STATUS_NOT_STARTED
+                && cause == CAUSE_INSTALL_CANCELLED
+                && mJustCancelledByUser) {
+            // if task is cancelled by user, do not notify them
+            notifyOnNotificationBar = false;
+            mJustCancelledByUser = false;
+        }
+
+        if (notifyOnNotificationBar) {
+            mNM.notify(NOTIFICATION_ID, buildNotification(status, cause));
+        }
+
+        for (int i = mClients.size() - 1; i >= 0; i--) {
+            try {
+                notifyOneClient(mClients.get(i), status, cause);
+            } catch (RemoteException e) {
+                mClients.remove(i);
+            }
+        }
+    }
+
+    private void notifyOneClient(Messenger client, int status, int cause) throws RemoteException {
+        Bundle bundle = new Bundle();
+
+        bundle.putLong(DynamicAndroidClient.KEY_INSTALLED_SIZE, mInstalledSize);
+
+        client.send(Message.obtain(null,
+                  DynamicAndroidClient.MSG_POST_STATUS, status, cause, bundle));
+    }
+
+    private int getStatus() {
+        if (isInDynamicAndroid()) {
+            return STATUS_IN_USE;
+
+        } else if (mInstallTask == null) {
+            return STATUS_NOT_STARTED;
+
+        }
+
+        switch (mInstallTask.getStatus()) {
+            case PENDING:
+                return STATUS_NOT_STARTED;
+
+            case RUNNING:
+                return STATUS_IN_PROGRESS;
+
+            case FINISHED:
+                int result = mInstallTask.getResult();
+
+                if (result == RESULT_OK) {
+                    return STATUS_READY;
+                } else {
+                    throw new IllegalStateException("A failed InstallationTask is not reset");
+                }
+
+            default:
+                return STATUS_NOT_STARTED;
+        }
+    }
+
+    private boolean isInDynamicAndroid() {
+        return mDynAndroid.isInUse();
+    }
+
+    void handleMessage(Message msg) {
+        switch (msg.what) {
+            case DynamicAndroidClient.MSG_REGISTER_LISTENER:
+                try {
+                    Messenger client = msg.replyTo;
+
+                    int status = getStatus();
+
+                    // tell just registered client my status, but do not specify cause
+                    notifyOneClient(client, status, CAUSE_NOT_SPECIFIED);
+
+                    mClients.add(client);
+                } catch (RemoteException e) {
+                    // do nothing if we cannot send update to the client
+                    e.printStackTrace();
+                }
+
+                break;
+            case DynamicAndroidClient.MSG_UNREGISTER_LISTENER:
+                mClients.remove(msg.replyTo);
+                break;
+            default:
+                // do nothing
+        }
+    }
+}
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java
new file mode 100644
index 0000000..3c759e9
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java
@@ -0,0 +1,205 @@
+/*
+ * 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.dynandroid;
+
+import android.os.AsyncTask;
+import android.os.DynamicAndroidManager;
+import android.util.Log;
+import android.webkit.URLUtil;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.zip.GZIPInputStream;
+
+
+class InstallationAsyncTask extends AsyncTask<String, Long, Integer> {
+
+    private static final String TAG = "InstallationAsyncTask";
+
+    private static final int READ_BUFFER_SIZE = 1 << 19;
+
+    private class InvalidImageUrlException extends RuntimeException {
+        private InvalidImageUrlException(String message) {
+            super(message);
+        }
+    }
+
+
+    /** Not completed, including being cancelled */
+    static final int NO_RESULT = 0;
+    static final int RESULT_OK = 1;
+    static final int RESULT_ERROR_IO = 2;
+    static final int RESULT_ERROR_INVALID_URL = 3;
+    static final int RESULT_ERROR_EXCEPTION = 6;
+
+    interface InstallStatusListener {
+        void onProgressUpdate(long installedSize);
+        void onResult(int resultCode);
+        void onCancelled();
+    }
+
+    private final String mUrl;
+    private final long mSystemSize;
+    private final long mUserdataSize;
+    private final DynamicAndroidManager mDynamicAndroid;
+    private final InstallStatusListener mListener;
+    private DynamicAndroidManager.Session mInstallationSession;
+
+    private long mInstalledSize;
+    private long mReportedInstalledSize;
+    private int mResult = NO_RESULT;
+
+    private InputStream mStream;
+
+
+    InstallationAsyncTask(String url, long systemSize, long userdataSize,
+            DynamicAndroidManager dynAndroid, InstallStatusListener listener) {
+        mUrl = url;
+        mSystemSize = systemSize;
+        mUserdataSize = userdataSize;
+        mDynamicAndroid = dynAndroid;
+        mListener = listener;
+    }
+
+    @Override
+    protected void onPreExecute() {
+        mListener.onProgressUpdate(0);
+    }
+
+    @Override
+    protected Integer doInBackground(String... voids) {
+        Log.d(TAG, "Start doInBackground(), URL: " + mUrl);
+
+        try {
+            // call start in background
+            mInstallationSession = mDynamicAndroid.startInstallation(mSystemSize, mUserdataSize);
+
+            if (mInstallationSession == null) {
+                Log.e(TAG, "Failed to start installation with requested size: "
+                        + (mSystemSize + mUserdataSize));
+
+                return RESULT_ERROR_IO;
+            }
+
+            initInputStream();
+
+            byte[] bytes = new byte[READ_BUFFER_SIZE];
+
+            int numBytesRead;
+            long minStepToReport = mSystemSize / 100;
+
+            Log.d(TAG, "Start installation loop");
+            while ((numBytesRead = mStream.read(bytes, 0, READ_BUFFER_SIZE)) != -1) {
+                if (isCancelled()) {
+                    break;
+                }
+
+                byte[] writeBuffer = numBytesRead == READ_BUFFER_SIZE
+                        ? bytes : Arrays.copyOf(bytes, numBytesRead);
+
+                if (!mInstallationSession.write(writeBuffer)) {
+                    throw new IOException("Failed write() to DynamicAndroid");
+                }
+
+                mInstalledSize += numBytesRead;
+
+                if (mInstalledSize > mReportedInstalledSize + minStepToReport) {
+                    publishProgress(mInstalledSize);
+                    mReportedInstalledSize = mInstalledSize;
+                }
+            }
+
+            return RESULT_OK;
+
+        } catch (IOException e) {
+            e.printStackTrace();
+            return RESULT_ERROR_IO;
+
+        } catch (InvalidImageUrlException e) {
+            e.printStackTrace();
+            return RESULT_ERROR_INVALID_URL;
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            return RESULT_ERROR_EXCEPTION;
+
+        } finally {
+            close();
+        }
+    }
+
+    @Override
+    protected void onCancelled() {
+        Log.d(TAG, "onCancelled(), URL: " + mUrl);
+
+        close();
+
+        mListener.onCancelled();
+    }
+
+    @Override
+    protected void onPostExecute(Integer result) {
+        Log.d(TAG, "onPostExecute(), URL: " + mUrl + ", result: " + result);
+
+        close();
+
+        mResult = result;
+        mListener.onResult(mResult);
+    }
+
+    @Override
+    protected void onProgressUpdate(Long... values) {
+        long progress = values[0];
+        mListener.onProgressUpdate(progress);
+    }
+
+    private void initInputStream() throws IOException, InvalidImageUrlException {
+        if (URLUtil.isNetworkUrl(mUrl) || URLUtil.isFileUrl(mUrl)) {
+            mStream = new BufferedInputStream(new GZIPInputStream(new URL(mUrl).openStream()));
+        } else {
+            throw new InvalidImageUrlException(
+                    String.format(Locale.US, "Unsupported file source: %s", mUrl));
+        }
+    }
+
+    private void close() {
+        try {
+            if (mStream != null) {
+                mStream.close();
+                mStream = null;
+            }
+        } catch (IOException e) {
+            // ignore
+        }
+    }
+
+    int getResult() {
+        return mResult;
+    }
+
+    boolean commit() {
+        if (mInstallationSession == null) {
+            return false;
+        }
+
+        return mInstallationSession.commit();
+    }
+}
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/VerificationActivity.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/VerificationActivity.java
new file mode 100644
index 0000000..c18c4fe
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/VerificationActivity.java
@@ -0,0 +1,104 @@
+/*
+ * 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.dynandroid;
+
+import static android.content.DynamicAndroidClient.KEY_SYSTEM_SIZE;
+import static android.content.DynamicAndroidClient.KEY_SYSTEM_URL;
+import static android.content.DynamicAndroidClient.KEY_USERDATA_SIZE;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.DynamicAndroidClient;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.util.Log;
+
+
+/**
+ * This Activity starts KeyguardManager and ask the user to confirm
+ * before any installation request. If the device is not protected by
+ * a password, it approves the request by default.
+ */
+public class VerificationActivity extends Activity {
+
+    private static final String TAG = "VerificationActivity";
+
+    private static final int REQUEST_CODE = 1;
+
+    // For install request verification
+    private static String sVerifiedUrl;
+
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
+
+        if (km != null) {
+            String title = getString(R.string.keyguard_title);
+            String description = getString(R.string.keyguard_description);
+            Intent intent = km.createConfirmDeviceCredentialIntent(title, description);
+
+            if (intent == null) {
+                Log.d(TAG, "This device is not protected by a password/pin");
+                startInstallationService();
+                finish();
+            } else {
+                startActivityForResult(intent, REQUEST_CODE);
+            }
+        } else {
+            finish();
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
+            startInstallationService();
+        }
+
+        finish();
+    }
+
+    private void startInstallationService() {
+        // retrieve data from calling intent
+        Intent callingIntent = getIntent();
+
+        String url = callingIntent.getStringExtra(KEY_SYSTEM_URL);
+        long systemSize = callingIntent.getLongExtra(KEY_SYSTEM_SIZE, 0);
+        long userdataSize = callingIntent.getLongExtra(KEY_USERDATA_SIZE, 0);
+
+        sVerifiedUrl = url;
+
+        // start service
+        Intent intent = new Intent(this, DynamicAndroidInstallationService.class);
+        intent.setAction(DynamicAndroidClient.ACTION_START_INSTALL);
+        intent.putExtra(KEY_SYSTEM_URL, url);
+        intent.putExtra(KEY_SYSTEM_SIZE, systemSize);
+        intent.putExtra(KEY_USERDATA_SIZE, userdataSize);
+
+        Log.d(TAG, "Starting Installation Service");
+        startServiceAsUser(intent, UserHandle.SYSTEM);
+    }
+
+    static boolean isVerified(String url) {
+        return sVerifiedUrl != null && sVerifiedUrl.equals(url);
+    }
+}
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index f372fe5..24fa87a 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -15,11 +15,10 @@
  */
 package android.ext.services.notification;
 
-import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.Notification;
 import android.app.Person;
 import android.app.RemoteAction;
+import android.app.RemoteInput;
 import android.content.Context;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
@@ -27,7 +26,9 @@
 import android.os.Process;
 import android.service.notification.NotificationAssistantService;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.LruCache;
+import android.util.Pair;
 import android.view.textclassifier.ConversationAction;
 import android.view.textclassifier.ConversationActions;
 import android.view.textclassifier.TextClassificationContext;
@@ -35,6 +36,8 @@
 import android.view.textclassifier.TextClassifier;
 import android.view.textclassifier.TextClassifierEvent;
 
+import com.android.internal.util.ArrayUtils;
+
 import java.time.Instant;
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
@@ -43,11 +46,13 @@
 import java.util.Collections;
 import java.util.Deque;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
 public class SmartActionsHelper {
     private static final String KEY_ACTION_TYPE = "action_type";
+    private static final String KEY_ACTION_SCORE = "action_score";
     // If a notification has any of these flags set, it's inelgibile for actions being added.
     private static final int FLAG_MASK_INELGIBILE_FOR_ACTIONS =
             Notification.FLAG_ONGOING_EVENT
@@ -58,75 +63,136 @@
 
     private static final List<String> HINTS =
             Collections.singletonList(ConversationActions.Request.HINT_FOR_NOTIFICATION);
+    private static final ConversationActions EMPTY_CONVERSATION_ACTIONS =
+            new ConversationActions(Collections.emptyList(), null);
 
     private Context mContext;
-    @Nullable
     private TextClassifier mTextClassifier;
-    @NonNull
     private AssistantSettings mSettings;
-    private LruCache<String, String> mNotificationKeyToResultIdCache =
-            new LruCache<>(MAX_RESULT_ID_TO_CACHE);
+    private LruCache<String, Session> mSessionCache = new LruCache<>(MAX_RESULT_ID_TO_CACHE);
 
     SmartActionsHelper(Context context, AssistantSettings settings) {
         mContext = context;
         TextClassificationManager textClassificationManager =
                 mContext.getSystemService(TextClassificationManager.class);
-        if (textClassificationManager != null) {
-            mTextClassifier = textClassificationManager.getTextClassifier();
-        }
+        mTextClassifier = textClassificationManager.getTextClassifier();
         mSettings = settings;
     }
 
-    SmartSuggestions suggest(@NonNull NotificationEntry entry) {
+    SmartSuggestions suggest(NotificationEntry entry) {
         // Whenever suggest() is called on a notification, its previous session is ended.
-        mNotificationKeyToResultIdCache.remove(entry.getSbn().getKey());
+        mSessionCache.remove(entry.getSbn().getKey());
 
         boolean eligibleForReplyAdjustment =
                 mSettings.mGenerateReplies && isEligibleForReplyAdjustment(entry);
         boolean eligibleForActionAdjustment =
                 mSettings.mGenerateActions && isEligibleForActionAdjustment(entry);
 
-        List<ConversationAction> conversationActions =
+        ConversationActions conversationActionsResult =
                 suggestConversationActions(
                         entry,
                         eligibleForReplyAdjustment,
                         eligibleForActionAdjustment);
 
-        ArrayList<CharSequence> replies = conversationActions.stream()
-                .map(ConversationAction::getTextReply)
-                .filter(textReply -> !TextUtils.isEmpty(textReply))
-                .collect(Collectors.toCollection(ArrayList::new));
+        String resultId = conversationActionsResult.getId();
+        List<ConversationAction> conversationActions =
+                conversationActionsResult.getConversationActions();
+
+        ArrayList<CharSequence> replies = new ArrayList<>();
+        Map<CharSequence, Float> repliesScore = new ArrayMap<>();
+        for (ConversationAction conversationAction : conversationActions) {
+            CharSequence textReply = conversationAction.getTextReply();
+            if (TextUtils.isEmpty(textReply)) {
+                continue;
+            }
+            replies.add(textReply);
+            repliesScore.put(textReply, conversationAction.getConfidenceScore());
+        }
 
         ArrayList<Notification.Action> actions = conversationActions.stream()
                 .filter(conversationAction -> conversationAction.getAction() != null)
-                .map(action -> createNotificationAction(action.getAction(), action.getType()))
+                .map(action -> createNotificationAction(
+                        action.getAction(), action.getType(), action.getConfidenceScore()))
                 .collect(Collectors.toCollection(ArrayList::new));
+
+        // Start a new session for logging if necessary.
+        if (!TextUtils.isEmpty(resultId)
+                && !conversationActions.isEmpty()
+                && suggestionsMightBeUsedInNotification(
+                entry, !actions.isEmpty(), !replies.isEmpty())) {
+            mSessionCache.put(entry.getSbn().getKey(), new Session(resultId, repliesScore));
+        }
+
         return new SmartSuggestions(replies, actions);
     }
 
     /**
+     * Returns whether the suggestion might be used in the notifications in SysUI.
+     * <p>
+     * Currently, NAS has no idea if suggestions will actually be used in the notification, and thus
+     * this function tries to make a heuristic. This function tries to optimize the precision,
+     * that means when it is unsure, it will return false. The objective is to avoid false positive,
+     * which could pollute the log and CTR as we are logging click rate of suggestions that could
+     * be never visible to users. On the other hand, it is fine to have false negative because
+     * it would be just like sampling.
+     */
+    private boolean suggestionsMightBeUsedInNotification(
+            NotificationEntry notificationEntry, boolean hasSmartAction, boolean hasSmartReply) {
+        Notification notification = notificationEntry.getNotification();
+        boolean hasAppGeneratedContextualActions = !notification.getContextualActions().isEmpty();
+
+        Pair<RemoteInput, Notification.Action> freeformRemoteInputAndAction =
+                notification.findRemoteInputActionPair(/* requiresFreeform */ true);
+        boolean hasAppGeneratedReplies = false;
+        boolean allowGeneratedReplies = false;
+        if (freeformRemoteInputAndAction != null) {
+            RemoteInput freeformRemoteInput = freeformRemoteInputAndAction.first;
+            Notification.Action actionWithFreeformRemoteInput = freeformRemoteInputAndAction.second;
+            hasAppGeneratedReplies = !ArrayUtils.isEmpty(freeformRemoteInput.getChoices());
+            allowGeneratedReplies = actionWithFreeformRemoteInput.getAllowGeneratedReplies();
+        }
+
+        if (hasAppGeneratedReplies || hasAppGeneratedContextualActions) {
+            return false;
+        }
+        return hasSmartAction && notification.getAllowSystemGeneratedContextualActions()
+                || hasSmartReply && allowGeneratedReplies;
+    }
+
+    private void reportActionsGenerated(
+            String resultId, List<ConversationAction> conversationActions) {
+        if (TextUtils.isEmpty(resultId)) {
+            return;
+        }
+        TextClassifierEvent textClassifierEvent =
+                createTextClassifierEventBuilder(
+                        TextClassifierEvent.TYPE_ACTIONS_GENERATED, resultId)
+                        .setEntityTypes(conversationActions.stream()
+                                .map(ConversationAction::getType)
+                                .toArray(String[]::new))
+                        .build();
+        mTextClassifier.onTextClassifierEvent(textClassifierEvent);
+    }
+
+    /**
      * Adds action adjustments based on the notification contents.
      */
-    @NonNull
-    private List<ConversationAction> suggestConversationActions(
-            @NonNull NotificationEntry entry,
+    private ConversationActions suggestConversationActions(
+            NotificationEntry entry,
             boolean includeReplies,
             boolean includeActions) {
         if (!includeReplies && !includeActions) {
-            return Collections.emptyList();
-        }
-        if (mTextClassifier == null) {
-            return Collections.emptyList();
+            return EMPTY_CONVERSATION_ACTIONS;
         }
         List<ConversationActions.Message> messages = extractMessages(entry.getNotification());
         if (messages.isEmpty()) {
-            return Collections.emptyList();
+            return EMPTY_CONVERSATION_ACTIONS;
         }
         // Do not generate smart actions if the last message is from the local user.
         ConversationActions.Message lastMessage = messages.get(messages.size() - 1);
         if (arePersonsEqual(
                 ConversationActions.Message.PERSON_USER_SELF, lastMessage.getAuthor())) {
-            return Collections.emptyList();
+            return EMPTY_CONVERSATION_ACTIONS;
         }
 
         TextClassifier.EntityConfig.Builder typeConfigBuilder =
@@ -146,25 +212,20 @@
                         .setHints(HINTS)
                         .setTypeConfig(typeConfigBuilder.build())
                         .build();
-
-        ConversationActions conversationActionsResult =
+        ConversationActions conversationActions =
                 mTextClassifier.suggestConversationActions(request);
-
-        String resultId = conversationActionsResult.getId();
-        if (!TextUtils.isEmpty(resultId)
-                && !conversationActionsResult.getConversationActions().isEmpty()) {
-            mNotificationKeyToResultIdCache.put(entry.getSbn().getKey(), resultId);
-        }
-        return conversationActionsResult.getConversationActions();
+        reportActionsGenerated(
+                conversationActions.getId(), conversationActions.getConversationActions());
+        return conversationActions;
     }
 
-    void onNotificationExpansionChanged(@NonNull NotificationEntry entry, boolean isUserAction,
+    void onNotificationExpansionChanged(NotificationEntry entry, boolean isUserAction,
             boolean isExpanded) {
         if (!isExpanded) {
             return;
         }
-        String resultId = mNotificationKeyToResultIdCache.get(entry.getSbn().getKey());
-        if (resultId == null) {
+        Session session = mSessionCache.get(entry.getSbn().getKey());
+        if (session == null) {
             return;
         }
         // Only report if this is the first time the user sees these suggestions.
@@ -173,56 +234,50 @@
         }
         entry.setShowActionEventLogged();
         TextClassifierEvent textClassifierEvent =
-                createTextClassifierEventBuilder(TextClassifierEvent.TYPE_ACTIONS_SHOWN,
-                        resultId)
+                createTextClassifierEventBuilder(
+                        TextClassifierEvent.TYPE_ACTIONS_SHOWN, session.resultId)
                         .build();
         // TODO: If possible, report which replies / actions are actually seen by user.
         mTextClassifier.onTextClassifierEvent(textClassifierEvent);
     }
 
-    void onNotificationDirectReplied(@NonNull String key) {
-        if (mTextClassifier == null) {
-            return;
-        }
-        String resultId = mNotificationKeyToResultIdCache.get(key);
-        if (resultId == null) {
+    void onNotificationDirectReplied(String key) {
+        Session session = mSessionCache.get(key);
+        if (session == null) {
             return;
         }
         TextClassifierEvent textClassifierEvent =
-                createTextClassifierEventBuilder(TextClassifierEvent.TYPE_MANUAL_REPLY, resultId)
+                createTextClassifierEventBuilder(
+                        TextClassifierEvent.TYPE_MANUAL_REPLY, session.resultId)
                         .build();
         mTextClassifier.onTextClassifierEvent(textClassifierEvent);
     }
 
-    void onSuggestedReplySent(@NonNull String key, @NonNull CharSequence reply,
+    void onSuggestedReplySent(String key, CharSequence reply,
             @NotificationAssistantService.Source int source) {
-        if (mTextClassifier == null) {
-            return;
-        }
         if (source != NotificationAssistantService.SOURCE_FROM_ASSISTANT) {
             return;
         }
-        String resultId = mNotificationKeyToResultIdCache.get(key);
-        if (resultId == null) {
+        Session session = mSessionCache.get(key);
+        if (session == null) {
             return;
         }
         TextClassifierEvent textClassifierEvent =
-                createTextClassifierEventBuilder(TextClassifierEvent.TYPE_SMART_ACTION, resultId)
+                createTextClassifierEventBuilder(
+                        TextClassifierEvent.TYPE_SMART_ACTION, session.resultId)
                         .setEntityTypes(ConversationAction.TYPE_TEXT_REPLY)
+                        .setScore(session.repliesScores.getOrDefault(reply, 0f))
                         .build();
         mTextClassifier.onTextClassifierEvent(textClassifierEvent);
     }
 
-    void onActionClicked(@NonNull String key, @NonNull Notification.Action action,
+    void onActionClicked(String key, Notification.Action action,
             @NotificationAssistantService.Source int source) {
-        if (mTextClassifier == null) {
-            return;
-        }
         if (source != NotificationAssistantService.SOURCE_FROM_ASSISTANT) {
             return;
         }
-        String resultId = mNotificationKeyToResultIdCache.get(key);
-        if (resultId == null) {
+        Session session = mSessionCache.get(key);
+        if (session == null) {
             return;
         }
         String actionType = action.getExtras().getString(KEY_ACTION_TYPE);
@@ -230,28 +285,32 @@
             return;
         }
         TextClassifierEvent textClassifierEvent =
-                createTextClassifierEventBuilder(TextClassifierEvent.TYPE_SMART_ACTION, resultId)
+                createTextClassifierEventBuilder(
+                        TextClassifierEvent.TYPE_SMART_ACTION, session.resultId)
                         .setEntityTypes(actionType)
                         .build();
         mTextClassifier.onTextClassifierEvent(textClassifierEvent);
     }
 
     private Notification.Action createNotificationAction(
-            RemoteAction remoteAction, String actionType) {
+            RemoteAction remoteAction, String actionType, float score) {
         Icon icon = remoteAction.shouldShowIcon()
                 ? remoteAction.getIcon()
                 : Icon.createWithResource(mContext, com.android.internal.R.drawable.ic_action_open);
+        Bundle extras = new Bundle();
+        extras.putString(KEY_ACTION_TYPE, actionType);
+        extras.putFloat(KEY_ACTION_SCORE, score);
         return new Notification.Action.Builder(
                 icon,
                 remoteAction.getTitle(),
                 remoteAction.getActionIntent())
                 .setContextual(true)
-                .addExtras(Bundle.forPair(KEY_ACTION_TYPE, actionType))
+                .addExtras(extras)
                 .build();
     }
 
     private TextClassifierEvent.Builder createTextClassifierEventBuilder(
-            int eventType, @NonNull String resultId) {
+            int eventType, String resultId) {
         return new TextClassifierEvent.Builder(
                 TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS, eventType)
                 .setEventTime(System.currentTimeMillis())
@@ -269,7 +328,7 @@
      * to fundamental phone functionality where any error would result in a very negative user
      * experience.
      */
-    private boolean isEligibleForActionAdjustment(@NonNull NotificationEntry entry) {
+    private boolean isEligibleForActionAdjustment(NotificationEntry entry) {
         Notification notification = entry.getNotification();
         String pkg = entry.getSbn().getPackageName();
         if (!Process.myUserHandle().equals(entry.getSbn().getUser())) {
@@ -285,7 +344,7 @@
         return entry.isMessaging();
     }
 
-    private boolean isEligibleForReplyAdjustment(@NonNull NotificationEntry entry) {
+    private boolean isEligibleForReplyAdjustment(NotificationEntry entry) {
         if (!Process.myUserHandle().equals(entry.getSbn().getUser())) {
             return false;
         }
@@ -306,8 +365,7 @@
     }
 
     /** Returns the text most salient for action extraction in a notification. */
-    @Nullable
-    private List<ConversationActions.Message> extractMessages(@NonNull Notification notification) {
+    private List<ConversationActions.Message> extractMessages(Notification notification) {
         Parcelable[] messages = notification.extras.getParcelableArray(Notification.EXTRA_MESSAGES);
         if (messages == null || messages.length == 0) {
             return Collections.singletonList(new ConversationActions.Message.Builder(
@@ -343,7 +401,7 @@
         return new ArrayList<>(extractMessages);
     }
 
-    private static boolean arePersonsEqual(@NonNull Person left, @NonNull Person right) {
+    private static boolean arePersonsEqual(Person left, Person right) {
         return Objects.equals(left.getKey(), right.getKey())
                 && Objects.equals(left.getName(), right.getName())
                 && Objects.equals(left.getUri(), right.getUri());
@@ -359,4 +417,14 @@
             this.actions = actions;
         }
     }
+
+    private static class Session {
+        public final String resultId;
+        public final Map<CharSequence, Float> repliesScores;
+
+        Session(String resultId, Map<CharSequence, Float> repliesScores) {
+            this.resultId = resultId;
+            this.repliesScores = repliesScores;
+        }
+    }
 }
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
index 74c20fc..d0b6d00 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
@@ -19,7 +19,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -53,8 +55,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 import java.time.Instant;
@@ -71,9 +73,12 @@
 public class SmartActionsHelperTest {
     private static final String NOTIFICATION_KEY = "key";
     private static final String RESULT_ID = "id";
+    private static final float SCORE = 0.7f;
+    private static final CharSequence SMART_REPLY = "Home";
     private static final ConversationAction REPLY_ACTION =
             new ConversationAction.Builder(ConversationAction.TYPE_TEXT_REPLY)
-                    .setTextReply("Home")
+                    .setTextReply(SMART_REPLY)
+                    .setConfidenceScore(SCORE)
                     .build();
     private static final String MESSAGE = "Where are you?";
 
@@ -197,8 +202,16 @@
 
         List<ConversationActions.Message> messages =
                 runSuggestAndCaptureRequest().getConversation();
+
         assertThat(messages).hasSize(1);
         MessageSubject.assertThat(messages.get(0)).hasText(MESSAGE);
+        ArgumentCaptor<TextClassifierEvent> argumentCaptor =
+                ArgumentCaptor.forClass(TextClassifierEvent.class);
+        verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
+        TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
+        assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_ACTIONS_GENERATED);
+        assertThat(textClassifierEvent.getEntityTypes()).asList()
+                .containsExactly(ConversationAction.TYPE_TEXT_REPLY);
     }
 
     @Test
@@ -249,6 +262,14 @@
         MessageSubject.assertThat(fourthMessage).hasPerson(userB);
         MessageSubject.assertThat(fourthMessage)
                 .hasReferenceTime(createZonedDateTimeFromMsUtc(4000));
+
+        ArgumentCaptor<TextClassifierEvent> argumentCaptor =
+                ArgumentCaptor.forClass(TextClassifierEvent.class);
+        verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
+        TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
+        assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_ACTIONS_GENERATED);
+        assertThat(textClassifierEvent.getEntityTypes()).asList()
+                .containsExactly(ConversationAction.TYPE_TEXT_REPLY);
     }
 
     @Test
@@ -299,13 +320,15 @@
 
         mSmartActionsHelper.suggest(createNotificationEntry());
         mSmartActionsHelper.onSuggestedReplySent(
-                NOTIFICATION_KEY, MESSAGE, NotificationAssistantService.SOURCE_FROM_ASSISTANT);
+                NOTIFICATION_KEY, SMART_REPLY, NotificationAssistantService.SOURCE_FROM_ASSISTANT);
 
         ArgumentCaptor<TextClassifierEvent> argumentCaptor =
                 ArgumentCaptor.forClass(TextClassifierEvent.class);
-        verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
-        TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
-        assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_SMART_ACTION);
+        verify(mTextClassifier, times(2)).onTextClassifierEvent(argumentCaptor.capture());
+        List<TextClassifierEvent> events = argumentCaptor.getAllValues();
+        assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED);
+        assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_SMART_ACTION);
+        assertThat(events.get(1).getScore()).isEqualTo(SCORE);
     }
 
     @Test
@@ -317,24 +340,22 @@
         mSmartActionsHelper.onSuggestedReplySent(
                 "something_else", MESSAGE, NotificationAssistantService.SOURCE_FROM_ASSISTANT);
 
-        verify(mTextClassifier, never())
-                .onTextClassifierEvent(Mockito.any(TextClassifierEvent.class));
+        verify(mTextClassifier, never()).onTextClassifierEvent(
+                argThat(new TextClassifierEventMatcher(TextClassifierEvent.TYPE_SMART_ACTION)));
     }
 
     @Test
     public void testOnSuggestedReplySent_missingResultId() {
         when(mTextClassifier.suggestConversationActions(any(ConversationActions.Request.class)))
-                .thenReturn(new ConversationActions(Collections.emptyList(), null));
-
+                .thenReturn(new ConversationActions(Collections.singletonList(REPLY_ACTION), null));
         Notification notification = createMessageNotification();
         when(mStatusBarNotification.getNotification()).thenReturn(notification);
 
         mSmartActionsHelper.suggest(createNotificationEntry());
         mSmartActionsHelper.onSuggestedReplySent(
-                "something_else", MESSAGE, NotificationAssistantService.SOURCE_FROM_ASSISTANT);
+                NOTIFICATION_KEY, SMART_REPLY, NotificationAssistantService.SOURCE_FROM_ASSISTANT);
 
-        verify(mTextClassifier, never())
-                .onTextClassifierEvent(Mockito.any(TextClassifierEvent.class));
+        verify(mTextClassifier, never()).onTextClassifierEvent(any(TextClassifierEvent.class));
     }
 
     @Test
@@ -347,9 +368,10 @@
 
         ArgumentCaptor<TextClassifierEvent> argumentCaptor =
                 ArgumentCaptor.forClass(TextClassifierEvent.class);
-        verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
-        TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
-        assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_MANUAL_REPLY);
+        verify(mTextClassifier, times(2)).onTextClassifierEvent(argumentCaptor.capture());
+        List<TextClassifierEvent> events = argumentCaptor.getAllValues();
+        assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED);
+        assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_MANUAL_REPLY);
     }
 
     @Test
@@ -362,9 +384,10 @@
 
         ArgumentCaptor<TextClassifierEvent> argumentCaptor =
                 ArgumentCaptor.forClass(TextClassifierEvent.class);
-        verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
-        TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
-        assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_ACTIONS_SHOWN);
+        verify(mTextClassifier, times(2)).onTextClassifierEvent(argumentCaptor.capture());
+        List<TextClassifierEvent> events = argumentCaptor.getAllValues();
+        assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED);
+        assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_ACTIONS_SHOWN);
     }
 
     @Test
@@ -376,7 +399,7 @@
         mSmartActionsHelper.onNotificationExpansionChanged(createNotificationEntry(), false, false);
 
         verify(mTextClassifier, never()).onTextClassifierEvent(
-                Mockito.any(TextClassifierEvent.class));
+                argThat(new TextClassifierEventMatcher(TextClassifierEvent.TYPE_ACTIONS_SHOWN)));
     }
 
     @Test
@@ -389,9 +412,10 @@
 
         ArgumentCaptor<TextClassifierEvent> argumentCaptor =
                 ArgumentCaptor.forClass(TextClassifierEvent.class);
-        verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
-        TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
-        assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_ACTIONS_SHOWN);
+        verify(mTextClassifier, times(2)).onTextClassifierEvent(argumentCaptor.capture());
+        List<TextClassifierEvent> events = argumentCaptor.getAllValues();
+        assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED);
+        assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_ACTIONS_SHOWN);
     }
 
     private ZonedDateTime createZonedDateTimeFromMsUtc(long msUtc) {
@@ -490,4 +514,21 @@
             return assertAbout(FACTORY).that(message);
         }
     }
+
+    private final class TextClassifierEventMatcher implements ArgumentMatcher<TextClassifierEvent> {
+
+        private int mType;
+
+        private TextClassifierEventMatcher(int type) {
+            mType = type;
+        }
+
+        @Override
+        public boolean matches(TextClassifierEvent textClassifierEvent) {
+            if (textClassifierEvent == null) {
+                return false;
+            }
+            return mType == textClassifierEvent.getEventType();
+        }
+    }
 }
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 36ee813..caa928f 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -21,6 +21,7 @@
         "SettingsLibActionButtonsPreference",
         "SettingsLibEntityHeaderWidgets",
         "SettingsLibBarChartPreference",
+        "SettingsLibProgressBar",
     ],
 
     // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
diff --git a/packages/SettingsLib/ProgressBar/Android.bp b/packages/SettingsLib/ProgressBar/Android.bp
new file mode 100644
index 0000000..eae21d8
--- /dev/null
+++ b/packages/SettingsLib/ProgressBar/Android.bp
@@ -0,0 +1,9 @@
+android_library {
+    name: "SettingsLibProgressBar",
+
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/ProgressBar/AndroidManifest.xml b/packages/SettingsLib/ProgressBar/AndroidManifest.xml
new file mode 100644
index 0000000..256b8f3
--- /dev/null
+++ b/packages/SettingsLib/ProgressBar/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.settingslib.widget">
+
+    <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/ProgressBar/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/packages/SettingsLib/ProgressBar/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
new file mode 100644
index 0000000..2b7535a
--- /dev/null
+++ b/packages/SettingsLib/ProgressBar/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<!-- Variant of progress_indeterminate_horizontal_material in frameworks/base/core/res, which
+     draws the whole height of the progress bar instead having blank space above and below the
+     bar. -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+                 android:drawable="@drawable/vector_drawable_progress_indeterminate_horizontal_trimmed" >
+    <target
+        android:name="rect2_grp"
+        android:animation="@*android:anim/progress_indeterminate_horizontal_rect2" />
+    <target
+        android:name="rect1_grp"
+        android:animation="@*android:anim/progress_indeterminate_horizontal_rect1" />
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/ProgressBar/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml b/packages/SettingsLib/ProgressBar/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml
new file mode 100644
index 0000000..2f604d0
--- /dev/null
+++ b/packages/SettingsLib/ProgressBar/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<!-- Variant of vector_drawable_progress_indeterminate_horizontal in frameworks/base/core/res, which
+     draws the whole height of the progress bar instead having blank space above and below the
+     bar. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="10dp"
+        android:width="360dp"
+        android:viewportHeight="10"
+        android:viewportWidth="360" >
+    <group
+        android:name="progress_group"
+        android:translateX="180"
+        android:translateY="5" >
+        <path
+            android:name="background_track"
+            android:pathData="M -180.0,-5.0 l 360.0,0 l 0,10.0 l -360.0,0 Z"
+            android:fillColor="?android:attr/colorControlActivated"
+            android:fillAlpha="?android:attr/disabledAlpha"/>
+        <group
+            android:name="rect2_grp"
+            android:translateX="-197.60001"
+            android:scaleX="0.1" >
+            <path
+                android:name="rect2"
+                android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z"
+                android:fillColor="?android:attr/colorControlActivated" />
+        </group>
+        <group
+            android:name="rect1_grp"
+            android:translateX="-522.59998"
+            android:scaleX="0.1" >
+            <path
+                android:name="rect1"
+                android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z"
+                android:fillColor="?android:attr/colorControlActivated" />
+        </group>
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/ProgressBar/res/layout/progress_header.xml b/packages/SettingsLib/ProgressBar/res/layout/progress_header.xml
new file mode 100644
index 0000000..268858b
--- /dev/null
+++ b/packages/SettingsLib/ProgressBar/res/layout/progress_header.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2015 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.
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="3dp">
+    <View
+        android:id="@+id/progress_bar_background"
+        style="@style/TrimmedHorizontalProgressBar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="?android:attr/colorSecondary" />
+    <ProgressBar
+        android:id="@+id/progress_bar_animation"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        style="@style/TrimmedHorizontalProgressBar"
+        android:indeterminate="true" />
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/ProgressBar/res/values/styles.xml b/packages/SettingsLib/ProgressBar/res/values/styles.xml
new file mode 100644
index 0000000..5f57c1d
--- /dev/null
+++ b/packages/SettingsLib/ProgressBar/res/values/styles.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+
+    <style name="TrimmedHorizontalProgressBar"
+           parent="android:Widget.Material.ProgressBar.Horizontal">
+        <item name="android:indeterminateDrawable">
+            @drawable/progress_indeterminate_horizontal_material_trimmed
+        </item>
+        <item name="android:minHeight">3dp</item>
+        <item name="android:maxHeight">3dp</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
index 8c309ff..8d24eab 100644
--- a/packages/SettingsLib/common.mk
+++ b/packages/SettingsLib/common.mk
@@ -31,3 +31,4 @@
     androidx.legacy_legacy-preference-v14 \
     SettingsLib
 
+LOCAL_RESOURCE_DIR += $(call my-dir)/res
diff --git a/packages/SettingsLib/res/drawable/ic_system_update.xml b/packages/SettingsLib/res/drawable/ic_system_update.xml
new file mode 100644
index 0000000..3325fdd
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_system_update.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM16,12.5l-4,4l-4,-4l1.41,-1.41L11,12.67V8.5V8h2v0.5v4.17l1.59,-1.59L16,12.5z"/>
+</vector>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index d644833..f5d58d8 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -337,6 +337,9 @@
     <string name="data_usage_uninstalled_apps">Removed apps</string>
     <!-- Title of data usage item that represents all uninstalled applications or removed users. [CHAR LIMIT=48] -->
     <string name="data_usage_uninstalled_apps_users">Removed apps and users</string>
+    <!-- Title of data usage item that represents system updates (OTAs). [CHAR LIMIT=48] -->
+    <string name="data_usage_ota">System updates</string>
+
 
     <!-- Tethering controls, item title to go into the tethering settings -->
     <!-- Tethering controls, item title to go into the tethering settings when only USB tethering is available [CHAR LIMIT=25]-->
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index a1bf936..c1933fd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -73,9 +73,8 @@
                         BluetoothProfile.STATE_CONNECTED);
                 device.refresh();
             }
-
-            mProfileManager.callServiceConnectedListeners();
             mIsProfileReady=true;
+            mProfileManager.callServiceConnectedListeners();
         }
 
         public void onServiceDisconnected(int profile) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
index 305a1ff..dd6d563 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
@@ -40,6 +40,7 @@
 import com.android.settingslib.NetworkPolicyEditor;
 
 import java.time.ZonedDateTime;
+import java.util.ArrayList;
 import java.util.Iterator;
 
 /**
@@ -52,6 +53,7 @@
     protected final int mNetworkType;
     private final NetworkPolicy mPolicy;
     private final NetworkTemplate mNetworkTemplate;
+    private final ArrayList<Long> mCycles;
     @VisibleForTesting
     final INetworkStatsService mNetworkStatsService;
 
@@ -60,6 +62,7 @@
         mSubId = builder.mSubId;
         mNetworkType = builder.mNetworkType;
         mNetworkTemplate = builder.mNetworkTemplate;
+        mCycles = builder.mCycles;
         mNetworkStatsManager = (NetworkStatsManager)
             builder.mContext.getSystemService(Context.NETWORK_STATS_SERVICE);
         mNetworkStatsService = INetworkStatsService.Stub.asInterface(
@@ -77,7 +80,9 @@
     }
 
     public D loadInBackground() {
-        if (mPolicy == null) {
+        if (mCycles != null && mCycles.size() > 1) {
+            loadDataForSpecificCycles();
+        } else if (mPolicy == null) {
             loadFourWeeksData();
         } else {
             loadPolicyData();
@@ -132,6 +137,17 @@
     }
 
     @VisibleForTesting
+    void loadDataForSpecificCycles() {
+        long cycleEnd = mCycles.get(0);
+        final int lastCycleIndex = mCycles.size() - 1;
+        for (int i = 1; i <= lastCycleIndex; i++) {
+            final long cycleStart = mCycles.get(i);
+            recordUsage(cycleStart, cycleEnd);
+            cycleEnd = cycleStart;
+        }
+    }
+
+    @VisibleForTesting
     abstract void recordUsage(long start, long end);
 
     abstract D getCycleUsage();
@@ -157,11 +173,17 @@
         return bytes;
     }
 
+    @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+    public ArrayList<Long> getCycles() {
+        return mCycles;
+    }
+
     public static abstract class Builder<T extends NetworkCycleDataLoader> {
         private final Context mContext;
         private String mSubId;
         private int mNetworkType;
         private NetworkTemplate mNetworkTemplate;
+        private ArrayList<Long> mCycles;
 
         public Builder (Context context) {
             mContext = context;
@@ -178,6 +200,16 @@
             return this;
         }
 
+        /**
+         * Sets the network cycles to be used to query the usage data.
+         * @param cycles the time slots for the network cycle to be used to query the network usage.
+         * @return the builder
+         */
+        public Builder<T> setCycles(ArrayList<Long> cycles) {
+            mCycles = cycles;
+            return this;
+        }
+
         public abstract T build();
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
index c14f558..e351615 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
@@ -28,6 +28,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.ConnectivityManager;
 import android.net.TrafficStats;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -111,7 +112,7 @@
 
         // handle special case labels
         switch (uid) {
-            case android.os.Process.SYSTEM_UID:
+            case Process.SYSTEM_UID:
                 detail.label = res.getString(R.string.process_kernel_label);
                 detail.icon = pm.getDefaultActivityIcon();
                 return detail;
@@ -127,6 +128,10 @@
                 detail.label = res.getString(Utils.getTetheringLabel(cm));
                 detail.icon = pm.getDefaultActivityIcon();
                 return detail;
+            case Process.OTA_UPDATE_UID:
+                detail.label = res.getString(R.string.data_usage_ota);
+                detail.icon = mContext.getDrawable(R.drawable.ic_system_update);
+                return detail;
         }
 
         final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index b9a5f23..8ea0f4b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -53,6 +53,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.internal.util.CollectionUtils;
 import com.android.settingslib.R;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -566,9 +567,6 @@
 
                 AccessPoint accessPoint =
                         getCachedOrCreate(entry.getValue(), cachedAccessPoints);
-                if (mLastInfo != null && mLastNetworkInfo != null) {
-                    accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
-                }
 
                 // Update the matching config if there is one, to populate saved network info
                 accessPoint.update(configsByKey.get(entry.getKey()));
@@ -578,68 +576,20 @@
 
             List<ScanResult> cachedScanResults = new ArrayList<>(mScanResultCache.values());
 
-            // Add a unique Passpoint R1 AccessPoint for each Passpoint profile's FQDN.
-            List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> passpointConfigsAndScans =
-                    mWifiManager.getAllMatchingWifiConfigs(cachedScanResults);
-            Set<String> seenFQDNs = new ArraySet<>();
-            for (Pair<WifiConfiguration,
-                    Map<Integer, List<ScanResult>>> pairing : passpointConfigsAndScans) {
-                WifiConfiguration config = pairing.first;
+            // Add a unique Passpoint AccessPoint for each Passpoint profile's FQDN.
+            accessPoints.addAll(updatePasspointAccessPoints(
+                    mWifiManager.getAllMatchingWifiConfigs(cachedScanResults), cachedAccessPoints));
 
-                List<ScanResult> scanResults = new ArrayList<>();
+            // Add OSU Provider AccessPoints
+            accessPoints.addAll(updateOsuAccessPoints(
+                    mWifiManager.getMatchingOsuProviders(cachedScanResults), cachedAccessPoints));
 
-                List<ScanResult> homeScans =
-                        pairing.second.get(WifiManager.PASSPOINT_HOME_NETWORK);
-                List<ScanResult> roamingScans =
-                        pairing.second.get(WifiManager.PASSPOINT_ROAMING_NETWORK);
-
-                if (homeScans == null) {
-                    homeScans = new ArrayList<>();
-                }
-                if (roamingScans == null) {
-                    roamingScans = new ArrayList<>();
-                }
-
-                // TODO(b/118705403): Differentiate home network vs roaming network for summary info
-                if (!homeScans.isEmpty()) {
-                    scanResults.addAll(homeScans);
-                } else {
-                    scanResults.addAll(roamingScans);
-                }
-
-                if (seenFQDNs.add(config.FQDN)) {
-                    int bestRssi = Integer.MIN_VALUE;
-                    for (ScanResult result : scanResults) {
-                        if (result.level >= bestRssi) {
-                            bestRssi = result.level;
-                            config.SSID = AccessPoint.convertToQuotedString(result.SSID);
-                        }
-                    }
-
-                    AccessPoint accessPoint =
-                            getCachedOrCreatePasspoint(scanResults, cachedAccessPoints, config);
-                    accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
-                    accessPoints.add(accessPoint);
+            if (mLastInfo != null && mLastNetworkInfo != null) {
+                for (AccessPoint ap : accessPoints) {
+                    ap.update(connectionConfig, mLastInfo, mLastNetworkInfo);
                 }
             }
 
-            // Add Passpoint OSU Provider AccessPoints
-            Map<OsuProvider, List<ScanResult>> providersAndScans =
-                    mWifiManager.getMatchingOsuProviders(cachedScanResults);
-            Set<OsuProvider> alreadyProvisioned = mWifiManager
-                    .getMatchingPasspointConfigsForOsuProviders(
-                            providersAndScans.keySet()).keySet();
-            for (OsuProvider provider : providersAndScans.keySet()) {
-                if (!alreadyProvisioned.contains(provider)) {
-                    AccessPoint accessPointOsu =
-                            getCachedOrCreateOsu(providersAndScans.get(provider),
-                                    cachedAccessPoints, provider);
-                    accessPointOsu.update(connectionConfig, mLastInfo, mLastNetworkInfo);
-                    accessPoints.add(accessPointOsu);
-                }
-            }
-
-
             // If there were no scan results, create an AP for the currently connected network (if
             // it exists).
             if (accessPoints.isEmpty() && connectionConfig != null) {
@@ -686,7 +636,67 @@
     }
 
     @VisibleForTesting
-    AccessPoint getCachedOrCreate(
+    List<AccessPoint> updatePasspointAccessPoints(
+            List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> passpointConfigsAndScans,
+            List<AccessPoint> accessPointCache) {
+        List<AccessPoint> accessPoints = new ArrayList<>();
+
+        Set<String> seenFQDNs = new ArraySet<>();
+        for (Pair<WifiConfiguration,
+                Map<Integer, List<ScanResult>>> pairing : passpointConfigsAndScans) {
+            WifiConfiguration config = pairing.first;
+            if (seenFQDNs.add(config.FQDN)) {
+                List<ScanResult> apScanResults = new ArrayList<>();
+
+                List<ScanResult> homeScans =
+                        pairing.second.get(WifiManager.PASSPOINT_HOME_NETWORK);
+                List<ScanResult> roamingScans =
+                        pairing.second.get(WifiManager.PASSPOINT_ROAMING_NETWORK);
+
+                // TODO(b/118705403): Differentiate home network vs roaming network for summary info
+                if (!CollectionUtils.isEmpty(homeScans)) {
+                    apScanResults.addAll(homeScans);
+                } else if (!CollectionUtils.isEmpty(roamingScans)) {
+                    apScanResults.addAll(roamingScans);
+                }
+
+                int bestRssi = Integer.MIN_VALUE;
+                for (ScanResult result : apScanResults) {
+                    if (result.level >= bestRssi) {
+                        bestRssi = result.level;
+                        config.SSID = AccessPoint.convertToQuotedString(result.SSID);
+                    }
+                }
+
+                AccessPoint accessPoint =
+                        getCachedOrCreatePasspoint(apScanResults, accessPointCache, config);
+                accessPoints.add(accessPoint);
+            }
+        }
+        return accessPoints;
+    }
+
+    @VisibleForTesting
+    List<AccessPoint> updateOsuAccessPoints(
+            Map<OsuProvider, List<ScanResult>> providersAndScans,
+            List<AccessPoint> accessPointCache) {
+        List<AccessPoint> accessPoints = new ArrayList<>();
+
+        Set<OsuProvider> alreadyProvisioned = mWifiManager
+                .getMatchingPasspointConfigsForOsuProviders(
+                        providersAndScans.keySet()).keySet();
+        for (OsuProvider provider : providersAndScans.keySet()) {
+            if (!alreadyProvisioned.contains(provider)) {
+                AccessPoint accessPointOsu =
+                        getCachedOrCreateOsu(providersAndScans.get(provider),
+                                accessPointCache, provider);
+                accessPoints.add(accessPointOsu);
+            }
+        }
+        return accessPoints;
+    }
+
+    private AccessPoint getCachedOrCreate(
             List<ScanResult> scanResults,
             List<AccessPoint> cache) {
         AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(scanResults.get(0)));
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 42eb0b9..7d22788 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -48,11 +49,15 @@
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiNetworkScoreCache;
 import android.net.wifi.WifiSsid;
+import android.net.wifi.hotspot2.OsuProvider;
+import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.SystemClock;
 import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Pair;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -74,7 +79,10 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -94,6 +102,8 @@
     private static final int RSSI_1 = -30;
     private static final byte SCORE_1 = 10;
     private static final int BADGE_1 = AccessPoint.Speed.MODERATE;
+    private static final String FQDN_1 = "fqdn1";
+    private static final String PROVIDER_FRIENDLY_NAME_1 = "providerFriendlyName1";
 
     private static final String SSID_2 = "ssid2";
     private static final String BSSID_2 = "AA:AA:AA:AA:AA:AA";
@@ -102,6 +112,8 @@
     private static final int RSSI_2 = -30;
     private static final byte SCORE_2 = 15;
     private static final int BADGE_2 = AccessPoint.Speed.FAST;
+    private static final String FQDN_2 = "fqdn2";
+    private static final String PROVIDER_FRIENDLY_NAME_2 = "providerFriendlyName2";
 
     private static final String SSID_3 = "ssid3";
     private static final String BSSID_3 = "CC:00:00:00:00:00";
@@ -271,6 +283,61 @@
                 0 /* microsecond timestamp */);
     }
 
+    private static WifiConfiguration buildPasspointConfiguration(String fqdn, String friendlyName) {
+        WifiConfiguration config = spy(new WifiConfiguration());
+        config.FQDN = fqdn;
+        config.providerFriendlyName = friendlyName;
+        when(config.isPasspoint()).thenReturn(true);
+        return config;
+    }
+
+    private List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>>
+            createPasspointMatchingWifiConfigsWithDuplicates() {
+        List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> matchingList =
+                new ArrayList<>();
+        Map<Integer, List<ScanResult>> mapping = new HashMap<>();
+
+        mapping.put(WifiManager.PASSPOINT_HOME_NETWORK, Arrays.asList(buildScanResult1()));
+
+        WifiConfiguration passpointConfig1 =
+                buildPasspointConfiguration(FQDN_1, PROVIDER_FRIENDLY_NAME_1);
+        WifiConfiguration passpointConfig2 =
+                buildPasspointConfiguration(FQDN_2, PROVIDER_FRIENDLY_NAME_2);
+
+        matchingList.add(new Pair(passpointConfig1, mapping));
+        matchingList.add(new Pair(passpointConfig1, mapping));
+        matchingList.add(new Pair(passpointConfig2, mapping));
+        matchingList.add(new Pair(passpointConfig2, mapping));
+
+        return matchingList;
+    }
+
+    private List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>>
+            createPasspointMatchingWifiConfigWithScanResults(
+            List<ScanResult> homeList, List<ScanResult> roamingList) {
+        List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> matchingList =
+                new ArrayList<>();
+        Map<Integer, List<ScanResult>> mapping = new HashMap<>();
+
+        if (homeList != null) {
+            mapping.put(WifiManager.PASSPOINT_HOME_NETWORK, homeList);
+        }
+        if (roamingList != null) {
+            mapping.put(WifiManager.PASSPOINT_ROAMING_NETWORK, roamingList);
+        }
+
+        matchingList.add(new Pair(buildPasspointConfiguration(FQDN_1, PROVIDER_FRIENDLY_NAME_1),
+                mapping));
+
+        return matchingList;
+    }
+
+    private static OsuProvider buildOsuProvider(String friendlyName) {
+        Map<String, String> friendlyNames = new HashMap<>();
+        friendlyNames.put("en", friendlyName);
+        return new OsuProvider(null, friendlyNames, null, null, null, null, null);
+    }
+
     private WifiTracker createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(
                     Intent ... intents)
             throws InterruptedException {
@@ -926,4 +993,172 @@
         assertThat(tracker.getAccessPoints().get(0).getBssid()).isEqualTo(BSSID_1);
         assertThat(tracker.getAccessPoints().get(1).getBssid()).isEqualTo(BSSID_2);
     }
+
+    /**
+     * Verifies that updatePasspointAccessPoints will only return AccessPoints whose
+     * isPasspoint() evaluates as true.
+     */
+    @Test
+    public void updatePasspointAccessPoints_returnedAccessPointsArePasspoint() {
+        WifiTracker tracker = createMockedWifiTracker();
+
+        List<AccessPoint> passpointAccessPoints = tracker.updatePasspointAccessPoints(
+                createPasspointMatchingWifiConfigsWithDuplicates(), new ArrayList<>());
+
+        assertTrue(passpointAccessPoints.size() != 0);
+        for (AccessPoint ap : passpointAccessPoints) {
+            assertTrue(ap.isPasspoint());
+        }
+    }
+
+    /**
+     * Verifies that updatePasspointAccessPoints will return the same amount of AccessPoints as
+     * unique WifiConfigurations, even if duplicate FQDNs exist.
+     */
+    @Test
+    public void updatePasspointAccessPoints_ignoresDuplicateFQDNs() {
+        WifiTracker tracker = createMockedWifiTracker();
+
+        // Process matching list of four configs with two duplicate FQDNs.
+        List<AccessPoint> passpointAccessPoints = tracker.updatePasspointAccessPoints(
+                createPasspointMatchingWifiConfigsWithDuplicates(), new ArrayList<>());
+
+        // Should have 2 APs with unique FQDNs, ignoring the 2 duplicate FQDNs.
+        assertThat(passpointAccessPoints).hasSize(2);
+
+        Set<String> fqdns = new ArraySet<>(Arrays.asList(FQDN_1, FQDN_2));
+
+        assertTrue(fqdns.remove(passpointAccessPoints.get(0).getConfig().FQDN));
+        assertTrue(fqdns.remove(passpointAccessPoints.get(1).getConfig().FQDN));
+    }
+
+    /**
+     * Verifies that updatePasspointAccessPoints will return matching cached APs and update their
+     * scan results instead of creating new APs.
+     */
+    @Test
+    public void updatePasspointAccessPoints_usesCachedAccessPoints() {
+        WifiTracker tracker = createMockedWifiTracker();
+
+        ScanResult result = buildScanResult1();
+
+        List<AccessPoint> passpointAccessPointsFirstUpdate = tracker.updatePasspointAccessPoints(
+                createPasspointMatchingWifiConfigWithScanResults(Arrays.asList(result),
+                        null), new ArrayList<>());
+        List<AccessPoint> cachedAccessPoints = new ArrayList<>(passpointAccessPointsFirstUpdate);
+
+        int prevRssi = result.level;
+        int newRssi = prevRssi + 10;
+        result.level = newRssi;
+
+        List<AccessPoint> passpointAccessPointsSecondUpdate = tracker.updatePasspointAccessPoints(
+                createPasspointMatchingWifiConfigWithScanResults(Arrays.asList(result),
+                        null), cachedAccessPoints);
+
+        // Verify second update AP is the same object as the first update AP
+        assertThat(passpointAccessPointsFirstUpdate.get(0))
+                .isSameAs(passpointAccessPointsSecondUpdate.get(0));
+        // Verify second update AP has the average of the first and second update RSSIs
+        assertThat(passpointAccessPointsSecondUpdate.get(0).getRssi())
+                .isEqualTo((prevRssi + newRssi) / 2);
+    }
+
+    /**
+     * Verifies that updateOsuAccessPoints will only return AccessPoints whose
+     * isOsuProvider() evaluates as true.
+     */
+    @Test
+    public void updateOsuAccessPoints_returnedAccessPointsAreOsuProviders() {
+        WifiTracker tracker = createMockedWifiTracker();
+
+        Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>();
+        providersAndScans.put(
+                buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(buildScanResult1()));
+        providersAndScans.put(
+                buildOsuProvider(PROVIDER_FRIENDLY_NAME_2), Arrays.asList(buildScanResult2()));
+
+        List<AccessPoint> osuAccessPoints = tracker.updateOsuAccessPoints(
+                providersAndScans, new ArrayList<>());
+
+        assertThat(osuAccessPoints).hasSize(2);
+        for (AccessPoint ap: osuAccessPoints) {
+            assertThat(ap.isOsuProvider()).isTrue();
+        }
+    }
+
+    /**
+     * Verifies that updateOsuAccessPoints will not return Osu AccessPoints for already provisioned
+     * networks
+     */
+    @Test
+    public void updateOsuAccessPoints_doesNotReturnAlreadyProvisionedOsuAccessPoints() {
+        WifiTracker tracker = createMockedWifiTracker();
+
+        // Start with two Osu Providers
+        Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>();
+        providersAndScans.put(
+                buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(buildScanResult1()));
+        providersAndScans.put(
+                buildOsuProvider(PROVIDER_FRIENDLY_NAME_2), Arrays.asList(buildScanResult2()));
+
+        // First update
+        List<AccessPoint> osuAccessPoints = tracker.updateOsuAccessPoints(
+                providersAndScans, new ArrayList<>());
+
+        // Make sure both Osu Providers' APs are returned
+        assertThat(osuAccessPoints).hasSize(2);
+        List<String> friendlyNames = Arrays.asList(
+                osuAccessPoints.get(0).getTitle(), osuAccessPoints.get(1).getTitle());
+        assertThat(friendlyNames)
+                .containsExactly(PROVIDER_FRIENDLY_NAME_1, PROVIDER_FRIENDLY_NAME_2);
+
+        // Simulate Osu Provider 1 being provisioned
+        Map<OsuProvider, PasspointConfiguration> matchingPasspointConfigForOsuProvider =
+                new HashMap<>();
+        matchingPasspointConfigForOsuProvider.put(buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), null);
+        when(mockWifiManager.getMatchingPasspointConfigsForOsuProviders(any())).thenReturn(
+                matchingPasspointConfigForOsuProvider);
+
+        // Second update
+        osuAccessPoints = tracker.updateOsuAccessPoints(
+                providersAndScans, new ArrayList<>());
+
+        // Returned AP should only be for Osu Provider 2
+        assertThat(osuAccessPoints).hasSize(1);
+        assertThat(osuAccessPoints.get(0).getTitle()).isEqualTo(PROVIDER_FRIENDLY_NAME_2);
+    }
+
+    /**
+     * Verifies that updateOsuAccessPoints will return matching cached APs and update their
+     * scan results instead of creating new APs.
+     */
+    @Test
+    public void updateOsuAccessPoints_usesCachedAccessPoints() {
+        WifiTracker tracker = createMockedWifiTracker();
+
+        ScanResult result = buildScanResult1();
+
+        Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>();
+        providersAndScans.put(
+                buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(result));
+
+        List<AccessPoint> osuAccessPointsFirstUpdate = tracker.updateOsuAccessPoints(
+                providersAndScans, new ArrayList<>());
+        List<AccessPoint> cachedAccessPoints = new ArrayList<>(osuAccessPointsFirstUpdate);
+
+        // New RSSI for second update
+        int prevRssi = result.level;
+        int newRssi = prevRssi + 10;
+        result.level = newRssi;
+
+        List<AccessPoint> osuAccessPointsSecondUpdate = tracker.updateOsuAccessPoints(
+                providersAndScans, cachedAccessPoints);
+
+        // Verify second update AP is the same object as the first update AP
+        assertTrue(osuAccessPointsFirstUpdate.get(0)
+                == osuAccessPointsSecondUpdate.get(0));
+        // Verify second update AP has the average of the first and second update RSSIs
+        assertThat(osuAccessPointsSecondUpdate.get(0).getRssi())
+                .isEqualTo((prevRssi + newRssi) / 2);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
index b8a143a..c5f54bb 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
@@ -46,6 +46,7 @@
 import org.robolectric.util.ReflectionHelpers;
 
 import java.time.ZonedDateTime;
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
@@ -99,6 +100,20 @@
     }
 
     @Test
+    public void loadInBackground_hasCyclePeriod_shouldLoadDataForSpecificCycles() {
+        mLoader = spy(new NetworkCycleDataTestLoader(mContext));
+        doNothing().when(mLoader).loadDataForSpecificCycles();
+        final ArrayList<Long> cycles = new ArrayList<>();
+        cycles.add(67890L);
+        cycles.add(12345L);
+        ReflectionHelpers.setField(mLoader, "mCycles", cycles);
+
+        mLoader.loadInBackground();
+
+        verify(mLoader).loadDataForSpecificCycles();
+    }
+
+    @Test
     public void loadPolicyData_shouldRecordUsageFromPolicyCycle() {
         final int networkType = ConnectivityManager.TYPE_MOBILE;
         final String subId = "TestSubscriber";
@@ -139,6 +154,27 @@
         verify(mLoader).recordUsage(fourWeeksAgo, now);
     }
 
+    @Test
+    public void loadDataForSpecificCycles_shouldRecordUsageForSpecifiedTime() {
+        mLoader = spy(new NetworkCycleDataTestLoader(mContext));
+        final long now = System.currentTimeMillis();
+        final long tenDaysAgo = now - (DateUtils.DAY_IN_MILLIS * 10);
+        final long twentyDaysAgo = now - (DateUtils.DAY_IN_MILLIS * 20);
+        final long thirtyDaysAgo = now - (DateUtils.DAY_IN_MILLIS * 30);
+        final ArrayList<Long> cycles = new ArrayList<>();
+        cycles.add(now);
+        cycles.add(tenDaysAgo);
+        cycles.add(twentyDaysAgo);
+        cycles.add(thirtyDaysAgo);
+        ReflectionHelpers.setField(mLoader, "mCycles", cycles);
+
+        mLoader.loadDataForSpecificCycles();
+
+        verify(mLoader).recordUsage(tenDaysAgo, now);
+        verify(mLoader).recordUsage(twentyDaysAgo, tenDaysAgo);
+        verify(mLoader).recordUsage(thirtyDaysAgo, twentyDaysAgo);
+    }
+
     public class NetworkCycleDataTestLoader extends NetworkCycleDataLoader<List<NetworkCycleData>> {
 
         private NetworkCycleDataTestLoader(Context context) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 6152b8c..db4b131 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -698,6 +698,9 @@
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST,
                 GlobalSettingsProto.Gpu.ANGLE_WHITELIST);
         dumpSetting(s, p,
+                Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX,
+                GlobalSettingsProto.Gpu.SHOW_ANGLE_IN_USE_DIALOG);
+        dumpSetting(s, p,
                 Settings.Global.GPU_DEBUG_LAYER_APP,
                 GlobalSettingsProto.Gpu.DEBUG_LAYER_APP);
         dumpSetting(s, p,
@@ -718,6 +721,9 @@
         dumpSetting(s, p,
                 Settings.Global.GAME_DRIVER_WHITELIST,
                 GlobalSettingsProto.Gpu.GAME_DRIVER_WHITELIST);
+        dumpSetting(s, p,
+                Settings.Global.GAME_DRIVER_BLACKLISTS,
+                GlobalSettingsProto.Gpu.GAME_DRIVER_BLACKLISTS);
         p.end(gpuToken);
 
         final long hdmiToken = p.start(GlobalSettingsProto.HDMI);
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 94481e7..5714556 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -64,6 +64,9 @@
          charged, say that it is charged. -->
     <string name="keyguard_charged">Fully charged</string>
 
+    <!-- When the lock screen is showing and the phone plugged in, and the battery is not fully charged, say that it's wirelessly charging. [CHAR LIMIT=50]  -->
+    <string name="keyguard_plugged_in_wireless"><xliff:g id="percentage" example="20%">%s</xliff:g> • Wirelessly Charging</string>
+
     <!-- When the lock screen is showing and the phone plugged in, and the battery
          is not fully charged, say that it's charging.  -->
     <string name="keyguard_plugged_in"><xliff:g id="percentage">%s</xliff:g> • Charging</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index db92ed2..7d009b5 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -955,6 +955,9 @@
     <!-- Interruption level: Alarms only.  Optimized for narrow two-line display. [CHAR LIMIT=40] -->
     <string name="interruption_level_alarms_twoline">Alarms\nonly</string>
 
+    <!-- Indication on the keyguard that is shown when the device is wirelessly charging. [CHAR LIMIT=80]-->
+    <string name="keyguard_indication_charging_time_wireless"><xliff:g id="percentage" example="20%">%2$s</xliff:g> • Wirelessly Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%1$s</xliff:g> until full)</string>
+
     <!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=50]-->
     <string name="keyguard_indication_charging_time"><xliff:g id="percentage">%2$s</xliff:g> • Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%1$s</xliff:g> until full)</string>
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 2ff98ba..37abab9 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -16,19 +16,32 @@
 
 package com.android.systemui.shared.recents;
 
+import android.graphics.Region;
+import android.os.Bundle;
 import android.view.MotionEvent;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 
 oneway interface IOverviewProxy {
-    void onBind(in ISystemUiProxy sysUiProxy);
+
+    void onActiveNavBarRegionChanges(in Region activeRegion) = 11;
+
+    void onInitialize(in Bundle params) = 12;
+
+
+    /**
+     * @deprecated
+     */
+    void onBind(in ISystemUiProxy sysUiProxy) = 0;
 
     /**
      * Called once immediately prior to the first onMotionEvent() call, providing a hint to the
      * target the initial source of the subsequent motion events.
      *
      * @param downHitTarget is one of the {@link NavigationBarCompat.HitTarget}s
+     *
+     * @deprecated
      */
-    void onPreMotionEvent(int downHitTarget);
+    void onPreMotionEvent(int downHitTarget) = 1;
 
     /**
      * Proxies motion events from the nav bar in SystemUI to the OverviewProxyService. The sender
@@ -38,40 +51,48 @@
      * Quick scrub: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, SCRUB_START, SCRUB_PROGRESS*, SCRUB_END
      *
      * Once quick scrub is sent, then no further motion events will be provided.
+     *
+     * @deprecated
      */
-    void onMotionEvent(in MotionEvent event);
+    void onMotionEvent(in MotionEvent event) = 2;
 
     /**
      * Sent when the user starts to actively scrub the nav bar to switch tasks. Once this event is
      * sent the caller will stop sending any motion events and will no longer preemptively cancel
      * any recents animations started as a part of the motion event handling.
+     *
+     * @deprecated
      */
-    void onQuickScrubStart();
+    void onQuickScrubStart() = 3;
 
     /**
      * Sent when the user stops actively scrubbing the nav bar to switch tasks.
+     *
+     * @deprecated
      */
-    void onQuickScrubEnd();
+    void onQuickScrubEnd() = 4;
 
     /**
      * Sent for each movement over the nav bar while the user is scrubbing it to switch tasks.
+     *
+     * @deprecated
      */
-    void onQuickScrubProgress(float progress);
+    void onQuickScrubProgress(float progress) = 5;
 
     /**
      * Sent when overview button is pressed to toggle show/hide of overview.
      */
-    void onOverviewToggle();
+    void onOverviewToggle() = 6;
 
     /**
      * Sent when overview is to be shown.
      */
-    void onOverviewShown(boolean triggeredFromAltTab);
+    void onOverviewShown(boolean triggeredFromAltTab) = 7;
 
     /**
      * Sent when overview is to be hidden.
      */
-    void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
+    void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) = 8;
 
     /**
      * Sent when a user swipes up over the navigation bar to launch overview. Swipe up is determined
@@ -83,11 +104,13 @@
      * visible, this event will still be sent if user swipes up). When this signal is sent,
      * navigation bar will not handle any gestures such as quick scrub and the home button will
      * cancel (long) press.
+     *
+     * @deprecated
      */
-    void onQuickStep(in MotionEvent event);
+    void onQuickStep(in MotionEvent event) = 9;
 
     /**
      * Sent when there was an action on one of the onboarding tips view.
      */
-    void onTip(int actionType, int viewType);
+    void onTip(int actionType, int viewType) = 10;
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java
index f7ccb81..804f4f1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.shared.system;
 
+import android.os.Bundle;
 import android.os.Looper;
 import android.util.Pair;
 import android.view.BatchedInputEventReceiver;
@@ -53,6 +54,16 @@
     }
 
     /**
+     * Creates a dispatcher from the extras received as part on onInitialize
+     */
+    public static InputEventReceiver fromBundle(Bundle params, String key,
+            Looper looper, Choreographer choreographer, InputEventListener listener) {
+
+        InputChannel channel = params.getParcelable(key);
+        return new InputEventReceiver(channel, looper, choreographer, listener);
+    }
+
+    /**
      * @see BatchedInputEventReceiver
      */
     public static class InputEventReceiver {
@@ -90,7 +101,7 @@
         private final InputChannel mInputChannel;
         private final InputEventSender mSender;
 
-        private InputEventDispatcher(InputChannel inputChannel, Looper looper) {
+        public InputEventDispatcher(InputChannel inputChannel, Looper looper) {
             mInputChannel = inputChannel;
             mSender = new InputEventSender(inputChannel, looper) { };
         }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
index 69aea2c..b363b4a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
@@ -17,31 +17,15 @@
 package com.android.systemui.shared.system;
 
 import android.annotation.IntDef;
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.DisplayMetrics;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
-public class NavigationBarCompat {
-    /**
-     * Touch slopes and thresholds for quick step operations. Drag slop is the point where the
-     * home button press/long press over are ignored and will start to drag when exceeded and the
-     * touch slop is when the respected operation will occur when exceeded. Touch slop must be
-     * larger than the drag slop.
-     */
-    public static int getQuickStepDragSlopPx() {
-        return convertDpToPixel(10);
-    }
+/**
+ * TODO: Remove this class
+ */
+public class NavigationBarCompat extends QuickStepContract {
 
-    public static int getQuickStepTouchSlopPx() {
-        return convertDpToPixel(24);
-    }
-
-    public static int getQuickScrubTouchSlopPx() {
-        return convertDpToPixel(24);
-    }
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({HIT_TARGET_NONE, HIT_TARGET_BACK, HIT_TARGET_HOME, HIT_TARGET_OVERVIEW})
@@ -75,8 +59,4 @@
      * Interaction type: show/hide the overview button while this service is connected to launcher
      */
     public static final int FLAG_SHOW_OVERVIEW_BUTTON = 0x4;
-
-    private static int convertDpToPixel(float dp){
-        return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
-    }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
new file mode 100644
index 0000000..6d7abd0
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.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.shared.system;
+
+import android.content.res.Resources;
+
+/**
+ * Various shared constants between Launcher and SysUI as part of quickstep
+ */
+public class QuickStepContract {
+
+    public static final String KEY_EXTRA_SYSUI_PROXY = "extra_sysui_proxy";
+    public static final String KEY_EXTRA_INPUT_CHANNEL = "extra_input_channel";
+    public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
+    public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners";
+
+    /**
+     * Touch slopes and thresholds for quick step operations. Drag slop is the point where the
+     * home button press/long press over are ignored and will start to drag when exceeded and the
+     * touch slop is when the respected operation will occur when exceeded. Touch slop must be
+     * larger than the drag slop.
+     */
+    public static int getQuickStepDragSlopPx() {
+        return convertDpToPixel(10);
+    }
+
+    public static int getQuickStepTouchSlopPx() {
+        return convertDpToPixel(24);
+    }
+
+    public static int getQuickScrubTouchSlopPx() {
+        return convertDpToPixel(24);
+    }
+
+    private static int convertDpToPixel(float dp) {
+        return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 4d70890..038f491 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -290,10 +290,6 @@
         return mAssistUtils.isSessionRunning();
     }
 
-    public void destroy() {
-        mWindowManager.removeViewImmediate(mView);
-    }
-
     private void maybeSwapSearchIcon(@NonNull ComponentName assistComponent, boolean isService) {
         replaceDrawable(mView.getOrb().getLogo(), assistComponent, ASSIST_ICON_METADATA_NAME,
                 isService);
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
index ecbf024..1765dc8 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
@@ -21,7 +21,9 @@
 import android.widget.ImageView
 import android.widget.LinearLayout
 import android.widget.TextView
+import com.android.systemui.Dependency
 import com.android.systemui.R
+import com.android.systemui.statusbar.policy.KeyguardMonitor
 
 class OngoingPrivacyChip @JvmOverloads constructor(
     context: Context,
@@ -49,6 +51,8 @@
                 updateView()
             }
         }
+    @Suppress("DEPRECATION")
+    private val keyguardMonitor = Dependency.get(KeyguardMonitor::class.java)
     var builder = PrivacyDialogBuilder(context, emptyList<PrivacyItem>())
     var privacyList = emptyList<PrivacyItem>()
         set(value) {
@@ -90,16 +94,7 @@
         if (!privacyList.isEmpty()) {
             generateContentDescription()
             setIcons(builder, iconsContainer)
-            text.visibility = if (builder.types.size == 1 && expanded) VISIBLE else GONE
-            if (builder.types.size == 1 && expanded) {
-                if (builder.app != null) {
-                    text.setText(builder.app?.applicationName)
-                } else {
-                    text.text = context.resources.getQuantityString(
-                            R.plurals.ongoing_privacy_chip_multiple_apps,
-                            builder.appsAndTypes.size, builder.appsAndTypes.size)
-                }
-            }
+            setApplicationText()
         } else {
             text.visibility = GONE
             iconsContainer.removeAllViews()
@@ -107,13 +102,28 @@
         requestLayout()
     }
 
+    private fun setApplicationText() {
+        text.visibility = if (builder.types.size == 1 && expanded) VISIBLE else GONE
+        if (builder.types.size == 1 && expanded) {
+            if (builder.app != null && !amISecure()) {
+                text.setText(builder.app?.applicationName)
+            } else {
+                text.text = context.resources.getQuantityString(
+                        R.plurals.ongoing_privacy_chip_multiple_apps,
+                        builder.appsAndTypes.size, builder.appsAndTypes.size)
+            }
+        }
+    }
+
+    private fun amISecure() = keyguardMonitor.isShowing && keyguardMonitor.isSecure
+
     private fun generateContentDescription() {
         val typesText = builder.joinTypes()
         if (builder.types.size > 1) {
             contentDescription = context.getString(
                     R.string.ongoing_privacy_chip_content_multiple_apps, typesText)
         } else {
-            if (builder.app != null) {
+            if (builder.app != null && !amISecure()) {
                 contentDescription =
                         context.getString(R.string.ongoing_privacy_chip_content_single_app,
                                 builder.app?.applicationName, typesText)
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
index cff7fe4..75b8a05 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
@@ -36,8 +36,8 @@
 import java.util.concurrent.TimeUnit
 
 class OngoingPrivacyDialog constructor(
-    val context: Context,
-    val dialogBuilder: PrivacyDialogBuilder
+    private val context: Context,
+    private val dialogBuilder: PrivacyDialogBuilder
 ) {
 
     private val iconSize = context.resources.getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt
index 9c1076a..bbea6b2 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt
@@ -18,7 +18,7 @@
 import android.graphics.drawable.Drawable
 import com.android.systemui.R
 
-class PrivacyDialogBuilder(val context: Context, itemsList: List<PrivacyItem>) {
+class PrivacyDialogBuilder(private val context: Context, itemsList: List<PrivacyItem>) {
 
     val appsAndTypes: List<Pair<PrivacyApplication, List<PrivacyType>>>
     val types: List<PrivacyType>
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index f1c3bf2..faeacf7 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -35,7 +35,7 @@
 import javax.inject.Singleton
 
 @Singleton
-class PrivacyItemController @Inject constructor(val context: Context) {
+class PrivacyItemController @Inject constructor(private val context: Context) {
 
     companion object {
         val OPS = intArrayOf(AppOpsManager.OP_CAMERA,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index ee9255c..c0f87cb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -48,7 +48,6 @@
 import android.view.DisplayCutout;
 import android.view.View;
 import android.view.WindowInsets;
-import android.view.WindowManager;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -553,12 +552,10 @@
             Handler mUiHandler = new Handler(Looper.getMainLooper());
             mUiHandler.post(() -> {
                 Dialog mDialog = new OngoingPrivacyDialog(mContext, builder).createDialog();
-                mDialog.getWindow().setType(
-                        WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-                SystemUIDialog.setShowForAllUsers(mDialog, true);
+                SystemUIDialog.setShowForAllUsers(mDialog, false);
                 SystemUIDialog.registerDismissListener(mDialog);
                 SystemUIDialog.setWindowOnTop(mDialog);
-                mUiHandler.post(() -> mDialog.show());
+                mActivityStarter.postQSRunnableDismissingKeyguard(() -> mDialog.show());
                 mHost.collapsePanels();
             });
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index c474faf..83c4cfc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -24,6 +24,10 @@
 import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
 import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
 import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_CHANNEL;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
 
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -32,7 +36,9 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -41,6 +47,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
+import android.view.InputChannel;
 import android.view.MotionEvent;
 
 import com.android.internal.policy.ScreenDecorationsUtils;
@@ -51,6 +58,7 @@
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.InputChannelCompat.InputEventDispatcher;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.CallbackController;
@@ -93,6 +101,8 @@
     private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
     private final Intent mQuickStepIntent;
 
+    private Region mActiveNavBarRegion;
+
     private IOverviewProxy mOverviewProxy;
     private int mConnectionBackoffAttempts;
     private @InteractionType int mInteractionFlags;
@@ -103,6 +113,8 @@
     private float mWindowCornerRadius;
     private boolean mSupportsRoundedCornersOnWindows;
 
+    private InputEventDispatcher mInputEventDispatcher;
+
     private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
 
         public void startScreenPinning(int taskId) {
@@ -309,6 +321,20 @@
                 mCurrentBoundedUserId = -1;
                 Log.e(TAG_OPS, "Failed to call onBind()", e);
             }
+
+            Bundle params = new Bundle();
+            params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder());
+            params.putParcelable(KEY_EXTRA_INPUT_CHANNEL, createNewInputDispatcher());
+            params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius);
+            params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows);
+            try {
+                mOverviewProxy.onInitialize(params);
+            } catch (RemoteException e) {
+                // Ignore error until the migration is complete.
+                Log.e(TAG_OPS, "Failed to call onBind()", e);
+            }
+            dispatchNavButtonBounds();
+
             notifyConnectionChanged();
         }
 
@@ -317,6 +343,7 @@
             Log.w(TAG_OPS, "Null binding of '" + name + "', try reconnecting");
             mCurrentBoundedUserId = -1;
             retryConnectionWithBackoff();
+            disposeInputDispatcher();
         }
 
         @Override
@@ -324,15 +351,32 @@
             Log.w(TAG_OPS, "Binding died of '" + name + "', try reconnecting");
             mCurrentBoundedUserId = -1;
             retryConnectionWithBackoff();
+            disposeInputDispatcher();
         }
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
             // Do nothing
             mCurrentBoundedUserId = -1;
+            disposeInputDispatcher();
         }
     };
 
+    private void disposeInputDispatcher() {
+        if (mInputEventDispatcher != null) {
+            mInputEventDispatcher.dispose();
+            mInputEventDispatcher = null;
+        }
+    }
+
+    private InputChannel createNewInputDispatcher() {
+        disposeInputDispatcher();
+
+        InputChannel[] channels = InputChannel.openInputChannelPair("overview-proxy-service");
+        mInputEventDispatcher = new InputEventDispatcher(channels[0], Looper.getMainLooper());
+        return channels[1];
+    }
+
     private final DeviceProvisionedListener mDeviceProvisionedCallback =
                 new DeviceProvisionedListener() {
             @Override
@@ -382,6 +426,24 @@
         }
     }
 
+    /**
+     * Sets the navbar region which can receive touch inputs
+     */
+    public void onActiveNavBarRegionChanges(Region activeRegion) {
+        mActiveNavBarRegion = activeRegion;
+        dispatchNavButtonBounds();
+    }
+
+    private void dispatchNavButtonBounds() {
+        if (mOverviewProxy != null && mActiveNavBarRegion != null) {
+            try {
+                mOverviewProxy.onActiveNavBarRegionChanges(mActiveNavBarRegion);
+            } catch (RemoteException e) {
+                Log.e(TAG_OPS, "Failed to call onActiveNavBarRegionChanges()", e);
+            }
+        }
+    }
+
     public float getBackButtonAlpha() {
         return mBackButtonAlpha;
     }
@@ -477,6 +539,10 @@
         return mOverviewProxy;
     }
 
+    public InputEventDispatcher getInputEventDispatcher() {
+        return mInputEventDispatcher;
+    }
+
     public int getInteractionFlags() {
         return mInteractionFlags;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index be749ae..164f582 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -424,22 +424,28 @@
         final boolean hasChargingTime = chargingTimeRemaining > 0;
 
         int chargingId;
-        switch (mChargingSpeed) {
-            case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST:
-                chargingId = hasChargingTime
-                        ? R.string.keyguard_indication_charging_time_fast
-                        : R.string.keyguard_plugged_in_charging_fast;
-                break;
-            case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY:
-                chargingId = hasChargingTime
-                        ? R.string.keyguard_indication_charging_time_slowly
-                        : R.string.keyguard_plugged_in_charging_slowly;
-                break;
-            default:
-                chargingId = hasChargingTime
-                        ? R.string.keyguard_indication_charging_time
-                        : R.string.keyguard_plugged_in;
-                break;
+        if (mPowerPluggedInWired) {
+            switch (mChargingSpeed) {
+                case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST:
+                    chargingId = hasChargingTime
+                            ? R.string.keyguard_indication_charging_time_fast
+                            : R.string.keyguard_plugged_in_charging_fast;
+                    break;
+                case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY:
+                    chargingId = hasChargingTime
+                            ? R.string.keyguard_indication_charging_time_slowly
+                            : R.string.keyguard_plugged_in_charging_slowly;
+                    break;
+                default:
+                    chargingId = hasChargingTime
+                            ? R.string.keyguard_indication_charging_time
+                            : R.string.keyguard_plugged_in;
+                    break;
+            }
+        } else {
+            chargingId = hasChargingTime
+                    ? R.string.keyguard_indication_charging_time_wireless
+                    : R.string.keyguard_plugged_in_wireless;
         }
 
         String percentage = NumberFormat.getPercentInstance()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index e11ec2d..2edea78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -158,18 +158,6 @@
         });
     }
 
-    /** Removes navigation bars. */
-    public void destroy() {
-        mDisplayManager.unregisterDisplayListener(this);
-        if (mNavigationBars.size() > 0) {
-            for (int i = 0; i < mNavigationBars.size(); i++) {
-                int displayId = mNavigationBars.keyAt(i);
-                removeNavigationBar(displayId);
-            }
-            mNavigationBars.clear();
-        }
-    }
-
     private void removeNavigationBar(int displayId) {
         NavigationBarFragment navBar = mNavigationBars.get(displayId);
         if (navBar != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index c25b7cf..1cc6dc3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -42,8 +42,6 @@
     /** Adds a listener to be notified when the current user changes. */
     void addUserChangedListener(UserChangedListener listener);
 
-    void destroy();
-
     SparseArray<UserInfo> getCurrentProfiles();
 
     void setLockscreenPublicMode(boolean isProfilePublic, int userId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 6a49b80..9cb6f11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -550,12 +550,6 @@
         return mKeyguardMonitor.isSecure() || mLockPatternUtils.isSecure(userId);
     }
 
-    public void destroy() {
-        mContext.unregisterReceiver(mBaseBroadcastReceiver);
-        mContext.unregisterReceiver(mAllUsersReceiver);
-        mListeners.clear();
-    }
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("NotificationLockscreenUserManager state:");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index 839b06c..1ed671f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -47,7 +47,11 @@
     }
 
     /**
-     * Called when a notification is updated, before any filtering of notifications have occurred.
+     * Called when a notification is about to be updated. Notification- and ranking-derived fields
+     * on the entry have already been updated but the following have not yet occurred:
+     * (a) View binding (i.e. the associated view has not yet been updated / inflation has not yet
+     *      been kicked off.
+     * (b) Notification filtering
      */
     default void onPreEntryUpdated(NotificationEntry entry) {
     }
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 81d0e25..56922be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -230,7 +230,6 @@
                 }
             }
         }
-        entry.setLowPriorityStateUpdated(false);
     }
 
     @Override
@@ -346,8 +345,7 @@
 
         Dependency.get(LeakDetector.class).trackInstance(entry);
         // Construct the expanded view.
-        getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification),
-                mNotificationData.get(entry.key) != null);
+        getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification));
 
         abortExistingInflation(key);
 
@@ -384,13 +382,11 @@
 
         mNotificationData.update(entry, ranking, notification);
 
-        getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification),
-                mNotificationData.get(entry.key) != null);
-
         for (NotificationEntryListener listener : mNotificationEntryListeners) {
             listener.onPreEntryUpdated(entry);
         }
 
+        getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification));
         updateNotifications();
 
         if (DEBUG) {
@@ -422,6 +418,7 @@
         }
     }
 
+    @Override
     public void updateNotificationRanking(NotificationListenerService.RankingMap rankingMap) {
         List<NotificationEntry> entries = new ArrayList<>();
         entries.addAll(mNotificationData.getActiveNotifications());
@@ -447,8 +444,7 @@
                     entry,
                     oldImportances.get(entry.key),
                     oldAdjustments.get(entry.key),
-                    NotificationUiAdjustment.extractFromNotificationEntry(entry),
-                    mNotificationData.get(entry.key) != null);
+                    NotificationUiAdjustment.extractFromNotificationEntry(entry));
         }
 
         updateNotifications();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
index 88f4ca2..769cbb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
@@ -61,11 +61,6 @@
         mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
     }
 
-    /** Should be called when the list controller is being destroyed. */
-    public void destroy() {
-        mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
-    }
-
     @SuppressWarnings("FieldCanBeLocal")
     private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
index 0b8596f..f1bb0d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
@@ -124,8 +124,7 @@
      */
     public void inflateViews(
             NotificationEntry entry,
-            Runnable onDismissRunnable,
-            boolean isUpdate)
+            Runnable onDismissRunnable)
             throws InflationException {
         ViewGroup parent = mListContainer.getViewParentForNotification(entry);
         PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext,
@@ -135,13 +134,13 @@
         if (entry.rowExists()) {
             entry.updateIcons(mContext, sbn);
             entry.reset();
-            updateNotification(entry, pmUser, sbn, entry.getRow(), isUpdate);
+            updateNotification(entry, pmUser, sbn, entry.getRow());
         } else {
             entry.createIcons(mContext, sbn);
             new RowInflaterTask().inflate(mContext, parent, entry,
                     row -> {
                         bindRow(entry, pmUser, sbn, row, onDismissRunnable);
-                        updateNotification(entry, pmUser, sbn, row, isUpdate);
+                        updateNotification(entry, pmUser, sbn, row);
                     });
         }
     }
@@ -197,15 +196,14 @@
             NotificationEntry entry,
             @Nullable Integer oldImportance,
             NotificationUiAdjustment oldAdjustment,
-            NotificationUiAdjustment newAdjustment,
-            boolean isUpdate) {
+            NotificationUiAdjustment newAdjustment) {
         if (NotificationUiAdjustment.needReinflate(oldAdjustment, newAdjustment)) {
             if (entry.rowExists()) {
                 entry.reset();
                 PackageManager pmUser = StatusBar.getPackageManagerForUser(
                         mContext,
                         entry.notification.getUser().getIdentifier());
-                updateNotification(entry, pmUser, entry.notification, entry.getRow(), isUpdate);
+                updateNotification(entry, pmUser, entry.notification, entry.getRow());
             } else {
                 // Once the RowInflaterTask is done, it will pick up the updated entry, so
                 // no-op here.
@@ -224,12 +222,8 @@
             NotificationEntry entry,
             PackageManager pmUser,
             StatusBarNotification sbn,
-            ExpandableNotificationRow row,
-            boolean isUpdate) {
-        boolean isLowPriority = entry.ambient;
-        boolean wasLowPriority = row.isLowPriority();
-        row.setIsLowPriority(isLowPriority);
-        row.setLowPriorityStateUpdated(isUpdate && (wasLowPriority != isLowPriority));
+            ExpandableNotificationRow row) {
+        row.setIsLowPriority(entry.ambient);
         // bind the click event to the content area
         checkNotNull(mNotificationClicker).register(row, sbn);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index c886685..396a3a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -45,7 +45,7 @@
     private boolean mReorderingAllowed;
     private VisibilityLocationProvider mVisibilityLocationProvider;
     private ArraySet<View> mAllowedReorderViews = new ArraySet<>();
-    private ArraySet<View> mLowPriorityReorderingViews = new ArraySet<>();
+    private ArraySet<NotificationEntry> mLowPriorityReorderingViews = new ArraySet<>();
     private ArraySet<View> mAddedChildren = new ArraySet<>();
     private boolean mPulsing;
 
@@ -53,14 +53,21 @@
     public VisualStabilityManager(NotificationEntryManager notificationEntryManager) {
         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
-            public void onEntryReinflated(NotificationEntry entry) {
-                if (entry.hasLowPriorityStateUpdated()) {
-                    onLowPriorityUpdated(entry);
-                    if (mPresenter != null) {
-                        mPresenter.updateNotificationViews();
-                    }
+            public void onPreEntryUpdated(NotificationEntry entry) {
+                final boolean mAmbientStateHasChanged =
+                        entry.ambient != entry.getRow().isLowPriority();
+                if (mAmbientStateHasChanged) {
+                    mLowPriorityReorderingViews.add(entry);
                 }
             }
+
+            @Override
+            public void onPostEntryUpdated(NotificationEntry entry) {
+                // This line is technically not required as we'll get called as the hierarchy
+                // manager will call onReorderingFinished() immediately before this.
+                // TODO: Find a way to make this relationship more explicit
+                mLowPriorityReorderingViews.remove(entry);
+            }
         });
     }
 
@@ -142,7 +149,7 @@
         if (mAddedChildren.contains(row)) {
             return true;
         }
-        if (mLowPriorityReorderingViews.contains(row)) {
+        if (mLowPriorityReorderingViews.contains(row.getEntry())) {
             return true;
         }
         if (mAllowedReorderViews.contains(row)
@@ -172,10 +179,6 @@
         }
     }
 
-    private void onLowPriorityUpdated(NotificationEntry entry) {
-        mLowPriorityReorderingViews.add(entry.getRow());
-    }
-
     /**
      * Notify the visual stability manager that a new view was added and should be allowed to
      * reorder next time.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index f74de5b..f6d4ce22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -622,10 +622,6 @@
         return null;
     }
 
-    public boolean hasLowPriorityStateUpdated() {
-        return row != null && row.hasLowPriorityStateUpdated();
-    }
-
     public void removeRow() {
         if (row != null) row.setRemoved();
     }
@@ -650,10 +646,6 @@
         return parent == null;
     }
 
-    public void setLowPriorityStateUpdated(boolean updated) {
-        if (row != null) row.setLowPriorityStateUpdated(updated);
-    }
-
     /**
      * @return Can the underlying notification be cleared? This can be different from whether the
      *         notification can be dismissed in case notifications are sensitive on the lockscreen.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index b8e33a8..8f7778b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -124,6 +124,7 @@
     public static final float DEFAULT_HEADER_VISIBLE_AMOUNT = 1.0f;
     private static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
     private boolean mUpdateBackgroundOnUpdate;
+    private boolean mNotificationTranslationFinished = false;
 
     /**
      * Listener for when {@link ExpandableNotificationRow} is laid out.
@@ -133,7 +134,6 @@
     }
 
     private LayoutListener mLayoutListener;
-    private boolean mLowPriorityStateUpdated;
     private final NotificationInflater mNotificationInflater;
     private int mIconTransformContentShift;
     private int mIconTransformContentShiftNoIcon;
@@ -1453,6 +1453,10 @@
         return mIsBlockingHelperShowing;
     }
 
+    public boolean isBlockingHelperShowingAndTranslationFinished() {
+        return mIsBlockingHelperShowing && mNotificationTranslationFinished;
+    }
+
     public void setOnDismissRunnable(Runnable onDismissRunnable) {
         mOnDismissRunnable = onDismissRunnable;
     }
@@ -1577,15 +1581,6 @@
         }
     }
 
-
-    public void setLowPriorityStateUpdated(boolean lowPriorityStateUpdated) {
-        mLowPriorityStateUpdated = lowPriorityStateUpdated;
-    }
-
-    public boolean hasLowPriorityStateUpdated() {
-        return mLowPriorityStateUpdated;
-    }
-
     public boolean isLowPriority() {
         return mIsLowPriority;
     }
@@ -1851,7 +1846,6 @@
     }
 
     void onGutsOpened() {
-        resetTranslation();
         updateContentAccessibilityImportanceForGuts(false /* isEnabled */);
     }
 
@@ -1905,11 +1899,10 @@
 
     @Override
     public void setTranslation(float translationX) {
-        if (areGutsExposed()) {
-            // Don't translate if guts are showing.
+        if (isBlockingHelperShowingAndTranslationFinished()) {
+            mGuts.setTranslationX(translationX);
             return;
-        }
-        if (!mShouldTranslateContents) {
+        } else if (!mShouldTranslateContents) {
             setTranslationX(translationX);
         } else if (mTranslateableViews != null) {
             // Translate the group of views
@@ -1925,6 +1918,7 @@
             // positioning, so we can use the scrollX instead.
             getEntry().expandedIcon.setScrollX((int) -translationX);
         }
+
         if (mMenuRow.getMenuView() != null) {
             mMenuRow.onParentTranslationUpdate(translationX);
         }
@@ -1936,6 +1930,10 @@
             return getTranslationX();
         }
 
+        if (isBlockingHelperShowingAndCanTranslate()) {
+            return mGuts.getTranslationX();
+        }
+
         if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
             // All of the views in the list should have same translation, just use first one.
             return mTranslateableViews.get(0).getTranslationX();
@@ -1944,15 +1942,16 @@
         return 0;
     }
 
+    private boolean isBlockingHelperShowingAndCanTranslate() {
+        return areGutsExposed() && mIsBlockingHelperShowing && mNotificationTranslationFinished;
+    }
+
     public Animator getTranslateViewAnimator(final float leftTarget,
             AnimatorUpdateListener listener) {
         if (mTranslateAnim != null) {
             mTranslateAnim.cancel();
         }
-        if (areGutsExposed()) {
-            // No translation if guts are exposed.
-            return null;
-        }
+
         final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
                 leftTarget);
         if (listener != null) {
@@ -1968,6 +1967,9 @@
 
             @Override
             public void onAnimationEnd(Animator anim) {
+                if (mIsBlockingHelperShowing) {
+                    mNotificationTranslationFinished = true;
+                }
                 if (!cancelled && leftTarget == 0) {
                     mMenuRow.resetMenu();
                     mTranslateAnim = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 7105876..fbf1e31 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -578,6 +578,10 @@
     @Override
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void onDensityOrFontScaleChanged() {
+        reinflateViews();
+    }
+
+    private void reinflateViews() {
         inflateFooterView();
         inflateEmptyShadeView();
         updateFooter();
@@ -608,6 +612,7 @@
             mCornerRadius = newRadius;
             invalidate();
         }
+        reinflateViews();
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 2a88080..7882fd3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -195,6 +195,9 @@
             return false;
         }
         ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+        if (row.isBlockingHelperShowingAndTranslationFinished()) {
+            return true;
+        }
         if (row.areGutsExposed() || !row.getEntry().hasFinishedInitialization()) {
             return false;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 4c1c0a4..de0e194 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -141,10 +141,6 @@
         mAnimationStateHandler = handler;
     }
 
-    public void destroy() {
-        Dependency.get(StatusBarStateController.class).removeCallback(this);
-    }
-
     private void initResources() {
         Resources resources = mContext.getResources();
         mStatusBarHeight = resources.getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 651670c..ebd4204 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -45,6 +45,8 @@
 import android.graphics.Canvas;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.Region.Op;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -128,8 +130,8 @@
     private Rect mBackButtonBounds = new Rect();
     private Rect mRecentsButtonBounds = new Rect();
     private Rect mRotationButtonBounds = new Rect();
+    private final Region mActiveRegion = new Region();
     private int[] mTmpPosition = new int[2];
-    private Rect mTmpRect = new Rect();
 
     private KeyButtonDrawable mBackIcon;
     private KeyButtonDrawable mHomeDefaultIcon;
@@ -954,17 +956,22 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        updateButtonLocationOnScreen(getBackButton(), mBackButtonBounds);
-        updateButtonLocationOnScreen(getHomeButton(), mHomeButtonBounds);
-        updateButtonLocationOnScreen(getRecentsButton(), mRecentsButtonBounds);
-        updateButtonLocationOnScreen(getRotateSuggestionButton(), mRotationButtonBounds);
+
+        mActiveRegion.setEmpty();
+        updateButtonLocation(getBackButton(), mBackButtonBounds, true);
+        updateButtonLocation(getHomeButton(), mHomeButtonBounds, false);
+        updateButtonLocation(getRecentsButton(), mRecentsButtonBounds, false);
+        updateButtonLocation(getRotateSuggestionButton(), mRotationButtonBounds, true);
+        // TODO: Handle button visibility changes
+        mOverviewProxyService.onActiveNavBarRegionChanges(mActiveRegion);
         if (mGestureHelper != null) {
             mGestureHelper.onLayout(changed, left, top, right, bottom);
         }
         mRecentsOnboarding.setNavBarHeight(getMeasuredHeight());
     }
 
-    private void updateButtonLocationOnScreen(ButtonDispatcher button, Rect buttonBounds) {
+    private void updateButtonLocation(ButtonDispatcher button, Rect buttonBounds,
+            boolean isActive) {
         View view = button.getCurrentView();
         if (view == null) {
             buttonBounds.setEmpty();
@@ -975,6 +982,14 @@
         final float posY = view.getTranslationY();
         view.setTranslationX(0);
         view.setTranslationY(0);
+
+        if (isActive) {
+            view.getLocationOnScreen(mTmpPosition);
+            buttonBounds.set(mTmpPosition[0], mTmpPosition[1],
+                    mTmpPosition[0] + view.getMeasuredWidth(),
+                    mTmpPosition[1] + view.getMeasuredHeight());
+            mActiveRegion.op(buttonBounds, Op.UNION);
+        }
         view.getLocationInWindow(mTmpPosition);
         buttonBounds.set(mTmpPosition[0], mTmpPosition[1],
                 mTmpPosition[0] + view.getMeasuredWidth(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 069703e..f4fa1e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -590,11 +590,6 @@
                     mClockPositionResult.clockX, CLOCK_ANIMATION_PROPERTIES, animateClock);
             PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.Y,
                     mClockPositionResult.clockY, CLOCK_ANIMATION_PROPERTIES, animateClock);
-            // Move big clock up while pulling up the bouncer
-            PropertyAnimator.setProperty(mBigClockContainer, AnimatableProperty.Y,
-                    MathUtils.lerp(-mBigClockContainer.getHeight(), 0,
-                          Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(getExpandedFraction())),
-                    CLOCK_ANIMATION_PROPERTIES, animateClock);
             updateClock();
             stackScrollerPadding = mClockPositionResult.stackScrollerPadding;
         }
@@ -1334,8 +1329,7 @@
         }
     };
 
-    private void setKeyguardBottomAreaVisibility(int statusBarState,
-            boolean goingToFullShade) {
+    private void setKeyguardBottomAreaVisibility(int statusBarState, boolean goingToFullShade) {
         mKeyguardBottomArea.animate().cancel();
         if (goingToFullShade) {
             mKeyguardBottomArea.animate()
@@ -1438,6 +1432,7 @@
         if (mBarState == StatusBarState.SHADE_LOCKED
                 || mBarState == StatusBarState.KEYGUARD) {
             updateKeyguardBottomAreaAlpha();
+            updateBigClockAlpha();
         }
         if (mBarState == StatusBarState.SHADE && mQsExpanded
                 && !mStackScrollerOverscrolling && mQsScrimEnabled) {
@@ -1883,6 +1878,19 @@
         }
     }
 
+    /**
+     * Custom clock fades away when user drags up to unlock or pulls down quick settings.
+     *
+     * Updates alpha of custom clock to match the alpha of the KeyguardBottomArea. See
+     * {@link updateKeyguardBottomAreaAlpha}.
+     */
+    private void updateBigClockAlpha() {
+        float expansionAlpha = MathUtils.map(isUnlockHintRunning()
+                ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f, 0f, 1f, getExpandedFraction());
+        float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
+        mBigClockContainer.setAlpha(alpha);
+    }
+
     private float getNotificationsTopY() {
         if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
             return getExpandedHeight();
@@ -2597,6 +2605,7 @@
         }
         mNotificationStackScroller.setExpandedHeight(expandedHeight);
         updateKeyguardBottomAreaAlpha();
+        updateBigClockAlpha();
         updateStatusBarIcons();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 18711c0..2799191 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -284,25 +284,6 @@
         });
     }
 
-    public void destroy() {
-        mRotationLockController.removeCallback(this);
-        mBluetooth.removeCallback(this);
-        mProvisionedController.removeCallback(this);
-        mZenController.removeCallback(this);
-        mCast.removeCallback(mCastCallback);
-        mHotspot.removeCallback(mHotspotCallback);
-        mNextAlarmController.removeCallback(mNextAlarmCallback);
-        mDataSaver.removeCallback(this);
-        mKeyguardMonitor.removeCallback(this);
-        mPrivacyItemController.removeCallback(this);
-        SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallback(this);
-        mContext.unregisterReceiver(mIntentReceiver);
-
-        NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
-        mCurrentNotifs.forEach(v -> noMan.cancelAsUser(v.first, SystemMessage.NOTE_INSTANT_APPS,
-                new UserHandle(v.second)));
-    }
-
     @Override
     public void onZenChanged(int zen) {
         updateVolumeZen();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index 84f1cef..73ab527 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -56,6 +56,7 @@
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.system.InputChannelCompat.InputEventDispatcher;
 import com.android.systemui.shared.system.NavigationBarCompat;
 
 import java.io.PrintWriter;
@@ -676,8 +677,13 @@
     }
 
     private boolean proxyMotionEvents(MotionEvent event) {
-        final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
         event.transform(mTransformGlobalMatrix);
+        InputEventDispatcher dispatcher = mOverviewEventSender.getInputEventDispatcher();
+        if (dispatcher != null) {
+            dispatcher.dispatch(event);
+        }
+
+        final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
         try {
             if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
                 overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget());
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 9f3bec6..6b6998d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1550,12 +1550,12 @@
 
     @Override
     public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
-        mEntryManager.updateNotificationRanking(null /* rankingMap */);
+        mEntryManager.updateNotifications();
     }
 
     @Override
     public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
-        mEntryManager.updateNotificationRanking(null);
+        mEntryManager.updateNotifications();
         if (isAmbient) {
             mDozeServiceHost.fireNotificationPulse();
         } else if (!mAmbientPulseManager.hasNotifications()) {
@@ -2843,38 +2843,6 @@
         startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */);
     }
 
-    public void destroy() {
-        // Begin old BaseStatusBar.destroy().
-        mContext.unregisterReceiver(mBannerActionBroadcastReceiver);
-        mLockscreenUserManager.destroy();
-        try {
-            mNotificationListener.unregisterAsSystemService();
-        } catch (RemoteException e) {
-            // Ignore.
-        }
-        mNotificationListController.destroy();
-        // End old BaseStatusBar.destroy().
-        if (mStatusBarWindow != null) {
-            mWindowManager.removeViewImmediate(mStatusBarWindow);
-            mStatusBarWindow = null;
-        }
-        mNavigationBarController.destroy();
-        mContext.unregisterReceiver(mBroadcastReceiver);
-        mContext.unregisterReceiver(mDemoReceiver);
-        mAssistManager.destroy();
-        mHeadsUpManager.destroy();
-        mStatusBarStateController.removeCallback(this);
-
-        if (mQSPanel != null && mQSPanel.getHost() != null) {
-            mQSPanel.getHost().destroy();
-        }
-        Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null);
-        mDeviceProvisionedController.removeCallback(mUserSetupObserver);
-        Dependency.get(ConfigurationController.class).removeCallback(this);
-        mZenController.removeCallback(this);
-        mAppOpsController.removeCallback(APP_OPS, this);
-    }
-
     private boolean mDemoModeAllowed;
     private boolean mDemoMode;
 
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 e9705ff..3ce66c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -258,6 +258,11 @@
         }
     }
 
+    @Override
+    public void onOverlayChanged() {
+        onDensityOrFontScaleChanged();
+    }
+
     private void updateNotificationOnUiModeChanged() {
         ArrayList<NotificationEntry> userNotifications
                 = mEntryManager.getNotificationData().getNotificationsForCurrentUser();
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 3c91069..d9adec8 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6975,6 +6975,23 @@
     // formerly: histogram system_cost_for_smart_sharing
     FIELD_TIME_TO_APP_TARGETS = 1653;
 
+    // Open: Settings > Panel for Internet Connectivity
+    PANEL_INTERNET_CONNECTIVITY = 1654;
+
+    // Open: Settings > Panel for Volume
+    PANEL_VOLUME = 1655;
+
+    // Open: Settings > Panel for NFC
+    PANEL_NFC = 1656;
+
+    // Open: Settings > Panel for Media Output
+    PANEL_MEDIA_OUTPUT = 1657;
+
+    // ACTION: An interaction with a Slice or other component in the Panel.
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ACTION_PANEL_INTERACTION = 1658;
+
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/core/java/com/android/server/ExtconUEventObserver.java b/services/core/java/com/android/server/ExtconUEventObserver.java
index b3084f5..ebd4c55 100644
--- a/services/core/java/com/android/server/ExtconUEventObserver.java
+++ b/services/core/java/com/android/server/ExtconUEventObserver.java
@@ -22,8 +22,11 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.regex.Pattern;
 
 /**
  * A specialized UEventObserver that receives UEvents from the kernel for devices in the {@code
@@ -40,13 +43,14 @@
  * time in that process. Once started the UEvent thread will not stop (although it can stop
  * notifying UEventObserver's via stopObserving()).
  *
- * <p>
- *
  * @hide
  */
 public abstract class ExtconUEventObserver extends UEventObserver {
     private static final String TAG = "ExtconUEventObserver";
     private static final boolean LOG = false;
+    private static final String SELINUX_POLICIES_NEED_TO_BE_CHANGED =
+            "This probably mean the selinux policies need to be changed.";
+
     private final Map<String, ExtconInfo> mExtconInfos = new ArrayMap<>();
 
     @Override
@@ -70,15 +74,47 @@
 
     /** Starts observing {@link ExtconInfo#getDevicePath()}. */
     public void startObserving(ExtconInfo extconInfo) {
-        mExtconInfos.put(extconInfo.getDevicePath(), extconInfo);
-        if (LOG) Slog.v(TAG, "Observing  " + extconInfo.getDevicePath());
-        startObserving("DEVPATH=" + extconInfo.getDevicePath());
+        String devicePath = extconInfo.getDevicePath();
+        if (devicePath == null) {
+            Slog.wtf(TAG, "Unable to start observing  " + extconInfo.getName()
+                    + " because the device path is null. " + SELINUX_POLICIES_NEED_TO_BE_CHANGED);
+        } else {
+            mExtconInfos.put(devicePath, extconInfo);
+            if (LOG) Slog.v(TAG, "Observing  " + devicePath);
+            startObserving("DEVPATH=" + devicePath);
+        }
     }
 
     /** An External Connection to watch. */
     public static final class ExtconInfo {
         private static final String TAG = "ExtconInfo";
 
+        /** Returns a new list of all external connections whose name matches {@code regex}. */
+        public static List<ExtconInfo> getExtconInfos(@Nullable String regex) {
+            Pattern p = regex == null ? null : Pattern.compile(regex);
+            File file = new File("/sys/class/extcon");
+            File[] files = file.listFiles();
+            if (files == null) {
+                Slog.wtf(TAG, file + " exists " + file.exists() + " isDir " + file.isDirectory()
+                        + " but listFiles returns null. "
+                        + SELINUX_POLICIES_NEED_TO_BE_CHANGED);
+                return new ArrayList<>(0);  // Always return a new list.
+            } else {
+                ArrayList list = new ArrayList(files.length);
+                for (File f : files) {
+                    String name = f.getName();
+                    if (p == null || p.matcher(name).matches()) {
+                        ExtconInfo uei = new ExtconInfo(name);
+                        list.add(uei);
+                        if (LOG) Slog.d(TAG, name + " matches " + regex);
+                    } else {
+                        if (LOG) Slog.d(TAG, name + " does not match " + regex);
+                    }
+                }
+                return list;
+            }
+        }
+
         private final String mName;
 
         public ExtconInfo(String name) {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 4834ce0..3479e18 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -67,6 +67,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IInterface;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
@@ -109,6 +110,7 @@
 import com.android.server.location.LocationRequestStatistics.PackageStatistics;
 import com.android.server.location.MockProvider;
 import com.android.server.location.PassiveProvider;
+import com.android.server.location.RemoteListenerHelper;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -121,6 +123,8 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.NoSuchElementException;
+import java.util.function.Consumer;
+import java.util.function.Function;
 
 /**
  * The service class that manages LocationProviders and issues location
@@ -225,11 +229,14 @@
     private final ArraySet<String> mIgnoreSettingsPackageWhitelist = new ArraySet<>();
 
     @GuardedBy("mLock")
-    private final ArrayMap<IBinder, CallerIdentity> mGnssMeasurementsListeners = new ArrayMap<>();
-
+    private final ArrayMap<IBinder, LinkedListener<IGnssMeasurementsListener>>
+            mGnssMeasurementsListeners = new ArrayMap<>();
     @GuardedBy("mLock")
-    private final ArrayMap<IBinder, CallerIdentity>
+    private final ArrayMap<IBinder, LinkedListener<IGnssNavigationMessageListener>>
             mGnssNavigationMessageListeners = new ArrayMap<>();
+    @GuardedBy("mLock")
+    private final ArrayMap<IBinder, LinkedListener<IGnssStatusListener>>
+            mGnssStatusListeners = new ArrayMap<>();
 
     // current active user on the device - other users are denied location data
     private int mCurrentUserId = UserHandle.USER_SYSTEM;
@@ -243,7 +250,7 @@
     @GuardedBy("mLock")
     private IBatchedLocationCallback mGnssBatchingCallback;
     @GuardedBy("mLock")
-    private LinkedCallback mGnssBatchingDeathCallback;
+    private LinkedListener<IBatchedLocationCallback> mGnssBatchingDeathCallback;
     @GuardedBy("mLock")
     private boolean mGnssBatchingInProgress = false;
 
@@ -485,7 +492,7 @@
                         && record.mIsForegroundUid != foreground) {
                     if (D) {
                         Log.d(TAG, "request from uid " + uid + " is now "
-                                + (foreground ? "foreground" : "background)"));
+                                + foregroundAsString(foreground));
                     }
                     record.updateForeground(foreground);
 
@@ -499,44 +506,48 @@
             applyRequirementsLocked(provider);
         }
 
-        for (Entry<IBinder, CallerIdentity> entry : mGnssMeasurementsListeners.entrySet()) {
-            CallerIdentity callerIdentity = entry.getValue();
-            if (callerIdentity.mUid == uid) {
-                if (D) {
-                    Log.d(TAG, "gnss measurements listener from uid " + uid
-                            + " is now " + (foreground ? "foreground" : "background)"));
-                }
-                if (foreground || isThrottlingExemptLocked(entry.getValue())) {
-                    mGnssMeasurementsProvider.addListener(
-                            IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
-                            callerIdentity);
-                } else {
-                    mGnssMeasurementsProvider.removeListener(
-                            IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
-                }
-            }
-        }
+        updateGnssDataProviderOnUidImportanceChangedLocked(mGnssMeasurementsListeners,
+                mGnssMeasurementsProvider, IGnssMeasurementsListener.Stub::asInterface,
+                uid, foreground);
 
-        for (Entry<IBinder, CallerIdentity> entry : mGnssNavigationMessageListeners.entrySet()) {
-            CallerIdentity callerIdentity = entry.getValue();
-            if (callerIdentity.mUid == uid) {
-                if (D) {
-                    Log.d(TAG, "gnss navigation message listener from uid "
-                            + uid + " is now "
-                            + (foreground ? "foreground" : "background)"));
-                }
-                if (foreground || isThrottlingExemptLocked(entry.getValue())) {
-                    mGnssNavigationMessageProvider.addListener(
-                            IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
-                            callerIdentity);
-                } else {
-                    mGnssNavigationMessageProvider.removeListener(
-                            IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
-                }
+        updateGnssDataProviderOnUidImportanceChangedLocked(mGnssNavigationMessageListeners,
+                mGnssNavigationMessageProvider, IGnssNavigationMessageListener.Stub::asInterface,
+                uid, foreground);
+
+        updateGnssDataProviderOnUidImportanceChangedLocked(mGnssStatusListeners,
+                mGnssStatusProvider, IGnssStatusListener.Stub::asInterface, uid, foreground);
+    }
+
+    @GuardedBy("mLock")
+    private <TListener extends IInterface> void updateGnssDataProviderOnUidImportanceChangedLocked(
+            ArrayMap<IBinder, ? extends LinkedListenerBase> gnssDataListeners,
+            RemoteListenerHelper<TListener> gnssDataProvider,
+            Function<IBinder, TListener> mapBinderToListener, int uid, boolean foreground) {
+        for (Entry<IBinder, ? extends LinkedListenerBase> entry : gnssDataListeners.entrySet()) {
+            LinkedListenerBase linkedListener = entry.getValue();
+            CallerIdentity callerIdentity = linkedListener.mCallerIdentity;
+            if (callerIdentity.mUid != uid) {
+                continue;
+            }
+
+            if (D) {
+                Log.d(TAG, linkedListener.mListenerName + " from uid "
+                        + uid + " is now " + foregroundAsString(foreground));
+            }
+
+            TListener listener = mapBinderToListener.apply(entry.getKey());
+            if (foreground || isThrottlingExemptLocked(callerIdentity)) {
+                gnssDataProvider.addListener(listener, callerIdentity);
+            } else {
+                gnssDataProvider.removeListener(listener);
             }
         }
     }
 
+    private static String foregroundAsString(boolean foreground) {
+        return foreground ? "foreground" : "background";
+    }
+
     private static boolean isImportanceForeground(int importance) {
         return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
     }
@@ -1218,9 +1229,8 @@
      * A wrapper class holding either an ILocationListener or a PendingIntent to receive
      * location updates.
      */
-    private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
+    private final class Receiver extends LinkedListenerBase implements PendingIntent.OnFinished {
         private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
-        final CallerIdentity mCallerIdentity;
         private final int mAllowedResolutionLevel;  // resolution level allowed to receiver
 
         private final ILocationListener mListener;
@@ -1240,6 +1250,7 @@
 
         private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
                 String packageName, WorkSource workSource, boolean hideFromAppOps) {
+            super(new CallerIdentity(uid, pid, packageName), "LocationListener");
             mListener = listener;
             mPendingIntent = intent;
             if (listener != null) {
@@ -1248,7 +1259,6 @@
                 mKey = intent;
             }
             mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
-            mCallerIdentity = new CallerIdentity(uid, pid, packageName);
             if (workSource != null && workSource.isEmpty()) {
                 workSource = null;
             }
@@ -1486,7 +1496,7 @@
 
         @Override
         public void binderDied() {
-            if (D) Log.d(TAG, "Location listener died");
+            if (D) Log.d(TAG, "Remote " + mListenerName + " died.");
 
             synchronized (mLock) {
                 removeUpdatesLocked(this);
@@ -1617,53 +1627,59 @@
             return false;
         }
 
+        CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
+                Binder.getCallingPid(), packageName);
         synchronized (mLock) {
             mGnssBatchingCallback = callback;
-            mGnssBatchingDeathCallback = new LinkedCallback(callback);
-            try {
-                callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
-            } catch (RemoteException e) {
-                // if the remote process registering the listener is already dead, just swallow the
-                // exception and return
-                Log.e(TAG, "Remote listener already died.", e);
+            mGnssBatchingDeathCallback =  new LinkedListener<>(callback,
+                    "BatchedLocationCallback", callerIdentity,
+                    (IBatchedLocationCallback listener) -> {
+                        stopGnssBatch();
+                        removeGnssBatchingCallback();
+                    });
+            if (!linkToListenerDeathNotificationLocked(callback.asBinder(),
+                    mGnssBatchingDeathCallback)) {
                 return false;
             }
-
             return true;
         }
     }
 
-    private class LinkedCallback implements IBinder.DeathRecipient {
-        private final IBatchedLocationCallback mCallback;
+    private abstract static class LinkedListenerBase implements IBinder.DeathRecipient {
+        protected final CallerIdentity mCallerIdentity;
+        protected final String mListenerName;
 
-        private LinkedCallback(@NonNull IBatchedLocationCallback callback) {
-            mCallback = callback;
+        private LinkedListenerBase(@NonNull CallerIdentity callerIdentity,
+                @NonNull String listenerName) {
+            mCallerIdentity = callerIdentity;
+            mListenerName = listenerName;
         }
+    }
 
-        @NonNull
-        public IBatchedLocationCallback getUnderlyingListener() {
-            return mCallback;
+    private static class LinkedListener<TListener> extends LinkedListenerBase {
+        private final TListener mListener;
+        private final Consumer<TListener> mBinderDeathCallback;
+
+        private LinkedListener(@NonNull TListener listener, String listenerName,
+                @NonNull CallerIdentity callerIdentity,
+                @NonNull Consumer<TListener> binderDeathCallback) {
+            super(callerIdentity, listenerName);
+            mListener = listener;
+            mBinderDeathCallback = binderDeathCallback;
         }
 
         @Override
         public void binderDied() {
-            Log.d(TAG, "Remote Batching Callback died: " + mCallback);
-            stopGnssBatch();
-            removeGnssBatchingCallback();
+            if (D) Log.d(TAG, "Remote " + mListenerName + " died.");
+            mBinderDeathCallback.accept(mListener);
         }
     }
 
     @Override
     public void removeGnssBatchingCallback() {
         synchronized (mLock) {
-            try {
-                mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
-                        0 /* flags */);
-            } catch (NoSuchElementException e) {
-                // if the death callback isn't connected (it should be...), log error, swallow the
-                // exception and return
-                Log.e(TAG, "Couldn't unlink death callback.", e);
-            }
+            unlinkFromListenerDeathNotificationLocked(mGnssBatchingCallback.asBinder(),
+                    mGnssBatchingDeathCallback);
             mGnssBatchingCallback = null;
             mGnssBatchingDeathCallback = null;
         }
@@ -2264,10 +2280,8 @@
         if (receiver == null) {
             receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
                     hideFromAppOps);
-            try {
-                receiver.getListener().asBinder().linkToDeath(receiver, 0);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "linkToDeath failed:", e);
+            if (!linkToListenerDeathNotificationLocked(receiver.getListener().asBinder(),
+                    receiver)) {
                 return null;
             }
             mReceivers.put(binder, receiver);
@@ -2482,7 +2496,8 @@
         if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
 
         if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
-            receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
+            unlinkFromListenerDeathNotificationLocked(receiver.getListener().asBinder(),
+                    receiver);
             receiver.clearPendingBroadcastsLocked();
         }
 
@@ -2694,18 +2709,52 @@
     }
 
     @Override
-    public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
+    public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName) {
         if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
             return false;
         }
 
-        return mGnssStatusProvider.addListener(callback, new CallerIdentity(Binder.getCallingUid(),
-                Binder.getCallingPid(), packageName));
+        CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
+                Binder.getCallingPid(), packageName);
+        LinkedListener<IGnssStatusListener> linkedListener = new LinkedListener<>(listener,
+                "GnssStatusListener", callerIdentity, this::unregisterGnssStatusCallback);
+        IBinder binder = listener.asBinder();
+        synchronized (mLock) {
+            if (!linkToListenerDeathNotificationLocked(binder, linkedListener)) {
+                return false;
+            }
+
+            mGnssStatusListeners.put(binder, linkedListener);
+            long identity = Binder.clearCallingIdentity();
+            try {
+                if (isThrottlingExemptLocked(callerIdentity)
+                        || isImportanceForeground(
+                        mActivityManager.getPackageImportance(packageName))) {
+                    mGnssStatusProvider.addListener(listener, callerIdentity);
+                }
+                return true;
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
     }
 
     @Override
-    public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
-        mGnssStatusProvider.removeListener(callback);
+    public void unregisterGnssStatusCallback(IGnssStatusListener listener) {
+        if (mGnssStatusProvider == null) {
+            return;
+        }
+
+        IBinder binder = listener.asBinder();
+        synchronized (mLock) {
+            LinkedListener<IGnssStatusListener> linkedListener =
+                    mGnssStatusListeners.remove(binder);
+            if (linkedListener == null) {
+                return;
+            }
+            unlinkFromListenerDeathNotificationLocked(binder, linkedListener);
+            mGnssStatusProvider.removeListener(listener);
+        }
     }
 
     @Override
@@ -2715,22 +2764,75 @@
             return false;
         }
 
+        CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
+                Binder.getCallingPid(), packageName);
+        LinkedListener<IGnssMeasurementsListener> linkedListener = new LinkedListener<>(listener,
+                "GnssMeasurementsListener", callerIdentity, this::removeGnssMeasurementsListener);
+        IBinder binder = listener.asBinder();
         synchronized (mLock) {
-            CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
-                    Binder.getCallingPid(), packageName);
-            mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
+            if (!linkToListenerDeathNotificationLocked(binder, linkedListener)) {
+                return false;
+            }
+
+            mGnssMeasurementsListeners.put(binder, linkedListener);
             long identity = Binder.clearCallingIdentity();
             try {
                 if (isThrottlingExemptLocked(callerIdentity)
                         || isImportanceForeground(
                         mActivityManager.getPackageImportance(packageName))) {
-                    return mGnssMeasurementsProvider.addListener(listener, callerIdentity);
+                    mGnssMeasurementsProvider.addListener(listener, callerIdentity);
                 }
+                return true;
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
+        }
+    }
 
+    @Override
+    public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
+        if (mGnssMeasurementsProvider == null) {
+            return;
+        }
+
+        IBinder binder = listener.asBinder();
+        synchronized (mLock) {
+            LinkedListener<IGnssMeasurementsListener> linkedListener =
+                    mGnssMeasurementsListeners.remove(binder);
+            if (linkedListener == null) {
+                return;
+            }
+            unlinkFromListenerDeathNotificationLocked(binder, linkedListener);
+            mGnssMeasurementsProvider.removeListener(listener);
+        }
+    }
+
+
+    private boolean linkToListenerDeathNotificationLocked(IBinder binder,
+            LinkedListenerBase linkedListener) {
+        try {
+            binder.linkToDeath(linkedListener, 0 /* flags */);
             return true;
+        } catch (RemoteException e) {
+            // if the remote process registering the listener is already dead, just swallow the
+            // exception and return
+            Log.w(TAG, "Could not link " + linkedListener.mListenerName + " death callback.",
+                    e);
+            return false;
+        }
+    }
+
+    private boolean unlinkFromListenerDeathNotificationLocked(IBinder binder,
+            LinkedListenerBase linkedListener) {
+        try {
+            binder.unlinkToDeath(linkedListener, 0 /* flags */);
+            return true;
+        } catch (NoSuchElementException e) {
+            // if the death callback isn't connected (it should be...), log error,
+            // swallow the exception and return
+            Log.w(TAG, "Could not unlink " + linkedListener.mListenerName + " death callback.",
+                    e);
+            return false;
         }
     }
 
@@ -2759,52 +2861,53 @@
     }
 
     @Override
-    public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
-        if (mGnssMeasurementsProvider == null) {
-            return;
-        }
-
-        synchronized (mLock) {
-            mGnssMeasurementsListeners.remove(listener.asBinder());
-            mGnssMeasurementsProvider.removeListener(listener);
-        }
-    }
-
-    @Override
     public boolean addGnssNavigationMessageListener(
-            IGnssNavigationMessageListener listener,
-            String packageName) {
+            IGnssNavigationMessageListener listener, String packageName) {
         if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
             return false;
         }
 
+        CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
+                Binder.getCallingPid(), packageName);
+        LinkedListener<IGnssNavigationMessageListener> linkedListener =
+                new LinkedListener<>(listener, "GnssNavigationMessageListener", callerIdentity,
+                        this::removeGnssNavigationMessageListener);
+        IBinder binder = listener.asBinder();
         synchronized (mLock) {
-            CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
-                    Binder.getCallingPid(), packageName);
+            if (!linkToListenerDeathNotificationLocked(binder, linkedListener)) {
+                return false;
+            }
 
-            mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
+            mGnssNavigationMessageListeners.put(binder, linkedListener);
             long identity = Binder.clearCallingIdentity();
             try {
                 if (isThrottlingExemptLocked(callerIdentity)
                         || isImportanceForeground(
                         mActivityManager.getPackageImportance(packageName))) {
-                    return mGnssNavigationMessageProvider.addListener(listener, callerIdentity);
+                    mGnssNavigationMessageProvider.addListener(listener, callerIdentity);
                 }
+                return true;
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
-
-            return true;
         }
     }
 
     @Override
     public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
-        if (mGnssNavigationMessageProvider != null) {
-            synchronized (mLock) {
-                mGnssNavigationMessageListeners.remove(listener.asBinder());
-                mGnssNavigationMessageProvider.removeListener(listener);
+        if (mGnssNavigationMessageProvider == null) {
+            return;
+        }
+
+        IBinder binder = listener.asBinder();
+        synchronized (mLock) {
+            LinkedListener<IGnssNavigationMessageListener> linkedListener =
+                    mGnssNavigationMessageListeners.remove(binder);
+            if (linkedListener == null) {
+                return;
             }
+            unlinkFromListenerDeathNotificationLocked(binder, linkedListener);
+            mGnssNavigationMessageProvider.removeListener(listener);
         }
     }
 
@@ -3368,18 +3471,14 @@
                     pw.println("      " + record);
                 }
             }
+
             pw.println("  Active GnssMeasurement Listeners:");
-            for (CallerIdentity callerIdentity : mGnssMeasurementsListeners.values()) {
-                pw.println("    " + callerIdentity.mPid + " " + callerIdentity.mUid + " "
-                        + callerIdentity.mPackageName + ": "
-                        + isThrottlingExemptLocked(callerIdentity));
-            }
+            dumpGnssDataListenersLocked(pw, mGnssMeasurementsListeners);
             pw.println("  Active GnssNavigationMessage Listeners:");
-            for (CallerIdentity callerIdentity : mGnssNavigationMessageListeners.values()) {
-                pw.println("    " + callerIdentity.mPid + " " + callerIdentity.mUid + " "
-                        + callerIdentity.mPackageName + ": "
-                        + isThrottlingExemptLocked(callerIdentity));
-            }
+            dumpGnssDataListenersLocked(pw, mGnssNavigationMessageListeners);
+            pw.println("  Active GnssStatus Listeners:");
+            dumpGnssDataListenersLocked(pw, mGnssStatusListeners);
+
             pw.println("  Historical Records by Provider:");
             for (Map.Entry<PackageProviderKey, PackageStatistics> entry
                     : mRequestStatistics.statistics.entrySet()) {
@@ -3432,4 +3531,15 @@
             }
         }
     }
+
+    @GuardedBy("mLock")
+    private void dumpGnssDataListenersLocked(PrintWriter pw,
+            ArrayMap<IBinder, ? extends LinkedListenerBase> gnssDataListeners) {
+        for (LinkedListenerBase listener : gnssDataListeners.values()) {
+            CallerIdentity callerIdentity = listener.mCallerIdentity;
+            pw.println("    " + callerIdentity.mPid + " " + callerIdentity.mUid + " "
+                    + callerIdentity.mPackageName + ": "
+                    + isThrottlingExemptLocked(callerIdentity));
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index e7d7434..5da281a 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -860,7 +860,7 @@
         } else if (remote == 1) {
             res = true;
         } else {
-            res = false;
+            res = true;
         }
 
         Slog.d(TAG, "Isolated storage local flag " + local + " and remote flag "
@@ -1533,7 +1533,7 @@
 
         // Snapshot feature flag used for this boot
         SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
-                SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, false)));
+                SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));
 
         mContext = context;
         mResolver = mContext.getContentResolver();
diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
index 3939bee..9bbc315 100644
--- a/services/core/java/com/android/server/WiredAccessoryManager.java
+++ b/services/core/java/com/android/server/WiredAccessoryManager.java
@@ -23,6 +23,7 @@
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
 import android.os.UEventObserver;
+import android.util.Pair;
 import android.util.Slog;
 import android.media.AudioManager;
 import android.util.Log;
@@ -31,6 +32,7 @@
 import com.android.internal.R;
 import com.android.server.input.InputManagerService;
 import com.android.server.input.InputManagerService.WiredAccessoryCallbacks;
+
 import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT;
 import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT;
 import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT;
@@ -41,6 +43,7 @@
 import java.io.File;
 import java.io.FileReader;
 import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
@@ -52,7 +55,7 @@
  */
 final class WiredAccessoryManager implements WiredAccessoryCallbacks {
     private static final String TAG = WiredAccessoryManager.class.getSimpleName();
-    private static final boolean LOG = true;
+    private static final boolean LOG = false;
 
     private static final int BIT_HEADSET = (1 << 0);
     private static final int BIT_HEADSET_NO_MIC = (1 << 1);
@@ -60,9 +63,9 @@
     private static final int BIT_USB_HEADSET_DGTL = (1 << 3);
     private static final int BIT_HDMI_AUDIO = (1 << 4);
     private static final int BIT_LINEOUT = (1 << 5);
-    private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC|
-                                                   BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL|
-                                                   BIT_HDMI_AUDIO|BIT_LINEOUT);
+    private static final int SUPPORTED_HEADSETS = (BIT_HEADSET | BIT_HEADSET_NO_MIC |
+            BIT_USB_HEADSET_ANLG | BIT_USB_HEADSET_DGTL |
+            BIT_HDMI_AUDIO | BIT_LINEOUT);
 
     private static final String NAME_H2W = "h2w";
     private static final String NAME_USB_AUDIO = "usb_audio";
@@ -82,30 +85,34 @@
     private int mSwitchValues;
 
     private final WiredAccessoryObserver mObserver;
+    private final WiredAccessoryExtconObserver mExtconObserver;
     private final InputManagerService mInputManager;
 
     private final boolean mUseDevInputEventForAudioJack;
 
     public WiredAccessoryManager(Context context, InputManagerService inputManager) {
-        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryManager");
         mWakeLock.setReferenceCounted(false);
-        mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
+        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mInputManager = inputManager;
 
         mUseDevInputEventForAudioJack =
                 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
 
+        mExtconObserver = new WiredAccessoryExtconObserver();
         mObserver = new WiredAccessoryObserver();
     }
 
     private void onSystemReady() {
         if (mUseDevInputEventForAudioJack) {
             int switchValues = 0;
-            if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) {
+            if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT)
+                    == 1) {
                 switchValues |= SW_HEADPHONE_INSERT_BIT;
             }
-            if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) {
+            if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT)
+                    == 1) {
                 switchValues |= SW_MICROPHONE_INSERT_BIT;
             }
             if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_LINEOUT_INSERT) == 1) {
@@ -115,20 +122,31 @@
                     SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT);
         }
 
-        mObserver.init();
+
+        if (ExtconUEventObserver.extconExists()) {
+            if (mUseDevInputEventForAudioJack) {
+                Log.w(TAG, "Both input event and extcon are used for audio jack,"
+                        + " please just choose one.");
+            }
+            mExtconObserver.init();
+        } else {
+            mObserver.init();
+        }
     }
 
     @Override
     public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask) {
-        if (LOG) Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos
-                + " bits=" + switchCodeToString(switchValues, switchMask)
-                + " mask=" + Integer.toHexString(switchMask));
+        if (LOG) {
+            Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos
+                    + " bits=" + switchCodeToString(switchValues, switchMask)
+                    + " mask=" + Integer.toHexString(switchMask));
+        }
 
         synchronized (mLock) {
             int headset;
             mSwitchValues = (mSwitchValues & ~switchMask) | switchValues;
             switch (mSwitchValues &
-                (SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT)) {
+                    (SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT)) {
                 case 0:
                     headset = 0;
                     break;
@@ -155,7 +173,7 @@
             }
 
             updateLocked(NAME_H2W,
-                (mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT)) | headset);
+                    (mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT)) | headset);
         }
     }
 
@@ -175,7 +193,7 @@
      * results in support for the last one plugged in. Similarly, unplugging either is seen as
      * unplugging all.
      *
-     * @param newName One of the NAME_xxx variables defined above.
+     * @param newName  One of the NAME_xxx variables defined above.
      * @param newState 0 or one of the BIT_xxx variables defined above.
      */
     private void updateLocked(String newName, int newState) {
@@ -186,10 +204,12 @@
         int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT);
         boolean h2wStateChange = true;
         boolean usbStateChange = true;
-        if (LOG) Slog.v(TAG, "newName=" + newName
-                + " newState=" + newState
-                + " headsetState=" + headsetState
-                + " prev headsetState=" + mHeadsetState);
+        if (LOG) {
+            Slog.v(TAG, "newName=" + newName
+                    + " newState=" + newState
+                    + " headsetState=" + headsetState
+                    + " prev headsetState=" + mHeadsetState);
+        }
 
         if (mHeadsetState == headsetState) {
             Log.e(TAG, "No state change.");
@@ -229,7 +249,7 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_NEW_DEVICE_STATE:
-                    setDevicesState(msg.arg1, msg.arg2, (String)msg.obj);
+                    setDevicesState(msg.arg1, msg.arg2, (String) msg.obj);
                     mWakeLock.release();
                     break;
                 case MSG_SYSTEM_READY:
@@ -269,9 +289,9 @@
             if (headset == BIT_HEADSET) {
                 outDevice = AudioManager.DEVICE_OUT_WIRED_HEADSET;
                 inDevice = AudioManager.DEVICE_IN_WIRED_HEADSET;
-            } else if (headset == BIT_HEADSET_NO_MIC){
+            } else if (headset == BIT_HEADSET_NO_MIC) {
                 outDevice = AudioManager.DEVICE_OUT_WIRED_HEADPHONE;
-            } else if (headset == BIT_LINEOUT){
+            } else if (headset == BIT_LINEOUT) {
                 outDevice = AudioManager.DEVICE_OUT_LINE;
             } else if (headset == BIT_USB_HEADSET_ANLG) {
                 outDevice = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET;
@@ -280,7 +300,7 @@
             } else if (headset == BIT_HDMI_AUDIO) {
                 outDevice = AudioManager.DEVICE_OUT_HDMI;
             } else {
-                Slog.e(TAG, "setDeviceState() invalid headset type: "+headset);
+                Slog.e(TAG, "setDeviceState() invalid headset type: " + headset);
                 return;
             }
 
@@ -290,10 +310,10 @@
             }
 
             if (outDevice != 0) {
-              mAudioManager.setWiredDeviceConnectionState(outDevice, state, "", headsetName);
+                mAudioManager.setWiredDeviceConnectionState(outDevice, state, "", headsetName);
             }
             if (inDevice != 0) {
-              mAudioManager.setWiredDeviceConnectionState(inDevice, state, "", headsetName);
+                mAudioManager.setWiredDeviceConnectionState(inDevice, state, "", headsetName);
             }
         }
     }
@@ -340,7 +360,7 @@
                                 " not found while attempting to determine initial switch state");
                     } catch (Exception e) {
                         Slog.e(TAG, "Error while attempting to determine initial switch state for "
-                                + uei.getDevName() , e);
+                                + uei.getDevName(), e);
                     }
                 }
             }
@@ -350,7 +370,7 @@
             // observe three UEVENTs
             for (int i = 0; i < mUEventInfo.size(); ++i) {
                 UEventInfo uei = mUEventInfo.get(i);
-                startObserving("DEVPATH="+uei.getDevPath());
+                startObserving("DEVPATH=" + uei.getDevPath());
             }
         }
 
@@ -438,7 +458,9 @@
                 mStateNbits = stateNbits;
             }
 
-            public String getDevName() { return mDevName; }
+            public String getDevName() {
+                return mDevName;
+            }
 
             public String getDevPath() {
                 return String.format(Locale.US, "/devices/virtual/switch/%s", mDevName);
@@ -456,11 +478,84 @@
             public int computeNewHeadsetState(int headsetState, int switchState) {
                 int preserveMask = ~(mState1Bits | mState2Bits | mStateNbits);
                 int setBits = ((switchState == 1) ? mState1Bits :
-                              ((switchState == 2) ? mState2Bits :
-                              ((switchState == mStateNbits) ? mStateNbits : 0)));
+                        ((switchState == 2) ? mState2Bits :
+                                ((switchState == mStateNbits) ? mStateNbits : 0)));
 
                 return ((headsetState & preserveMask) | setBits);
             }
         }
     }
+
+    private class WiredAccessoryExtconObserver extends ExtconStateObserver<Pair<Integer, Integer>> {
+        private final List<ExtconInfo> mExtconInfos;
+
+        WiredAccessoryExtconObserver() {
+            mExtconInfos = ExtconInfo.getExtconInfos(".*audio.*");
+
+        }
+
+        private void init() {
+            for (ExtconInfo extconInfo : mExtconInfos) {
+                Pair<Integer, Integer> state = null;
+                try {
+                    state = parseStateFromFile(extconInfo);
+                } catch (FileNotFoundException e) {
+                    Slog.w(TAG, extconInfo.getStatePath()
+                            + " not found while attempting to determine initial state", e);
+                } catch (IOException e) {
+                    Slog.e(
+                            TAG,
+                            "Error reading " + extconInfo.getStatePath()
+                                    + " while attempting to determine initial state",
+                            e);
+                }
+                if (state != null) {
+                    updateState(extconInfo, extconInfo.getName(), state);
+                }
+                if (LOG) Slog.d(TAG, "observing " + extconInfo.getName());
+                startObserving(extconInfo);
+            }
+
+        }
+
+        @Override
+        public Pair<Integer, Integer> parseState(ExtconInfo extconInfo, String status) {
+            if (LOG) Slog.v(TAG, "status  " + status);
+            int []maskAndState = {0,0};
+            // extcon event state changes from kernel4.9
+            // new state will be like STATE=MICROPHONE=1\nHEADPHONE=0
+            updateBit(maskAndState, BIT_HEADSET_NO_MIC, status, "HEADPHONE") ;
+            updateBit(maskAndState, BIT_HEADSET, status,"MICROPHONE") ;
+            updateBit(maskAndState, BIT_HDMI_AUDIO, status,"HDMI") ;
+            updateBit(maskAndState, BIT_LINEOUT, status,"LINE-OUT") ;
+            if (LOG) Slog.v(TAG, "mask " + maskAndState[0] + " state " + maskAndState[1]);
+            return Pair.create(maskAndState[0],maskAndState[1]);
+        }
+
+        @Override
+        public void updateState(ExtconInfo extconInfo, String name,
+                Pair<Integer, Integer> maskAndState) {
+            synchronized (mLock) {
+                int mask = maskAndState.first;
+                int state = maskAndState.second;
+                updateLocked(name, mHeadsetState | (mask & state) & ~(mask & ~state));
+                return;
+            }
+        }
+    }
+
+    /**
+     * Updates the mask bit at {@code position} to 1 and the state bit at {@code position} to true
+     * if {@code name=1}  or false if {}@code name=0} is contained in {@code state}.
+     */
+    private static void updateBit(int[] maskAndState, int position, String state, String name) {
+        maskAndState[0] |= position;
+        if (state.contains(name + "=1")) {
+            maskAndState[0] |= position;
+            maskAndState[1] |= position;
+        } else if (state.contains(name + "=0")) {
+            maskAndState[0] |= position;
+            maskAndState[1] &= ~position;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 60a45bf..c4a9db6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6630,8 +6630,7 @@
 
                 String msg;
                 if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
-                    throw new SecurityException("Content provider lookup "
-                            + cpr.name.flattenToShortString()
+                    throw new SecurityException("Content provider lookup " + name
                             + " failed: association not allowed with package " + msg);
                 }
                 checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 0194624..8ffb67a 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -65,6 +65,8 @@
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES, String.class);
         sGlobalSettingToTypeMap.put(
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST, String.class);
+        sGlobalSettingToTypeMap.put(
+                Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_APP, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS, String.class);
@@ -76,6 +78,7 @@
         sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_OPT_OUT_APPS, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_BLACKLIST, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_WHITELIST, String.class);
+        sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_BLACKLISTS, String.class);
         // add other global settings here...
     }
 
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index f01305e..0d49e4c 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1681,7 +1681,8 @@
     public void killAppZygoteIfNeededLocked(AppZygote appZygote) {
         final ApplicationInfo appInfo = appZygote.getAppInfo();
         ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote);
-        if (zygoteProcesses.size() == 0) { // Only remove if no longer in use now
+        if (zygoteProcesses != null && zygoteProcesses.size() == 0) {
+            // Only remove if no longer in use now
             mAppZygotes.remove(appInfo.processName, appInfo.uid);
             mAppZygoteProcesses.remove(appZygote);
             mAppIsolatedUidRangeAllocator.freeUidRangeLocked(appInfo);
@@ -1703,6 +1704,7 @@
             ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote);
             zygoteProcesses.remove(app);
             if (zygoteProcesses.size() == 0) {
+                mService.mHandler.removeMessages(KILL_APP_ZYGOTE_MSG);
                 Message msg = mService.mHandler.obtainMessage(KILL_APP_ZYGOTE_MSG);
                 msg.obj = appZygote;
                 mService.mHandler.sendMessageDelayed(msg, KILL_APP_ZYGOTE_DELAY_MS);
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 8995068..eab3820 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -588,6 +588,11 @@
                         throws RemoteException {
                     // TODO
                 }
+
+                @Override
+                public void onLockoutChanged(long duration) {
+
+                }
             };
 
     /**
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 6ee5665..e9ae516 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -19,6 +19,7 @@
 import android.graphics.Rect;
 import android.hardware.display.DisplayViewport;
 import android.os.IBinder;
+import android.view.DisplayAddress;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
@@ -225,8 +226,12 @@
         viewport.deviceHeight = isRotated ? info.width : info.height;
 
         viewport.uniqueId = info.uniqueId;
-        // TODO(b/112898898) Use an actual port here.
-        viewport.physicalPort = null;
+
+        if (info.address instanceof DisplayAddress.Physical) {
+            viewport.physicalPort = ((DisplayAddress.Physical) info.address).getPort();
+        } else {
+            viewport.physicalPort = null;
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index ab64f61..729ea17 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -19,6 +19,7 @@
 import android.hardware.display.DisplayViewport;
 import android.util.DisplayMetrics;
 import android.view.Display;
+import android.view.DisplayAddress;
 import android.view.DisplayCutout;
 import android.view.Surface;
 
@@ -274,7 +275,7 @@
      * Display address, or null if none.
      * Interpretation varies by display type.
      */
-    public String address;
+    public DisplayAddress address;
 
     /**
      * Display state.
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 80ea1da..b99ba7e 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1336,7 +1336,7 @@
                 && !TextUtils.isEmpty(info.uniqueId)) {
             viewportType = VIEWPORT_VIRTUAL;
         } else {
-            Slog.wtf(TAG, "Unable to populate viewport for display device: " + info);
+            Slog.i(TAG, "Display " + info + " does not support input device matching.");
             return;
         }
 
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 28f21f63..4891947 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -31,6 +31,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
+import android.view.DisplayAddress;
 import android.view.DisplayCutout;
 import android.view.DisplayEventReceiver;
 import android.view.Surface;
@@ -382,6 +383,7 @@
                 mInfo.presentationDeadlineNanos = phys.presentationDeadlineNanos;
                 mInfo.state = mState;
                 mInfo.uniqueId = getUniqueId();
+                mInfo.address = DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
 
                 // Assume that all built-in displays that have secure output (eg. HDCP) also
                 // support compositing from gralloc protected buffers.
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index e8d6ad4..9e4c1cb 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -16,9 +16,6 @@
 
 package com.android.server.display;
 
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.IndentingPrintWriter;
-
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -35,9 +32,13 @@
 import android.os.UserHandle;
 import android.util.Slog;
 import android.view.Display;
+import android.view.DisplayAddress;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -581,7 +582,7 @@
         private final int mHeight;
         private final float mRefreshRate;
         private final int mFlags;
-        private final String mAddress;
+        private final DisplayAddress mAddress;
         private final Display.Mode mMode;
 
         private Surface mSurface;
@@ -596,7 +597,7 @@
             mHeight = height;
             mRefreshRate = refreshRate;
             mFlags = flags;
-            mAddress = address;
+            mAddress = DisplayAddress.fromMacAddress(address);
             mSurface = surface;
             mMode = createMode(width, height, refreshRate);
         }
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
index 7ae00af..b9aa34e8 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.util.Slog;
+import android.util.Spline;
 
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
@@ -75,6 +76,9 @@
     // Override the ambient color temperature for debugging purposes.
     private float mAmbientColorTemperatureOverride;
 
+    // A piecewise linear relationship between ambient and display color temperatures
+    private Spline.LinearSpline mAmbientToDisplayTemperatureSpline;
+
     /**
      * @param brightnessSensor
      *      The sensor used to detect changes in the ambient brightness.
@@ -109,7 +113,8 @@
             @NonNull AmbientSensor.AmbientColorTemperatureSensor colorTemperatureSensor,
             @NonNull AmbientFilter colorTemperatureFilter,
             @NonNull DisplayWhiteBalanceThrottler throttler,
-            float lowLightAmbientBrightnessThreshold, float lowLightAmbientColorTemperature) {
+            float lowLightAmbientBrightnessThreshold, float lowLightAmbientColorTemperature,
+            float[] ambientTemperatures, float[] displayTemperatures) {
         validateArguments(brightnessSensor, brightnessFilter, colorTemperatureSensor,
                 colorTemperatureFilter, throttler);
         mLoggingEnabled = false;
@@ -127,6 +132,14 @@
         mLastAmbientColorTemperature = -1.0f;
         mAmbientColorTemperatureHistory = new History(HISTORY_SIZE);
         mAmbientColorTemperatureOverride = -1.0f;
+
+        try {
+            mAmbientToDisplayTemperatureSpline = new Spline.LinearSpline(ambientTemperatures,
+                    displayTemperatures);
+        } catch (Exception e) {
+            mAmbientToDisplayTemperatureSpline = null;
+        }
+
         mColorDisplayServiceInternal = LocalServices.getService(ColorDisplayServiceInternal.class);
     }
 
@@ -227,6 +240,9 @@
         writer.println("  mLastAmbientColorTemperature=" + mLastAmbientColorTemperature);
         writer.println("  mAmbientColorTemperatureHistory=" + mAmbientColorTemperatureHistory);
         writer.println("  mAmbientColorTemperatureOverride=" + mAmbientColorTemperatureOverride);
+        writer.println("  mAmbientToDisplayTemperatureSpline="
+                + (mAmbientToDisplayTemperatureSpline == null ? "unused" :
+                    mAmbientToDisplayTemperatureSpline));
     }
 
     @Override // AmbientSensor.AmbientBrightnessSensor.Callbacks
@@ -250,6 +266,11 @@
         final long time = System.currentTimeMillis();
         float ambientColorTemperature = mColorTemperatureFilter.getEstimate(time);
 
+        if (mAmbientToDisplayTemperatureSpline != null) {
+            ambientColorTemperature =
+                mAmbientToDisplayTemperatureSpline.interpolate(ambientColorTemperature);
+        }
+
         final float ambientBrightness = mBrightnessFilter.getEstimate(time);
         if (ambientBrightness < mLowLightAmbientBrightnessThreshold) {
             if (mLoggingEnabled) {
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
index fd78ddb..56f4ca3 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
@@ -67,9 +67,14 @@
         final float lowLightAmbientColorTemperature = getFloat(resources,
                 com.android.internal.R.dimen
                 .config_displayWhiteBalanceLowLightAmbientColorTemperature);
+        final float[] ambientTemperatures = getFloatArray(resources,
+                com.android.internal.R.array.config_displayWhiteBalanceAmbientTemperatureValues);
+        final float[] displayTemperatures = getFloatArray(resources,
+                com.android.internal.R.array.config_displayWhiteBalanceDisplayTemperatureValues);
         final DisplayWhiteBalanceController controller = new DisplayWhiteBalanceController(
                 brightnessSensor, brightnessFilter, colorTemperatureSensor, colorTemperatureFilter,
-                throttler, lowLightAmbientBrightnessThreshold, lowLightAmbientColorTemperature);
+                throttler, lowLightAmbientBrightnessThreshold, lowLightAmbientColorTemperature,
+                ambientTemperatures, displayTemperatures);
         brightnessSensor.setCallbacks(controller);
         colorTemperatureSensor.setCallbacks(controller);
         return controller;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 20933db..560f7a0 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -342,7 +342,7 @@
         super.disableDevice(initiatedByCec, callback);
 
         assertRunOnServiceThread();
-        if (!initiatedByCec && mIsActiveSource) {
+        if (!initiatedByCec && mIsActiveSource && mService.isControlEnabled()) {
             mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(
                     mAddress, mService.getPhysicalAddress()));
         }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 5e7ea05..28393a2 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1805,9 +1805,10 @@
     }
 
     // Native callback.
-    private int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
+    private int interceptMotionBeforeQueueingNonInteractive(int displayId,
+            long whenNanos, int policyFlags) {
         return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
-                whenNanos, policyFlags);
+                displayId, whenNanos, policyFlags);
     }
 
     // Native callback.
@@ -2021,7 +2022,13 @@
 
         public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
 
-        public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
+        /**
+         * Provides an opportunity for the window manager policy to intercept early motion event
+         * processing when the device is in a non-interactive state since these events are normally
+         * dropped.
+         */
+        int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
+                int policyFlags);
 
         public long interceptKeyBeforeDispatching(IBinder token,
                 KeyEvent event, int policyFlags);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 2f0b388..3abacc2 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -976,7 +976,7 @@
         }
 
         if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
-        if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
+        if (mProviderRequest.reportLocation && isEnabled()) {
             // update client uids
             updateClientUids(mWorkSource);
 
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
index f03c99b..aa8a25a 100644
--- a/services/core/java/com/android/server/location/RemoteListenerHelper.java
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -31,9 +31,11 @@
 import java.util.Map;
 
 /**
- * A helper class, that handles operations in remote listeners, and tracks for remote process death.
+ * A helper class that handles operations in remote listeners.
+ *
+ * @param <TListener> the type of GNSS data listener.
  */
-abstract class RemoteListenerHelper<TListener extends IInterface> {
+public abstract class RemoteListenerHelper<TListener extends IInterface> {
 
     protected static final int RESULT_SUCCESS = 0;
     protected static final int RESULT_NOT_AVAILABLE = 1;
@@ -46,7 +48,7 @@
     protected final Handler mHandler;
     private final String mTag;
 
-    private final Map<IBinder, LinkedListener> mListenerMap = new HashMap<>();
+    private final Map<IBinder, IdentifiedListener> mListenerMap = new HashMap<>();
 
     protected final Context mContext;
     protected final AppOpsManager mAppOps;
@@ -71,24 +73,21 @@
         return mIsRegistered;
     }
 
-    public boolean addListener(@NonNull TListener listener, CallerIdentity callerIdentity) {
+    /**
+     * Adds GNSS data listener {@code listener} with caller identify {@code callerIdentify}.
+     */
+    public void addListener(@NonNull TListener listener, CallerIdentity callerIdentity) {
         Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener.");
         IBinder binder = listener.asBinder();
-        LinkedListener deathListener = new LinkedListener(listener, callerIdentity);
         synchronized (mListenerMap) {
             if (mListenerMap.containsKey(binder)) {
                 // listener already added
-                return true;
+                return;
             }
-            try {
-                binder.linkToDeath(deathListener, 0 /* flags */);
-            } catch (RemoteException e) {
-                // if the remote process registering the listener is already death, just swallow the
-                // exception and return
-                Log.v(mTag, "Remote listener already died.", e);
-                return false;
-            }
-            mListenerMap.put(binder, deathListener);
+
+            IdentifiedListener identifiedListener = new IdentifiedListener(listener,
+                    callerIdentity);
+            mListenerMap.put(binder, identifiedListener);
 
             // update statuses we already know about, starting from the ones that will never change
             int result;
@@ -107,26 +106,23 @@
             } else {
                 // at this point if the supported flag is not set, the notification will be sent
                 // asynchronously in the future
-                return true;
+                return;
             }
-            post(deathListener, getHandlerOperation(result));
+            post(identifiedListener, getHandlerOperation(result));
         }
-        return true;
     }
 
+    /**
+     * Remove GNSS data listener {@code listener}.
+     */
     public void removeListener(@NonNull TListener listener) {
         Preconditions.checkNotNull(listener, "Attempted to remove a 'null' listener.");
-        IBinder binder = listener.asBinder();
-        LinkedListener linkedListener;
         synchronized (mListenerMap) {
-            linkedListener = mListenerMap.remove(binder);
+            mListenerMap.remove(listener.asBinder());
             if (mListenerMap.isEmpty()) {
                 tryUnregister();
             }
         }
-        if (linkedListener != null) {
-            binder.unlinkToDeath(linkedListener, 0 /* flags */);
-        }
     }
 
     protected abstract boolean isAvailableInPlatform();
@@ -198,14 +194,15 @@
     }
 
     private void foreachUnsafe(ListenerOperation<TListener> operation) {
-        for (LinkedListener linkedListener : mListenerMap.values()) {
-            post(linkedListener, operation);
+        for (IdentifiedListener identifiedListener : mListenerMap.values()) {
+            post(identifiedListener, operation);
         }
     }
 
-    private void post(LinkedListener linkedListener, ListenerOperation<TListener> operation) {
+    private void post(IdentifiedListener identifiedListener,
+            ListenerOperation<TListener> operation) {
         if (operation != null) {
-            mHandler.post(new HandlerRunnable(linkedListener, operation));
+            mHandler.post(new HandlerRunnable(identifiedListener, operation));
         }
     }
 
@@ -259,35 +256,31 @@
         return RESULT_SUCCESS;
     }
 
-    private class LinkedListener implements IBinder.DeathRecipient {
+    private class IdentifiedListener {
         private final TListener mListener;
         private final CallerIdentity mCallerIdentity;
 
-        LinkedListener(@NonNull TListener listener, CallerIdentity callerIdentity) {
+        private IdentifiedListener(@NonNull TListener listener, CallerIdentity callerIdentity) {
             mListener = listener;
             mCallerIdentity = callerIdentity;
         }
-
-        @Override
-        public void binderDied() {
-            Log.d(mTag, "Remote Listener died: " + mListener);
-            removeListener(mListener);
-        }
     }
 
     private class HandlerRunnable implements Runnable {
-        private final LinkedListener mLinkedListener;
+        private final IdentifiedListener mIdentifiedListener;
         private final ListenerOperation<TListener> mOperation;
 
-        HandlerRunnable(LinkedListener linkedListener, ListenerOperation<TListener> operation) {
-            mLinkedListener = linkedListener;
+        private HandlerRunnable(IdentifiedListener identifiedListener,
+                ListenerOperation<TListener> operation) {
+            mIdentifiedListener = identifiedListener;
             mOperation = operation;
         }
 
         @Override
         public void run() {
             try {
-                mOperation.execute(mLinkedListener.mListener, mLinkedListener.mCallerIdentity);
+                mOperation.execute(mIdentifiedListener.mListener,
+                        mIdentifiedListener.mCallerIdentity);
             } catch (RemoteException e) {
                 Log.v(mTag, "Error in monitored listener.", e);
             }
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
index 5c73178..62d9b20 100644
--- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -284,13 +284,16 @@
      * Tells the system UI that volume has changed on an active remote session.
      */
     public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) {
-        if (mRvc == null || !session.isActive()) {
-            return;
-        }
-        try {
-            mRvc.remoteVolumeChanged(session.getSessionToken(), flags);
-        } catch (Exception e) {
-            Log.wtf(TAG, "Error sending volume change to system UI.", e);
+        synchronized (mLock) {
+            if (mRvc == null || !session.isActive()) {
+                return;
+            }
+            try {
+                mRvc.remoteVolumeChanged(session.getSessionToken(), flags);
+            } catch (Exception e) {
+                Log.w(TAG, "Error sending volume change to system UI.", e);
+                mRvc = null;
+            }
         }
     }
 
@@ -563,7 +566,7 @@
             String callerPackageName, SessionCallbackLink cb, String tag) {
         FullUserRecord user = getFullUserRecordLocked(userId);
         if (user == null) {
-            Log.wtf(TAG, "Request from invalid user: " +  userId);
+            Log.w(TAG, "Request from invalid user: " +  userId + ", pkg=" + callerPackageName);
             throw new RuntimeException("Session request from invalid user.");
         }
 
@@ -643,7 +646,8 @@
                 MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
                 mRvc.updateRemoteController(record == null ? null : record.getSessionToken());
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error sending default remote volume to sys ui.", e);
+                Log.w(TAG, "Error sending default remote volume to sys ui.", e);
+                mRvc = null;
             }
         }
     }
@@ -1661,7 +1665,9 @@
             final long token = Binder.clearCallingIdentity();
             try {
                 enforceSystemUiPermission("listen for volume changes", pid, uid);
-                mRvc = rvc;
+                synchronized (mLock) {
+                    mRvc = rvc;
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
new file mode 100644
index 0000000..dac4b6f
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -0,0 +1,221 @@
+/*
+ * 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.s
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.apex.ApexInfo;
+import android.apex.ApexInfoList;
+import android.apex.ApexSessionInfo;
+import android.apex.IApexService;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageParserException;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * ApexManager class handles communications with the apex service to perform operation and queries,
+ * as well as providing caching to avoid unnecessary calls to the service.
+ */
+class ApexManager {
+    static final String TAG = "ApexManager";
+    private final IApexService mApexService;
+    private final Map<String, PackageInfo> mActivePackagesCache;
+
+    ApexManager() {
+        mApexService = IApexService.Stub.asInterface(
+            ServiceManager.getService("apexservice"));
+        mActivePackagesCache = populateActivePackagesCache();
+    }
+
+    @NonNull
+    private Map<String, PackageInfo> populateActivePackagesCache() {
+        try {
+            List<PackageInfo> list = new ArrayList<>();
+            final ApexInfo[] activePkgs = mApexService.getActivePackages();
+            for (ApexInfo ai : activePkgs) {
+                // If the device is using flattened APEX, don't report any APEX
+                // packages since they won't be managed or updated by PackageManager.
+                if ((new File(ai.packagePath)).isDirectory()) {
+                    break;
+                }
+                try {
+                    list.add(PackageParser.generatePackageInfoFromApex(
+                            new File(ai.packagePath), true /* collect certs */));
+                } catch (PackageParserException pe) {
+                    throw new IllegalStateException("Unable to parse: " + ai, pe);
+                }
+            }
+            return list.stream().collect(Collectors.toMap(p -> p.packageName, Function.identity()));
+        } catch (RemoteException re) {
+            Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
+            throw new RuntimeException(re);
+        }
+    }
+
+    /**
+     * Retrieves information about an active APEX package.
+     *
+     * @param packageName the package name to look for. Note that this is the package name reported
+     *                    in the APK container manifest (i.e. AndroidManifest.xml), which might
+     *                    differ from the one reported in the APEX manifest (i.e.
+     *                    apex_manifest.json).
+     * @return a PackageInfo object with the information about the package, or null if the package
+     *         is not found.
+     */
+    @Nullable PackageInfo getActivePackage(String packageName) {
+        return mActivePackagesCache.get(packageName);
+    }
+
+    /**
+     * Retrieves information about all active APEX packages.
+     *
+     * @return a Collection of PackageInfo object, each one containing information about a different
+     *         active package.
+     */
+    Collection<PackageInfo> getActivePackages() {
+        return mActivePackagesCache.values();
+    }
+
+    /**
+     * Retrieves information about an apexd staged session i.e. the internal state used by apexd to
+     * track the different states of a session.
+     *
+     * @param sessionId the identifier of the session.
+     * @return an ApexSessionInfo object, or null if the session is not known.
+     */
+    @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
+        try {
+            ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId);
+            if (apexSessionInfo.isUnknown) {
+                return null;
+            }
+            return apexSessionInfo;
+        } catch (RemoteException re) {
+            Slog.e(TAG, "Unable to contact apexservice", re);
+            throw new RuntimeException(re);
+        }
+    }
+
+    /**
+     * Submit a staged session to apex service. This causes the apex service to perform some initial
+     * verification and accept or reject the session. Submitting a session successfully is not
+     * enough for it to be activated at the next boot, the caller needs to call
+     * {@link #markStagedSessionReady(int)}.
+     *
+     * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted.
+     * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain
+     *                        an array of identifiers of all the child sessions. Otherwise it should
+     *                        be an empty array.
+     * @param apexInfoList this is an output parameter, which needs to be initialized by tha caller
+     *                     and will be filled with a list of {@link ApexInfo} objects, each of which
+     *                     contains metadata about one of the packages being submitted as part of
+     *                     the session.
+     * @return whether the submission of the session was successful.
+     */
+    boolean submitStagedSession(
+            int sessionId, @NonNull int[] childSessionIds, @NonNull ApexInfoList apexInfoList) {
+        try {
+            return mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList);
+        } catch (RemoteException re) {
+            Slog.e(TAG, "Unable to contact apexservice", re);
+            throw new RuntimeException(re);
+        }
+    }
+
+    /**
+     * Mark a staged session previously submitted using {@cde submitStagedSession} as ready to be
+     * applied at next reboot.
+     *
+     * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready.
+     * @return true upon success, false if the session is unknown.
+     */
+    boolean markStagedSessionReady(int sessionId) {
+        try {
+            return mApexService.markStagedSessionReady(sessionId);
+        } catch (RemoteException re) {
+            Slog.e(TAG, "Unable to contact apexservice", re);
+            throw new RuntimeException(re);
+        }
+    }
+
+    /**
+     * Dumps various state information to the provided {@link PrintWriter} object.
+     *
+     * @param pw the {@link PrintWriter} object to send information to.
+     * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
+     *                    information about that specific package will be dumped.
+     */
+    void dump(PrintWriter pw, @Nullable String packageName) {
+        final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
+        ipw.println();
+        ipw.println("Active APEX packages:");
+        ipw.increaseIndent();
+        try {
+            populateActivePackagesCache();
+            for (PackageInfo pi : mActivePackagesCache.values()) {
+                if (packageName != null && !packageName.equals(pi.packageName)) {
+                    continue;
+                }
+                ipw.println(pi.packageName);
+                ipw.increaseIndent();
+                ipw.println("Version: " + pi.versionCode);
+                ipw.println("Path: " + pi.applicationInfo.sourceDir);
+                ipw.decreaseIndent();
+            }
+            ipw.decreaseIndent();
+            ipw.println();
+            ipw.println("APEX session state:");
+            ipw.increaseIndent();
+            final ApexSessionInfo[] sessions = mApexService.getSessions();
+            for (ApexSessionInfo si : sessions) {
+                ipw.println("Session ID: " + Integer.toString(si.sessionId));
+                ipw.increaseIndent();
+                if (si.isUnknown) {
+                    ipw.println("State: UNKNOWN");
+                } else if (si.isVerified) {
+                    ipw.println("State: VERIFIED");
+                } else if (si.isStaged) {
+                    ipw.println("State: STAGED");
+                } else if (si.isActivated) {
+                    ipw.println("State: ACTIVATED");
+                } else if (si.isActivationPendingRetry) {
+                    ipw.println("State: ACTIVATION PENDING RETRY");
+                } else if (si.isActivationFailed) {
+                    ipw.println("State: ACTIVATION FAILED");
+                }
+                ipw.decreaseIndent();
+            }
+            ipw.decreaseIndent();
+        } catch (RemoteException e) {
+            ipw.println("Couldn't communicate with apexd.");
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 21965e4..8608349 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -186,7 +186,7 @@
         }
     };
 
-    public PackageInstallerService(Context context, PackageManagerService pm) {
+    public PackageInstallerService(Context context, PackageManagerService pm, ApexManager am) {
         mContext = context;
         mPm = pm;
         mPermissionManager = LocalServices.getService(PermissionManagerInternal.class);
@@ -204,7 +204,7 @@
         mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
         mSessionsDir.mkdirs();
 
-        mStagingManager = new StagingManager(pm, this);
+        mStagingManager = new StagingManager(pm, this, am);
     }
 
     private void setBootCompleted()  {
@@ -481,6 +481,10 @@
             }
         }
 
+        if (params.isStaged) {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG);
+        }
+
         if (!params.isMultiPackage) {
             // Only system components can circumvent runtime permissions when installing.
             if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 874d1a7..400443a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -119,13 +119,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
-import android.apex.ApexInfo;
-import android.apex.ApexSessionInfo;
-import android.apex.IApexService;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AppDetailsActivity;
 import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
 import android.app.IActivityManager;
 import android.app.ResourcesManager;
 import android.app.admin.IDevicePolicyManager;
@@ -241,6 +239,7 @@
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
 import android.permission.PermissionControllerManager;
+import android.provider.DeviceConfig;
 import android.provider.MediaStore;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
@@ -733,10 +732,10 @@
     @GuardedBy("mPackages")
     final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>();
 
-    private PackageManager mPackageManager;
-
     private final ModuleInfoProvider mModuleInfoProvider;
 
+    private final ApexManager mApexManager;
+
     class PackageParserCallback implements PackageParser.Callback {
         @Override public final boolean hasFeature(String feature) {
             return PackageManagerService.this.hasSystemFeature(feature, 0);
@@ -1046,12 +1045,17 @@
             verificationIntent.setComponent(mIntentFilterVerifierComponent);
             verificationIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
 
+            final long whitelistTimeout = getVerificationTimeout();
+            final BroadcastOptions options = BroadcastOptions.makeBasic();
+            options.setTemporaryAppWhitelistDuration(whitelistTimeout);
+
             DeviceIdleController.LocalService idleController = getDeviceIdleController();
             idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
-                    mIntentFilterVerifierComponent.getPackageName(), getVerificationTimeout(),
+                    mIntentFilterVerifierComponent.getPackageName(), whitelistTimeout,
                     UserHandle.USER_SYSTEM, true, "intent filter verifier");
 
-            mContext.sendBroadcastAsUser(verificationIntent, UserHandle.SYSTEM);
+            mContext.sendBroadcastAsUser(verificationIntent, UserHandle.SYSTEM,
+                    null, options.toBundle());
             if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
                     "Sending IntentFilter verification broadcast");
         }
@@ -3074,7 +3078,8 @@
                 }
             }
 
-            mInstallerService = new PackageInstallerService(context, this);
+            mApexManager = new ApexManager();
+            mInstallerService = new PackageInstallerService(context, this, mApexManager);
             final Pair<ComponentName, String> instantAppResolverComponent =
                     getInstantAppResolverLPr();
             if (instantAppResolverComponent != null) {
@@ -3934,27 +3939,7 @@
             }
             //
             if (!matchFactoryOnly && (flags & MATCH_APEX) != 0) {
-                //TODO(b/123052859) Don't do file operations every time there is a query.
-                final IApexService apex = IApexService.Stub.asInterface(
-                        ServiceManager.getService("apexservice"));
-                if (apex != null) {
-                    try {
-                        final ApexInfo activePkg = apex.getActivePackage(packageName);
-                        if (activePkg != null && !TextUtils.isEmpty(activePkg.packagePath)) {
-                            try {
-                                return PackageParser.generatePackageInfoFromApex(
-                                        new File(activePkg.packagePath), true /* collect certs */);
-                            } catch (PackageParserException pe) {
-                                Log.e(TAG, "Unable to parse package at "
-                                        + activePkg.packagePath, pe);
-                            }
-                        }
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Unable to retrieve packages from apexservice: " + e.toString());
-                    }
-                } else {
-                    Log.e(TAG, "Unable to connect to apexservice for querying packages.");
-                }
+                return mApexManager.getActivePackage(packageName);
             }
         }
         return null;
@@ -7851,25 +7836,7 @@
             if (listApex) {
                 // TODO(b/119767311): include uninstalled/inactive APEX if
                 //  MATCH_UNINSTALLED_PACKAGES is set.
-                final IApexService apex = IApexService.Stub.asInterface(
-                        ServiceManager.getService("apexservice"));
-                if (apex != null) {
-                    try {
-                        final ApexInfo[] activePkgs = apex.getActivePackages();
-                        for (ApexInfo ai : activePkgs) {
-                            try {
-                                 list.add(PackageParser.generatePackageInfoFromApex(
-                                         new File(ai.packagePath), true /* collect certs */));
-                            } catch (PackageParserException pe) {
-                                 throw new IllegalStateException("Unable to parse: " + ai, pe);
-                            }
-                        }
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Unable to retrieve packages from apexservice: " + e.toString());
-                    }
-                } else {
-                    Log.e(TAG, "Unable to connect to apexservice for querying packages.");
-                }
+                list.addAll(mApexManager.getActivePackages());
             }
             return new ParceledListSlice<>(list);
         }
@@ -14604,14 +14571,19 @@
                             new BroadcastReceiver() {
                                 @Override
                                 public void onReceive(Context context, Intent intent) {
-                                    // TODO(ruhler) b/112431924 Have a configurable setting to
-                                    // allow changing the timeout and fall back to the default
-                                    // if no such specified.
+                                    // the duration to wait for rollback to be enabled, in millis
+                                    long rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT;
+                                    try {
+                                        rollbackTimeout = Long.valueOf(
+                                            DeviceConfig.getProperty(
+                                                DeviceConfig.Rollback.NAMESPACE,
+                                                DeviceConfig.Rollback.ENABLE_ROLLBACK_TIMEOUT));
+                                    } catch (NumberFormatException ignore) {
+                                    }
                                     final Message msg = mHandler.obtainMessage(
                                             ENABLE_ROLLBACK_TIMEOUT);
                                     msg.arg1 = enableRollbackToken;
-                                    mHandler.sendMessageDelayed(msg,
-                                            DEFAULT_ENABLE_ROLLBACK_TIMEOUT);
+                                    mHandler.sendMessageDelayed(msg, rollbackTimeout);
                                 }
                             }, null, 0, null, null);
 
@@ -21319,51 +21291,7 @@
         }
 
         if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX)) {
-            final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
-            ipw.println();
-            ipw.println("Active APEX packages:");
-            ipw.increaseIndent();
-            final IApexService apex = IApexService.Stub.asInterface(
-                    ServiceManager.getService("apexservice"));
-            try {
-                final ApexInfo[] activeApexes = apex.getActivePackages();
-                for (ApexInfo ai : activeApexes) {
-                    if (packageName != null && !packageName.equals(ai.packageName)) {
-                        continue;
-                    }
-                    ipw.println(ai.packageName);
-                    ipw.increaseIndent();
-                    ipw.println("Version: " + Long.toString(ai.versionCode));
-                    ipw.println("Path: " + ai.packagePath);
-                    ipw.decreaseIndent();
-                }
-                ipw.decreaseIndent();
-                ipw.println();
-                ipw.println("APEX session state:");
-                ipw.increaseIndent();
-                final ApexSessionInfo[] sessions = apex.getSessions();
-                for (ApexSessionInfo si : sessions) {
-                    ipw.println("Session ID: " + Integer.toString(si.sessionId));
-                    ipw.increaseIndent();
-                    if (si.isUnknown) {
-                        ipw.println("State: UNKNOWN");
-                    } else if (si.isVerified) {
-                        ipw.println("State: VERIFIED");
-                    } else if (si.isStaged) {
-                        ipw.println("State: STAGED");
-                    } else if (si.isActivated) {
-                        ipw.println("State: ACTIVATED");
-                    } else if (si.isActivationPendingRetry) {
-                        ipw.println("State: ACTIVATION PENDING RETRY");
-                    } else if (si.isActivationFailed) {
-                        ipw.println("State: ACTIVATION FAILED");
-                    }
-                    ipw.decreaseIndent();
-                }
-                ipw.decreaseIndent();
-            } catch (RemoteException e) {
-                ipw.println("Couldn't communicate with apexd.");
-            }
+            mApexManager.dump(pw, packageName);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 84c8b60..d9a5eb9 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -18,6 +18,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.Person;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -33,6 +34,7 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.server.pm.ShortcutService.DumpFilter;
@@ -71,6 +73,7 @@
     private static final String TAG_EXTRAS = "extras";
     private static final String TAG_SHORTCUT = "shortcut";
     private static final String TAG_CATEGORIES = "categories";
+    private static final String TAG_PERSON = "person";
 
     private static final String ATTR_NAME = "name";
     private static final String ATTR_CALL_COUNT = "call-count";
@@ -96,6 +99,12 @@
     private static final String ATTR_ICON_RES_NAME = "icon-resname";
     private static final String ATTR_BITMAP_PATH = "bitmap-path";
 
+    private static final String ATTR_PERSON_NAME = "name";
+    private static final String ATTR_PERSON_URI = "uri";
+    private static final String ATTR_PERSON_KEY = "key";
+    private static final String ATTR_PERSON_IS_BOT = "is-bot";
+    private static final String ATTR_PERSON_IS_IMPORTANT = "is-important";
+
     private static final String NAME_CATEGORIES = "categories";
 
     private static final String TAG_STRING_ARRAY_XMLUTILS = "string-array";
@@ -1499,6 +1508,22 @@
                     out.endTag(null, TAG_CATEGORIES);
                 }
             }
+            if (!forBackup) {  // Don't backup the persons field.
+                final Person[] persons = si.getPersons();
+                if (!ArrayUtils.isEmpty(persons)) {
+                    for (int i = 0; i < persons.length; i++) {
+                        final Person p = persons[i];
+
+                        out.startTag(null, TAG_PERSON);
+                        ShortcutService.writeAttr(out, ATTR_PERSON_NAME, p.getName());
+                        ShortcutService.writeAttr(out, ATTR_PERSON_URI, p.getUri());
+                        ShortcutService.writeAttr(out, ATTR_PERSON_KEY, p.getKey());
+                        ShortcutService.writeAttr(out, ATTR_PERSON_IS_BOT, p.isBot());
+                        ShortcutService.writeAttr(out, ATTR_PERSON_IS_IMPORTANT, p.isImportant());
+                        out.endTag(null, TAG_PERSON);
+                    }
+                }
+            }
             final Intent[] intentsNoExtras = si.getIntentsNoExtras();
             final PersistableBundle[] intentsExtras = si.getIntentPersistableExtrases();
             final int numIntents = intentsNoExtras.length;
@@ -1588,6 +1613,7 @@
         String bitmapPath;
         int backupVersionCode;
         ArraySet<String> categories = null;
+        ArrayList<Person> persons = new ArrayList<>();
 
         id = ShortcutService.parseStringAttribute(parser, ATTR_ID);
         activityComponent = ShortcutService.parseComponentNameAttribute(parser,
@@ -1638,6 +1664,9 @@
                 case TAG_CATEGORIES:
                     // This just contains string-array.
                     continue;
+                case TAG_PERSON:
+                    persons.add(parsePerson(parser));
+                    continue;
                 case TAG_STRING_ARRAY_XMLUTILS:
                     if (NAME_CATEGORIES.equals(ShortcutService.parseStringAttribute(parser,
                             ATTR_NAME_XMLUTILS))) {
@@ -1680,7 +1709,8 @@
                 categories,
                 intents.toArray(new Intent[intents.size()]),
                 rank, extras, lastChangedTimestamp, flags,
-                iconResId, iconResName, bitmapPath, disabledReason);
+                iconResId, iconResName, bitmapPath, disabledReason,
+                persons.toArray(new Person[persons.size()]));
     }
 
     private static Intent parseIntent(XmlPullParser parser)
@@ -1713,6 +1743,20 @@
         return intent;
     }
 
+    private static Person parsePerson(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        CharSequence name = ShortcutService.parseStringAttribute(parser, ATTR_PERSON_NAME);
+        String uri = ShortcutService.parseStringAttribute(parser, ATTR_PERSON_URI);
+        String key = ShortcutService.parseStringAttribute(parser, ATTR_PERSON_KEY);
+        boolean isBot = ShortcutService.parseBooleanAttribute(parser, ATTR_PERSON_IS_BOT);
+        boolean isImportant = ShortcutService.parseBooleanAttribute(parser,
+                ATTR_PERSON_IS_IMPORTANT);
+
+        Person.Builder builder = new Person.Builder();
+        builder.setName(name).setUri(uri).setKey(key).setBot(isBot).setImportant(isImportant);
+        return builder.build();
+    }
+
     @VisibleForTesting
     List<ShortcutInfo> getAllShortcutsForTest() {
         return new ArrayList<>(mShortcuts.values());
diff --git a/services/core/java/com/android/server/pm/ShortcutParser.java b/services/core/java/com/android/server/pm/ShortcutParser.java
index 90f08c3..668fc88 100644
--- a/services/core/java/com/android/server/pm/ShortcutParser.java
+++ b/services/core/java/com/android/server/pm/ShortcutParser.java
@@ -449,7 +449,8 @@
                 iconResId,
                 null, // icon res name
                 null, // bitmap path
-                disabledReason);
+                disabledReason,
+                null /* persons */);
     }
 
     private static String parseCategory(ShortcutService service, AttributeSet attrs) {
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index fa8360b..30c2281 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -20,12 +20,12 @@
 import android.apex.ApexInfo;
 import android.apex.ApexInfoList;
 import android.apex.ApexSessionInfo;
-import android.apex.IApexService;
 import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentSender;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageManager;
@@ -41,7 +41,6 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.apk.ApkSignatureVerifier;
@@ -68,14 +67,16 @@
 
     private final PackageInstallerService mPi;
     private final PackageManagerService mPm;
+    private final ApexManager mApexManager;
     private final Handler mBgHandler;
 
     @GuardedBy("mStagedSessions")
     private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
 
-    StagingManager(PackageManagerService pm, PackageInstallerService pi) {
+    StagingManager(PackageManagerService pm, PackageInstallerService pi, ApexManager am) {
         mPm = pm;
         mPi = pi;
+        mApexManager = am;
         mBgHandler = BackgroundThread.getHandler();
     }
 
@@ -100,7 +101,7 @@
         return new ParceledListSlice<>(result);
     }
 
-    private static boolean validateApexSignature(String apexPath, String packageName) {
+    private boolean validateApexSignature(String apexPath, String packageName) {
         final SigningDetails signingDetails;
         try {
             signingDetails = ApkSignatureVerifier.verify(apexPath, SignatureSchemeVersion.JAR);
@@ -109,17 +110,9 @@
             return false;
         }
 
-        final IApexService apex = IApexService.Stub.asInterface(
-                ServiceManager.getService("apexservice"));
-        final ApexInfo apexInfo;
-        try {
-            apexInfo = apex.getActivePackage(packageName);
-        } catch (RemoteException re) {
-            Slog.e(TAG, "Unable to contact APEXD", re);
-            return false;
-        }
+        final PackageInfo packageInfo = mApexManager.getActivePackage(packageName);
 
-        if (apexInfo == null || TextUtils.isEmpty(apexInfo.packageName)) {
+        if (packageInfo == null) {
             // TODO: What is the right thing to do here ? This implies there's no active package
             // with the given name. This should never be the case in production (where we only
             // accept updates to existing APEXes) but may be required for testing.
@@ -129,9 +122,10 @@
         final SigningDetails existingSigningDetails;
         try {
             existingSigningDetails = ApkSignatureVerifier.verify(
-                apexInfo.packagePath, SignatureSchemeVersion.JAR);
+                packageInfo.applicationInfo.sourceDir, SignatureSchemeVersion.JAR);
         } catch (PackageParserException e) {
-            Slog.e(TAG, "Unable to parse APEX package: " + apexInfo.packagePath, e);
+            Slog.e(TAG, "Unable to parse APEX package: "
+                    + packageInfo.applicationInfo.sourceDir, e);
             return false;
         }
 
@@ -143,10 +137,10 @@
         return false;
     }
 
-    private static boolean submitSessionToApexService(@NonNull PackageInstallerSession session,
-                                                      List<PackageInstallerSession> childSessions,
-                                                      ApexInfoList apexInfoList) {
-        return sendSubmitStagedSessionRequest(
+    private boolean submitSessionToApexService(@NonNull PackageInstallerSession session,
+                                               List<PackageInstallerSession> childSessions,
+                                               ApexInfoList apexInfoList) {
+        return mApexManager.submitStagedSession(
                 session.sessionId,
                 childSessions != null
                         ? childSessions.stream().mapToInt(s -> s.sessionId).toArray() :
@@ -154,33 +148,6 @@
                 apexInfoList);
     }
 
-    private static boolean sendSubmitStagedSessionRequest(
-            int sessionId, int[] childSessionIds, ApexInfoList apexInfoList) {
-        final IApexService apex = IApexService.Stub.asInterface(
-                ServiceManager.getService("apexservice"));
-        boolean success;
-        try {
-            success = apex.submitStagedSession(sessionId, childSessionIds, apexInfoList);
-        } catch (RemoteException re) {
-            Slog.e(TAG, "Unable to contact apexservice", re);
-            return false;
-        }
-        return success;
-    }
-
-    private static boolean sendMarkStagedSessionReadyRequest(int sessionId) {
-        final IApexService apex = IApexService.Stub.asInterface(
-                ServiceManager.getService("apexservice"));
-        boolean success;
-        try {
-            success = apex.markStagedSessionReady(sessionId);
-        } catch (RemoteException re) {
-            Slog.e(TAG, "Unable to contact apexservice", re);
-            return false;
-        }
-        return success;
-    }
-
     private static boolean isApexSession(@NonNull PackageInstallerSession session) {
         return (session.params.installFlags & PackageManager.INSTALL_APEX) != 0;
     }
@@ -260,7 +227,7 @@
         }
 
         session.setStagedSessionReady();
-        if (!sendMarkStagedSessionReadyRequest(session.sessionId)) {
+        if (!mApexManager.markStagedSessionReady(session.sessionId)) {
             session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
                             "APEX staging failed, check logcat messages from apexd for more "
                             + "details.");
@@ -284,16 +251,12 @@
 
     private void resumeSession(@NonNull PackageInstallerSession session) {
         if (sessionContainsApex(session)) {
-            // Check with apexservice whether the apex
-            // packages have been activated.
-            final IApexService apex = IApexService.Stub.asInterface(
-                    ServiceManager.getService("apexservice"));
-            ApexSessionInfo apexSessionInfo;
-            try {
-                apexSessionInfo = apex.getStagedSessionInfo(session.sessionId);
-            } catch (RemoteException re) {
-                Slog.e(TAG, "Unable to contact apexservice", re);
-                // TODO should we retry here? Mark the session as failed?
+            // Check with apexservice whether the apex packages have been activated.
+            ApexSessionInfo apexSessionInfo = mApexManager.getStagedSessionInfo(session.sessionId);
+            if (apexSessionInfo == null) {
+                session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+                        "apexd did not know anything about a staged session supposed to be"
+                        + "activated");
                 return;
             }
             if (apexSessionInfo.isActivationFailed || apexSessionInfo.isUnknown) {
@@ -323,8 +286,8 @@
         // The APEX part of the session is activated, proceed with the installation of APKs.
         if (!installApksInSession(session)) {
             session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
-                    "APEX activation failed. Check logcat messages from apexd for "
-                            + "more information.");
+                    "Staged installation of APKs failed. Check logcat messages for"
+                        + "more information.");
             return;
         }
         session.setStagedSessionApplied();
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b00193f..2e3e3e4 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -22,7 +22,6 @@
 import static android.app.AppOpsManager.OP_TOAST_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.content.Context.CONTEXT_RESTRICTED;
-import static android.content.Context.DISPLAY_SERVICE;
 import static android.content.Context.WINDOW_SERVICE;
 import static android.content.pm.PackageManager.FEATURE_HDMI_CEC;
 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
@@ -36,6 +35,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.Display.STATE_OFF;
+import static android.view.KeyEvent.KEYCODE_UNKNOWN;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
@@ -84,10 +84,8 @@
 import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
 
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
-import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs
-        .CAMERA_LENS_COVER_ABSENT;
-import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs
-        .CAMERA_LENS_UNCOVERED;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
 import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_DELEGATE;
@@ -371,6 +369,7 @@
     IStatusBarService mStatusBarService;
     StatusBarManagerInternal mStatusBarManagerInternal;
     AudioManagerInternal mAudioManagerInternal;
+    DisplayManager mDisplayManager;
     boolean mPreloadedRecentApps;
     final Object mServiceAquireLock = new Object();
     Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
@@ -1717,7 +1716,8 @@
         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
         mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
         mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
-        mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+        mDisplayManager = mContext.getSystemService(DisplayManager.class);
         mHasFeatureWatch = mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH);
         mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK);
         mHasFeatureHdmiCec = mContext.getPackageManager().hasSystemFeature(FEATURE_HDMI_CEC);
@@ -2508,8 +2508,7 @@
             return context;
         }
 
-        final DisplayManager dm = (DisplayManager) context.getSystemService(DISPLAY_SERVICE);
-        final Display targetDisplay = dm.getDisplay(displayId);
+        final Display targetDisplay = mDisplayManager.getDisplay(displayId);
         if (targetDisplay == null) {
             // Failed to obtain the non-default display where splash screen should be shown,
             // lets not show at all.
@@ -3655,7 +3654,7 @@
                 // Reset the pending key
                 mPendingWakeKey = PENDING_KEY_NULL;
             }
-        } else if (!interactive && shouldDispatchInputWhenNonInteractive(event)) {
+        } else if (!interactive && shouldDispatchInputWhenNonInteractive(displayId, keyCode)) {
             // If we're currently dozing with the screen on and the keyguard showing, pass the key
             // to the application but preserve its wake key status to make sure we still move
             // from dozing to fully interactive if we would normally go from off to fully
@@ -4126,7 +4125,8 @@
     // TODO(b/117479243): handle it in InputPolicy
     /** {@inheritDoc} */
     @Override
-    public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
+    public int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
+            int policyFlags) {
         if ((policyFlags & FLAG_WAKE) != 0) {
             if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion,
                     PowerManager.WAKE_REASON_WAKE_MOTION, "android.policy:MOTION")) {
@@ -4134,7 +4134,7 @@
             }
         }
 
-        if (shouldDispatchInputWhenNonInteractive(null)) {
+        if (shouldDispatchInputWhenNonInteractive(displayId, KEYCODE_UNKNOWN)) {
             return ACTION_PASS_TO_USER;
         }
 
@@ -4149,9 +4149,15 @@
         return 0;
     }
 
-    private boolean shouldDispatchInputWhenNonInteractive(KeyEvent event) {
-        final boolean displayOff = (mDefaultDisplay == null
-                || mDefaultDisplay.getState() == STATE_OFF);
+    private boolean shouldDispatchInputWhenNonInteractive(int displayId, int keyCode) {
+        // Apply the default display policy to unknown displays as well.
+        final boolean isDefaultDisplay = displayId == DEFAULT_DISPLAY
+                || displayId == INVALID_DISPLAY;
+        final Display display = isDefaultDisplay
+                ? mDefaultDisplay
+                : mDisplayManager.getDisplay(displayId);
+        final boolean displayOff = (display == null
+                || display.getState() == STATE_OFF);
 
         if (displayOff && !mHasFeatureWatch) {
             return false;
@@ -4163,25 +4169,25 @@
         }
 
         // Watches handle BACK specially
-        if (mHasFeatureWatch
-                && event != null
-                && (event.getKeyCode() == KeyEvent.KEYCODE_BACK
-                        || event.getKeyCode() == KeyEvent.KEYCODE_STEM_PRIMARY)) {
+        if (mHasFeatureWatch && (keyCode == KeyEvent.KEYCODE_BACK
+                || keyCode == KeyEvent.KEYCODE_STEM_PRIMARY)) {
             return false;
         }
 
-        // Send events to a dozing dream even if the screen is off since the dream
-        // is in control of the state of the screen.
-        IDreamManager dreamManager = getDreamManager();
+        // TODO(b/123372519): Refine when dream can support multi display.
+        if (isDefaultDisplay) {
+            // Send events to a dozing dream even if the screen is off since the dream
+            // is in control of the state of the screen.
+            IDreamManager dreamManager = getDreamManager();
 
-        try {
-            if (dreamManager != null && dreamManager.isDreaming()) {
-                return true;
+            try {
+                if (dreamManager != null && dreamManager.isDreaming()) {
+                    return true;
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "RemoteException when checking if dreaming", e);
             }
-        } catch (RemoteException e) {
-            Slog.e(TAG, "RemoteException when checking if dreaming", e);
         }
-
         // Otherwise, consume events since the user can't see what is being
         // interacted with.
         return false;
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index d1bd102..870d61b 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1003,11 +1003,13 @@
      * affect the power state of the device, for example, waking on motions.
      * Generally, it's best to keep as little as possible in the queue thread
      * because it's the most fragile.
+     * @param displayId The display ID of the motion event.
      * @param policyFlags The policy flags associated with the motion.
      *
      * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
      */
-    public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
+    int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
+            int policyFlags);
 
     /**
      * Called from the input dispatcher thread before a key is dispatched to a window.
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index dd2cda2..f3393e2 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -167,6 +167,7 @@
 
     public static final int CODE_DATA_BROADCAST = 1;
     public static final int CODE_SUBSCRIBER_BROADCAST = 1;
+    public static final int CODE_ACTIVE_CONFIGS_BROADCAST = 1;
     /**
      * The last report time is provided with each intent registered to
      * StatsManager#setFetchReportsOperation. This allows easy de-duping in the receiver if
@@ -356,6 +357,22 @@
     }
 
     @Override
+    public void sendActiveConfigsChangedBroadcast(IBinder intentSenderBinder, long[] configIds) {
+        enforceCallingPermission();
+        IntentSender intentSender = new IntentSender(intentSenderBinder);
+        Intent intent = new Intent();
+        intent.putExtra(StatsManager.EXTRA_STATS_ACTIVE_CONFIG_KEYS, configIds);
+        try {
+            intentSender.sendIntent(mContext, CODE_ACTIVE_CONFIGS_BROADCAST, intent, null, null);
+            if (DEBUG) {
+                Slog.d(TAG, "Sent broadcast with config ids " + Arrays.toString(configIds));
+            }
+        } catch (IntentSender.SendIntentException e) {
+            Slog.w(TAG, "Unable to send active configs changed broadcast using IntentSender");
+        }
+    }
+
+    @Override
     public void sendSubscriberBroadcast(IBinder intentSenderBinder, long configUid, long configKey,
             long subscriptionId, long subscriptionRuleId, String[] cookies,
             StatsDimensionsValue dimensionsValue) {
@@ -1169,7 +1186,7 @@
         BinderCallsStatsService.Internal binderStats =
                 LocalServices.getService(BinderCallsStatsService.Internal.class);
         if (binderStats == null) {
-            return;
+            throw new IllegalStateException("binderStats is null");
         }
 
         List<ExportedCallStat> callStats = binderStats.getExportedCallStats();
@@ -1200,7 +1217,7 @@
         BinderCallsStatsService.Internal binderStats =
                 LocalServices.getService(BinderCallsStatsService.Internal.class);
         if (binderStats == null) {
-            return;
+            throw new IllegalStateException("binderStats is null");
         }
 
         ArrayMap<String, Integer> exceptionStats = binderStats.getExportedExceptionStats();
@@ -1218,7 +1235,7 @@
             List<StatsLogEventWrapper> pulledData) {
         LooperStats looperStats = LocalServices.getService(LooperStats.class);
         if (looperStats == null) {
-            return;
+            throw new IllegalStateException("looperStats null");
         }
 
         List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
@@ -1689,18 +1706,19 @@
     private void pullCpuTimePerThreadFreq(int tagId, long elapsedNanos, long wallClockNanos,
             List<StatsLogEventWrapper> pulledData) {
         if (this.mKernelCpuThreadReader == null) {
-            return;
+            throw new IllegalStateException("mKernelCpuThreadReader is null");
         }
         ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages =
                 this.mKernelCpuThreadReader.getProcessCpuUsageByUids();
         if (processCpuUsages == null) {
-            return;
+            throw new IllegalStateException("processCpuUsages is null");
         }
         int[] cpuFrequencies = mKernelCpuThreadReader.getCpuFrequenciesKhz();
         if (cpuFrequencies.length > CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES) {
-            Slog.w(TAG, "Expected maximum " + CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES
-                    + " frequencies, but got " + cpuFrequencies.length);
-            return;
+            String message = "Expected maximum " + CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES
+                    + " frequencies, but got " + cpuFrequencies.length;
+            Slog.w(TAG, message);
+            throw new IllegalStateException(message);
         }
         for (int i = 0; i < processCpuUsages.size(); i++) {
             KernelCpuThreadReader.ProcessCpuUsage processCpuUsage = processCpuUsages.get(i);
@@ -1709,10 +1727,11 @@
             for (int j = 0; j < threadCpuUsages.size(); j++) {
                 KernelCpuThreadReader.ThreadCpuUsage threadCpuUsage = threadCpuUsages.get(j);
                 if (threadCpuUsage.usageTimesMillis.length != cpuFrequencies.length) {
-                    Slog.w(TAG, "Unexpected number of usage times,"
+                    String message = "Unexpected number of usage times,"
                             + " expected " + cpuFrequencies.length
-                            + " but got " + threadCpuUsage.usageTimesMillis.length);
-                    continue;
+                            + " but got " + threadCpuUsage.usageTimesMillis.length;
+                    Slog.w(TAG, message);
+                    throw new IllegalStateException(message);
                 }
 
                 StatsLogEventWrapper e =
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index f9c9d33..f46835e 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -163,15 +163,12 @@
         return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
     }
 
-    /**
-     * Provides an opportunity for the window manager policy to intercept early motion event
-     * processing when the device is in a non-interactive state since these events are normally
-     * dropped.
-     */
+    /** {@inheritDoc} */
     @Override
-    public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
+    public int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
+            int policyFlags) {
         return mService.mPolicy.interceptMotionBeforeQueueingNonInteractive(
-                whenNanos, policyFlags);
+                displayId, whenNanos, policyFlags);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index fb5b1d8..5c91d9e 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -300,7 +300,7 @@
      * corresponding record in display manager.
      */
     // TODO: Look into consolidating with getActivityDisplay()
-    ActivityDisplay getActivityDisplayOrCreate(int displayId) {
+    @Nullable ActivityDisplay getActivityDisplayOrCreate(int displayId) {
         ActivityDisplay activityDisplay = getActivityDisplay(displayId);
         if (activityDisplay != null) {
             return activityDisplay;
@@ -1317,6 +1317,9 @@
         if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId);
         synchronized (mService.mGlobalLock) {
             final ActivityDisplay display = getActivityDisplayOrCreate(displayId);
+            if (display == null) {
+                return;
+            }
             // Do not start home before booting, or it may accidentally finish booting before it
             // starts. Instead, we expect home activities to be launched when the system is ready
             // (ActivityManagerService#systemReady).
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 48cd6b6..3430987 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2466,7 +2466,7 @@
     /** @return false if this window desires touch events. */
     boolean cantReceiveTouchInput() {
         return mAppToken != null && mAppToken.getTask() != null
-                && mAppToken.getTask().mStack.shouldIgnoreInput();
+                && (mAppToken.getTask().mStack.shouldIgnoreInput() || mAppToken.hiddenRequested);
     }
 
     @Override
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index c18e98b..57377c6 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -249,7 +249,8 @@
     virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
     virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
-    virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
+    virtual void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
+            uint32_t& policyFlags);
     virtual nsecs_t interceptKeyBeforeDispatching(
             const sp<IBinder>& token,
             const KeyEvent* keyEvent, uint32_t policyFlags);
@@ -1066,7 +1067,8 @@
     }
 }
 
-void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
+void NativeInputManager::interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
+        uint32_t& policyFlags) {
     ATRACE_CALL();
     // Policy:
     // - Ignore untrusted events and pass them along.
@@ -1084,7 +1086,7 @@
             JNIEnv* env = jniEnv();
             jint wmActions = env->CallIntMethod(mServiceObj,
                         gServiceClassInfo.interceptMotionBeforeQueueingNonInteractive,
-                        when, policyFlags);
+                        displayId, when, policyFlags);
             if (checkAndClearExceptionFromCallback(env,
                     "interceptMotionBeforeQueueingNonInteractive")) {
                 wmActions = 0;
@@ -1794,7 +1796,7 @@
             "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;I)I");
 
     GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingNonInteractive, clazz,
-            "interceptMotionBeforeQueueingNonInteractive", "(JI)I");
+            "interceptMotionBeforeQueueingNonInteractive", "(IJI)I");
 
     GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz,
             "interceptKeyBeforeDispatching",
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index cbc3791..d178c3a 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -973,7 +973,10 @@
         JavaObject& object) {
     translateSingleGnssMeasurement(&(measurement_V2_0->v1_1), object);
 
-    SET(CodeType, (static_cast<int32_t>(measurement_V2_0->codeType)));
+    SET(CodeType, static_cast<int32_t>(measurement_V2_0->codeType));
+
+    // Overwrite with v2_0.state since v2_0->v1_1->v1_0.state is deprecated.
+    SET(State, static_cast<int32_t>(measurement_V2_0->state));
 }
 
 jobject GnssMeasurementCallback::translateGnssClock(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java
index de5dd17..d5cfab9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java
@@ -16,7 +16,7 @@
 
 package com.android.server.devicepolicy;
 
-import android.app.admin.DevicePolicyManager.InstallUpdateCallback;
+import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback;
 import android.app.admin.StartInstallingUpdateCallback;
 import android.content.Context;
 import android.os.ParcelFileDescriptor;
@@ -62,41 +62,43 @@
 
     private static Map<Integer, Integer> buildErrorCodesMap() {
         Map<Integer, Integer> map = new HashMap<>();
-        map.put(UpdateEngine.ErrorCodeConstants.ERROR, InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+        map.put(
+                UpdateEngine.ErrorCodeConstants.ERROR,
+                InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
         map.put(
                 DOWNLOAD_STATE_INITIALIZATION_ERROR,
-                InstallUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION);
+                InstallSystemUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION);
         map.put(
                 UpdateEngine.ErrorCodeConstants.PAYLOAD_TIMESTAMP_ERROR,
-                InstallUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION);
+                InstallSystemUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION);
 
         // Error constants corresponding to errors related to bad update file.
         map.put(
                 UpdateEngine.ErrorCodeConstants.DOWNLOAD_PAYLOAD_VERIFICATION_ERROR,
-                InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
+                InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
         map.put(
                 UpdateEngine.ErrorCodeConstants.PAYLOAD_SIZE_MISMATCH_ERROR,
-                InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
+                InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
         map.put(
                 UpdateEngine.ErrorCodeConstants.PAYLOAD_MISMATCHED_TYPE_ERROR,
-                InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
+                InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
         map.put(
                 UpdateEngine.ErrorCodeConstants.PAYLOAD_HASH_MISMATCH_ERROR,
-                InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
+                InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
 
         // Error constants corresponding to errors related to devices bad state.
         map.put(
                 UpdateEngine.ErrorCodeConstants.POST_INSTALL_RUNNER_ERROR,
-                InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+                InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
         map.put(
                 UpdateEngine.ErrorCodeConstants.INSTALL_DEVICE_OPEN_ERROR,
-                InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+                InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
         map.put(
                 UpdateEngine.ErrorCodeConstants.DOWNLOAD_TRANSFER_ERROR,
-                InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+                InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
         map.put(
                 UpdateEngine.ErrorCodeConstants.UPDATED_BUT_NOT_ACTIVE,
-                InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+                InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
 
         return map;
     }
@@ -153,12 +155,13 @@
         } catch (ZipException e) {
             Log.w(UpdateInstaller.TAG, e);
             notifyCallbackOnError(
-                    InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
+                    InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
                     Log.getStackTraceString(e));
         } catch (IOException e) {
             Log.w(UpdateInstaller.TAG, e);
             notifyCallbackOnError(
-                    InstallUpdateCallback.UPDATE_ERROR_UNKNOWN, Log.getStackTraceString(e));
+                    InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN,
+                    Log.getStackTraceString(e));
         }
     }
 
@@ -185,7 +188,7 @@
         if (mSizeForUpdate == -1) {
             Log.w(UpdateInstaller.TAG, "Failed to find payload entry in the given package.");
             notifyCallbackOnError(
-                    InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
+                    InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
                     "Failed to find payload entry in the given package.");
             return;
         }
@@ -210,7 +213,7 @@
                 if (entry.getMethod() != ZipEntry.STORED) {
                     Log.w(UpdateInstaller.TAG, "Invalid compression method.");
                     notifyCallbackOnError(
-                            InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
+                            InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
                             "Invalid compression method.");
                     return false;
                 }
@@ -263,7 +266,7 @@
             } else {
                 mUpdateInstaller.notifyCallbackOnError(
                         errorCodesMap.getOrDefault(
-                                errorCode, InstallUpdateCallback.UPDATE_ERROR_UNKNOWN),
+                                errorCode, InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN),
                         errorStringsMap.getOrDefault(errorCode, UNKNOWN_ERROR + errorCode));
             }
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 093ac89..9523202 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -17,8 +17,8 @@
 package com.android.server.devicepolicy;
 
 import static android.Manifest.permission.BIND_DEVICE_ADMIN;
-import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
 import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
+import static android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY;
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
@@ -4778,8 +4778,8 @@
         final int callingUserId = mInjector.userHandleGetCallingUserId();
         enforceUserUnlocked(callingUserId);
         mContext.enforceCallingOrSelfPermission(
-                GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY,
-                "Must have " + GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY + " permission.");
+                REQUEST_SCREEN_LOCK_COMPLEXITY,
+                "Must have " + REQUEST_SCREEN_LOCK_COMPLEXITY + " permission.");
 
         synchronized (getLockObject()) {
             int targetUserId = getCredentialOwner(callingUserId, /* parent= */ false);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NonAbUpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/NonAbUpdateInstaller.java
index 5f1e926..582306c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NonAbUpdateInstaller.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NonAbUpdateInstaller.java
@@ -16,7 +16,7 @@
 
 package com.android.server.devicepolicy;
 
-import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback;
 import android.app.admin.StartInstallingUpdateCallback;
 import android.content.Context;
 import android.os.ParcelFileDescriptor;
@@ -45,7 +45,7 @@
         } catch (IOException e) {
             Log.w(TAG, "IO error while trying to install non AB update.", e);
             notifyCallbackOnError(
-                    DevicePolicyManager.InstallUpdateCallback.UPDATE_ERROR_UNKNOWN,
+                    InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN,
                     Log.getStackTraceString(e));
         }
     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java
index cf68ccf..7148ed4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java
@@ -18,7 +18,7 @@
 
 import android.annotation.Nullable;
 import android.app.admin.DevicePolicyEventLogger;
-import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback;
 import android.app.admin.StartInstallingUpdateCallback;
 import android.content.Context;
 import android.content.Intent;
@@ -66,7 +66,7 @@
         mCopiedUpdateFile = null;
         if (!isBatteryLevelSufficient()) {
             notifyCallbackOnError(
-                    DevicePolicyManager.InstallUpdateCallback.UPDATE_ERROR_BATTERY_LOW,
+                    InstallSystemUpdateCallback.UPDATE_ERROR_BATTERY_LOW,
                     "The battery level must be above "
                             + mConstants.BATTERY_THRESHOLD_NOT_CHARGING + " while not charging or"
                             + "above " + mConstants.BATTERY_THRESHOLD_CHARGING + " while charging");
@@ -76,7 +76,7 @@
             mCopiedUpdateFile = copyUpdateFileToDataOtaPackageDir();
             if (mCopiedUpdateFile == null) {
                 notifyCallbackOnError(
-                        DevicePolicyManager.InstallUpdateCallback.UPDATE_ERROR_UNKNOWN,
+                        InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN,
                         "Error while copying file.");
                 return;
             }
@@ -111,7 +111,7 @@
         } catch (IOException e) {
             Log.w(TAG, "Failed to copy update file to OTA directory", e);
             notifyCallbackOnError(
-                    DevicePolicyManager.InstallUpdateCallback.UPDATE_ERROR_UNKNOWN,
+                    InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN,
                     Log.getStackTraceString(e));
             return null;
         }
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java
similarity index 100%
rename from services/robotests/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java
rename to services/robotests/backup/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java
similarity index 100%
rename from services/robotests/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java
rename to services/robotests/backup/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java
similarity index 100%
rename from services/robotests/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java
rename to services/robotests/backup/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 9ac91dd..de782a5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -5199,7 +5199,7 @@
     public void testGetPasswordComplexity_currentUserNoPassword() {
         when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE))
                 .thenReturn(true);
-        mServiceContext.permissions.add(permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+        mServiceContext.permissions.add(permission.REQUEST_SCREEN_LOCK_COMPLEXITY);
         when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE))
                 .thenReturn(DpmMockContext.CALLER_USER_HANDLE);
 
@@ -5209,7 +5209,7 @@
     public void testGetPasswordComplexity_currentUserHasPassword() {
         when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE))
                 .thenReturn(true);
-        mServiceContext.permissions.add(permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+        mServiceContext.permissions.add(permission.REQUEST_SCREEN_LOCK_COMPLEXITY);
         when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE))
                 .thenReturn(DpmMockContext.CALLER_USER_HANDLE);
         dpms.mUserPasswordMetrics.put(
@@ -5222,7 +5222,7 @@
     public void testGetPasswordComplexity_unifiedChallengeReturnsParentUserPassword() {
         when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE))
                 .thenReturn(true);
-        mServiceContext.permissions.add(permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+        mServiceContext.permissions.add(permission.REQUEST_SCREEN_LOCK_COMPLEXITY);
 
         UserInfo parentUser = new UserInfo();
         parentUser.id = DpmMockContext.CALLER_USER_HANDLE + 10;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 8d0365b..9504381 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -32,6 +32,7 @@
 
 import android.Manifest.permission;
 import android.app.ActivityManager;
+import android.app.Person;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ShortcutInfo;
@@ -890,6 +891,7 @@
                 .setText("text")
                 .setDisabledMessage("dismes")
                 .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
+                .setPerson(makePerson("person", "personKey", "personUri"))
                 .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
                 .setRank(123)
                 .setExtras(pb)
@@ -901,6 +903,8 @@
                 .setTitle("x")
                 .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
                 .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setPersons(list(makePerson("person1", "personKey1", "personUri1"),
+                        makePerson("person2", "personKey2", "personUri2")).toArray(new Person[2]))
                 .setRank(456)
                 .build();
         sorig2.setTimestamp(mInjectedCurrentTimeMillis);
@@ -936,6 +940,10 @@
         assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
         assertEquals("action", si.getIntent().getAction());
         assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(1, si.getPersons().length);
+        assertEquals("person", si.getPersons()[0].getName());
+        assertEquals("personKey", si.getPersons()[0].getKey());
+        assertEquals("personUri", si.getPersons()[0].getUri());
         assertEquals(0, si.getRank());
         assertEquals(1, si.getExtras().getInt("k"));
 
@@ -949,6 +957,8 @@
         // to test it.
         si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10);
         assertEquals(1, si.getRank());
+        assertEquals(2, si.getPersons().length);
+        assertEquals("personUri2", si.getPersons()[1].getUri());
 
         dumpUserFile(USER_10);
     }
@@ -1114,6 +1124,7 @@
                 .setDisabledMessage("dismes")
                 .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
                 .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setPerson(makePerson("person", "personKey", "personUri"))
                 .setRank(123)
                 .setExtras(pb)
                 .build();
@@ -1150,6 +1161,7 @@
         assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
         assertEquals("action", si.getIntent().getAction());
         assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(0, si.getPersons().length); // Don't backup the persons field
         assertEquals(0, si.getRank());
         assertEquals(1, si.getExtras().getInt("k"));
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index bfb9193..849772a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -156,7 +156,8 @@
     }
 
     @Override
-    public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
+    public int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
+            int policyFlags) {
         return 0;
     }
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 0c63b60..1b7228a 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2424,6 +2424,14 @@
             "5g_icon_configuration_string";
 
     /**
+     * Support ASCII 7-BIT encoding for long SMS. This carrier config is used to enable
+     * this feature.
+     * @hide
+     */
+    public static final String KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL =
+            "ascii_7_bit_support_for_long_message_bool";
+
+    /**
      * Controls RSRP threshold at which OpportunisticNetworkService will decide whether
      * the opportunistic network is good enough for internet data.
      */
@@ -2961,6 +2969,7 @@
         sDefaults.putInt(KEY_CALL_WAITING_SERVICE_CLASS_INT, 1 /* SERVICE_CLASS_VOICE */);
         sDefaults.putString(KEY_5G_ICON_CONFIGURATION_STRING,
                 "connected_mmwave:None,connected:5G,not_restricted:None,restricted:None");
+        sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false);
         /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */
         sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108);
         /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_MODERATE */
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index 6b1b84c..856f081 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -30,6 +30,7 @@
     private final int mNrArfcn;
     private final int mPci;
     private final int mTac;
+    private final long mNci;
 
     /**
      *
@@ -44,11 +45,12 @@
      * @hide
      */
     public CellIdentityNr(int pci, int tac, int nrArfcn,  String mccStr, String mncStr,
-            String alphal, String alphas) {
+            long nci, String alphal, String alphas) {
         super(TAG, CellInfo.TYPE_NR, mccStr, mncStr, alphal, alphas);
         mPci = pci;
         mTac = tac;
         mNrArfcn = nrArfcn;
+        mNci = nci;
     }
 
     /**
@@ -62,7 +64,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(super.hashCode(), mPci, mTac, mNrArfcn);
+        return Objects.hash(super.hashCode(), mPci, mTac, mNrArfcn, mNci);
     }
 
     @Override
@@ -72,7 +74,17 @@
         }
 
         CellIdentityNr o = (CellIdentityNr) other;
-        return super.equals(o) && mPci == o.mPci && mTac == o.mTac && mNrArfcn == o.mNrArfcn;
+        return super.equals(o) && mPci == o.mPci && mTac == o.mTac && mNrArfcn == o.mNrArfcn
+                && mNci == o.mNci;
+    }
+
+    /**
+     * Get the NR Cell Identity.
+     *
+     * @return The NR Cell Identity in range [0, 68719476735] or Long.MAX_VALUE if unknown.
+     */
+    public long getNci() {
+        return mNci;
     }
 
     /**
@@ -122,6 +134,7 @@
                 .append(" mNrArfcn = ").append(mNrArfcn)
                 .append(" mMcc = ").append(mMccStr)
                 .append(" mMnc = ").append(mMncStr)
+                .append(" mNci = ").append(mNci)
                 .append(" mAlphaLong = ").append(mAlphaLong)
                 .append(" mAlphaShort = ").append(mAlphaShort)
                 .append(" }")
@@ -134,6 +147,7 @@
         dest.writeInt(mPci);
         dest.writeInt(mTac);
         dest.writeInt(mNrArfcn);
+        dest.writeLong(mNci);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -142,6 +156,7 @@
         mPci = in.readInt();
         mTac = in.readInt();
         mNrArfcn = in.readInt();
+        mNci = in.readLong();
     }
 
     /** Implement the Parcelable interface */
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java
index ceb76b5..c37b492 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationState.java
@@ -27,6 +27,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 /**
  * Description of a mobile network registration state
@@ -360,7 +361,34 @@
         return 0;
     }
 
-    private static String regStateToString(int regState) {
+    /**
+     * Convert service type to string
+     *
+     * @hide
+     *
+     * @param serviceType The service type
+     * @return The service type in string format
+     */
+    public static String serviceTypeToString(@ServiceType int serviceType) {
+        switch (serviceType) {
+            case SERVICE_TYPE_VOICE: return "VOICE";
+            case SERVICE_TYPE_DATA: return "DATA";
+            case SERVICE_TYPE_SMS: return "SMS";
+            case SERVICE_TYPE_VIDEO: return "VIDEO";
+            case SERVICE_TYPE_EMERGENCY: return "EMERGENCY";
+        }
+        return "Unknown service type " + serviceType;
+    }
+
+    /**
+     * Convert registration state to string
+     *
+     * @hide
+     *
+     * @param regState The registration state
+     * @return The reg state in string
+     */
+    public static String regStateToString(@RegState int regState) {
         switch (regState) {
             case REG_STATE_NOT_REG_NOT_SEARCHING: return "NOT_REG_NOT_SEARCHING";
             case REG_STATE_HOME: return "HOME";
@@ -389,14 +417,17 @@
     public String toString() {
         return new StringBuilder("NetworkRegistrationState{")
                 .append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS")
-                .append("transportType=").append(mTransportType)
+                .append(" transportType=").append(TransportType.toString(mTransportType))
                 .append(" regState=").append(regStateToString(mRegState))
-                .append(" roamingType=").append(mRoamingType)
+                .append(" roamingType=").append(ServiceState.roamingTypeToString(mRoamingType))
                 .append(" accessNetworkTechnology=")
                 .append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology))
                 .append(" rejectCause=").append(mRejectCause)
                 .append(" emergencyEnabled=").append(mEmergencyOnly)
-                .append(" supportedServices=").append(mAvailableServices)
+                .append(" availableServices=").append("[" + (mAvailableServices != null
+                        ? Arrays.stream(mAvailableServices)
+                        .mapToObj(type -> serviceTypeToString(type))
+                        .collect(Collectors.joining(",")) : null) + "]")
                 .append(" cellIdentity=").append(mCellIdentity)
                 .append(" voiceSpecificStates=").append(mVoiceSpecificStates)
                 .append(" dataSpecificStates=").append(mDataSpecificStates)
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 3317876..402763e 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -887,6 +887,24 @@
     }
 
     /**
+     * Convert roaming type to string
+     *
+     * @param roamingType roaming type
+     * @return The roaming type in string format
+     *
+     * @hide
+     */
+    public static String roamingTypeToString(@RoamingType int roamingType) {
+        switch (roamingType) {
+            case ROAMING_TYPE_NOT_ROAMING: return "NOT_ROAMING";
+            case ROAMING_TYPE_UNKNOWN: return "UNKNOWN";
+            case ROAMING_TYPE_DOMESTIC: return "DOMESTIC";
+            case ROAMING_TYPE_INTERNATIONAL: return "INTERNATIONAL";
+        }
+        return "Unknown roaming type " + roamingType;
+    }
+
+    /**
      * Convert radio technology to String
      *
      * @param rt radioTechnology
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 313146d..3a4d33c 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -59,6 +59,7 @@
 import android.util.Log;
 
 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
+import com.android.internal.telephony.ISetOpportunisticDataCallback;
 import com.android.internal.telephony.ISub;
 import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.PhoneConstants;
@@ -72,6 +73,7 @@
 import java.util.Locale;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
 /**
@@ -2573,17 +2575,35 @@
      *              {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}, it means
      *              it's unset and {@link SubscriptionManager#getDefaultDataSubscriptionId()}
      *              is used to determine which modem is preferred.
+     * @param needValidation whether validation is needed before switch happens.
+     * @param executor The executor of where the callback will execute.
+     * @param callback Callback will be triggered once it succeeds or failed.
+     *                 See {@link TelephonyManager.SetOpportunisticSubscriptionResult}
+     *                 for more details. Pass null if don't care about the result.
+     *
      * @hide
      *
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public void setPreferredDataSubscriptionId(int subId) {
+    public void setPreferredDataSubscriptionId(int subId, boolean needValidation,
+            @NonNull @CallbackExecutor Executor executor, Consumer<Integer> callback) {
         if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId);
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
-            if (iSub != null) {
-                iSub.setPreferredDataSubscriptionId(subId);
-            }
+            if (iSub == null) return;
+
+            ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() {
+                @Override
+                public void onComplete(int result) {
+                    Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
+                        if (callback != null) {
+                            callback.accept(result);
+                        }
+                    }));
+                }
+            };
+            iSub.setPreferredDataSubscriptionId(subId, needValidation, callbackStub);
         } catch (RemoteException ex) {
             // ignore it
         }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 2a03924..f9cf253 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -229,10 +229,19 @@
     public static final int SRVCC_STATE_HANDOVER_CANCELED  = 3;
 
     /**
-     * An invalid UICC card identifier. See {@link #getCardIdForDefaultEuicc()} and
-     * {@link UiccCardInfo#getCardId()}.
+     * A UICC card identifier used if the device does not support the operation.
+     * For example, {@link #getCardIdForDefaultEuicc()} returns this value if the device has no
+     * eUICC, or the eUICC cannot be read.
      */
-    public static final int INVALID_CARD_ID = -1;
+    public static final int UNSUPPORTED_CARD_ID = -1;
+
+    /**
+     * A UICC card identifier used before the UICC card is loaded. See
+     * {@link #getCardIdForDefaultEuicc()} and {@link UiccCardInfo#getCardId()}.
+     * <p>
+     * Note that once the UICC card is loaded, the card ID may become {@link #UNSUPPORTED_CARD_ID}.
+     */
+    public static final int UNINITIALIZED_CARD_ID = -2;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -3178,24 +3187,25 @@
     }
 
     /**
-     * Get the card ID of the default eUICC card. If there is no eUICC, returns
-     * {@link #INVALID_CARD_ID}.
+     * Get the card ID of the default eUICC card. If the eUICCs have not yet been loaded, returns
+     * {@link #UNINITIALIZED_CARD_ID}. If there is no eUICC or the device does not support card IDs
+     * for eUICCs, returns {@link #UNSUPPORTED_CARD_ID}.
      *
      * <p>The card ID is a unique identifier associated with a UICC or eUICC card. Card IDs are
      * unique to a device, and always refer to the same UICC or eUICC card unless the device goes
      * through a factory reset.
      *
-     * @return card ID of the default eUICC card.
+     * @return card ID of the default eUICC card, if loaded.
      */
     public int getCardIdForDefaultEuicc() {
         try {
             ITelephony telephony = getITelephony();
             if (telephony == null) {
-                return INVALID_CARD_ID;
+                return UNINITIALIZED_CARD_ID;
             }
             return telephony.getCardIdForDefaultEuicc(mSubId, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            return INVALID_CARD_ID;
+            return UNINITIALIZED_CARD_ID;
         }
     }
 
@@ -10094,6 +10104,29 @@
         return false;
     }
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"SET_OPPORTUNISTIC_SUB"}, value = {
+            SET_OPPORTUNISTIC_SUB_SUCCESS,
+            SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED,
+            SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER})
+    public @interface SetOpportunisticSubscriptionResult {}
+
+    /**
+     * No error. Operation succeeded.
+     */
+    public static final int SET_OPPORTUNISTIC_SUB_SUCCESS = 0;
+
+    /**
+     * Validation failed when trying to switch to preferred subscription.
+     */
+    public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1;
+
+    /**
+     * The parameter passed in is invalid.
+     */
+    public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2;
+
     /**
      * Set preferred opportunistic data subscription id.
      *
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 1bbf9f4..ad34349 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -460,7 +460,7 @@
      */
     @Nullable
     public String getEid() {
-        if (!refreshCardIdIfInvalid()) {
+        if (!refreshCardIdIfUninitialized()) {
             return null;
         }
         try {
@@ -483,7 +483,7 @@
     @SystemApi
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public int getOtaStatus() {
-        if (!refreshCardIdIfInvalid()) {
+        if (!refreshCardIdIfUninitialized()) {
             return EUICC_OTA_STATUS_UNAVAILABLE;
         }
         try {
@@ -518,7 +518,7 @@
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void downloadSubscription(DownloadableSubscription subscription,
             boolean switchAfterDownload, PendingIntent callbackIntent) {
-        if (!refreshCardIdIfInvalid()) {
+        if (!refreshCardIdIfUninitialized()) {
             sendUnavailableError(callbackIntent);
             return;
         }
@@ -580,7 +580,7 @@
     @SystemApi
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) {
-        if (!refreshCardIdIfInvalid()) {
+        if (!refreshCardIdIfUninitialized()) {
             PendingIntent callbackIntent =
                     resolutionIntent.getParcelableExtra(
                             EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT);
@@ -617,7 +617,7 @@
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void getDownloadableSubscriptionMetadata(
             DownloadableSubscription subscription, PendingIntent callbackIntent) {
-        if (!refreshCardIdIfInvalid()) {
+        if (!refreshCardIdIfUninitialized()) {
             sendUnavailableError(callbackIntent);
             return;
         }
@@ -647,7 +647,7 @@
     @SystemApi
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void getDefaultDownloadableSubscriptionList(PendingIntent callbackIntent) {
-        if (!refreshCardIdIfInvalid()) {
+        if (!refreshCardIdIfUninitialized()) {
             sendUnavailableError(callbackIntent);
             return;
         }
@@ -666,7 +666,7 @@
      */
     @Nullable
     public EuiccInfo getEuiccInfo() {
-        if (!refreshCardIdIfInvalid()) {
+        if (!refreshCardIdIfUninitialized()) {
             return null;
         }
         try {
@@ -691,7 +691,7 @@
      */
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void deleteSubscription(int subscriptionId, PendingIntent callbackIntent) {
-        if (!refreshCardIdIfInvalid()) {
+        if (!refreshCardIdIfUninitialized()) {
             sendUnavailableError(callbackIntent);
             return;
         }
@@ -731,7 +731,7 @@
      */
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) {
-        if (!refreshCardIdIfInvalid()) {
+        if (!refreshCardIdIfUninitialized()) {
             sendUnavailableError(callbackIntent);
             return;
         }
@@ -757,7 +757,7 @@
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void updateSubscriptionNickname(
             int subscriptionId, String nickname, PendingIntent callbackIntent) {
-        if (!refreshCardIdIfInvalid()) {
+        if (!refreshCardIdIfUninitialized()) {
             sendUnavailableError(callbackIntent);
             return;
         }
@@ -781,7 +781,7 @@
     @SystemApi
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void eraseSubscriptions(PendingIntent callbackIntent) {
-        if (!refreshCardIdIfInvalid()) {
+        if (!refreshCardIdIfUninitialized()) {
             sendUnavailableError(callbackIntent);
             return;
         }
@@ -811,7 +811,7 @@
      * @hide
      */
     public void retainSubscriptionsForFactoryReset(PendingIntent callbackIntent) {
-        if (!refreshCardIdIfInvalid()) {
+        if (!refreshCardIdIfUninitialized()) {
             sendUnavailableError(callbackIntent);
             return;
         }
@@ -822,16 +822,24 @@
         }
     }
 
-    private boolean refreshCardIdIfInvalid() {
-        if (!isEnabled()) {
-            return false;
-        }
-        // Refresh mCardId if it's invalid.
-        if (mCardId == TelephonyManager.INVALID_CARD_ID) {
+    /**
+     * Refreshes the cardId if its uninitialized, and returns whether we should continue the
+     * operation.
+     * <p>
+     * Note that after a successful refresh, the mCardId may be TelephonyManager.UNSUPPORTED_CARD_ID
+     * on older HALs. For backwards compatability, we continue to the LPA and let it decide which
+     * card to use.
+     */
+    private boolean refreshCardIdIfUninitialized() {
+        // Refresh mCardId if its UNINITIALIZED_CARD_ID
+        if (mCardId == TelephonyManager.UNINITIALIZED_CARD_ID) {
             TelephonyManager tm = (TelephonyManager)
                     mContext.getSystemService(Context.TELEPHONY_SERVICE);
             mCardId = tm.getCardIdForDefaultEuicc();
         }
+        if (mCardId == TelephonyManager.UNINITIALIZED_CARD_ID) {
+            return false;
+        }
         return true;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl b/telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl
new file mode 100644
index 0000000..7a78f34
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+/**
+ * Callback to provide asynchronous result of setPreferredOpportunisticData.
+ * @hide
+ */
+oneway interface ISetOpportunisticDataCallback {
+    void onComplete(int result);
+}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 6ce9de4..75a4d82 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.telephony;
 
 import android.telephony.SubscriptionInfo;
+import com.android.internal.telephony.ISetOpportunisticDataCallback;
 
 interface ISub {
     /**
@@ -217,10 +218,14 @@
      * designed to overwrite default data subscription temporarily.
      *
      * @param subId which subscription is preferred to for cellular data.
+     * @param needValidation whether validation is needed before switching.
+     * @param callback callback upon request completion.
+     *
      * @hide
      *
      */
-    void setPreferredDataSubscriptionId(int subId);
+    void setPreferredDataSubscriptionId(int subId, boolean needValidation,
+                     ISetOpportunisticDataCallback callback);
 
     /**
      * Get which subscription is preferred for cellular data.
diff --git a/telephony/java/com/android/internal/telephony/cdma/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/BearerData.java
index a4cd56b..694cc69 100644
--- a/telephony/java/com/android/internal/telephony/cdma/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/BearerData.java
@@ -596,6 +596,45 @@
         System.arraycopy(payload, 0, uData.payload, udhBytes, payload.length);
     }
 
+    private static void encode7bitAsciiEms(UserData uData, byte[] udhData, boolean force)
+            throws CodingException
+    {
+        try {
+            Rlog.d(LOG_TAG, "encode7bitAsciiEms");
+            int udhBytes = udhData.length + 1;  // Add length octet.
+            int udhSeptets = ((udhBytes * 8) + 6) / 7;
+            int paddingBits = (udhSeptets * 7) - (udhBytes * 8);
+            String msg = uData.payloadStr;
+            byte[] payload ;
+            int msgLen = msg.length();
+            BitwiseOutputStream outStream = new BitwiseOutputStream(msgLen +
+                    (paddingBits > 0 ? 1 : 0));
+            outStream.write(paddingBits, 0);
+            for (int i = 0; i < msgLen; i++) {
+                int charCode = UserData.charToAscii.get(msg.charAt(i), -1);
+                if (charCode == -1) {
+                    if (force) {
+                        outStream.write(7, UserData.UNENCODABLE_7_BIT_CHAR);
+                    } else {
+                        throw new CodingException("cannot ASCII encode (" + msg.charAt(i) + ")");
+                    }
+                } else {
+                    outStream.write(7, charCode);
+                }
+            }
+            payload = outStream.toByteArray();
+            uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
+            uData.msgEncodingSet = true;
+            uData.numFields = udhSeptets + uData.payloadStr.length();
+            uData.payload = new byte[udhBytes + payload.length];
+            uData.payload[0] = (byte)udhData.length;
+            System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
+            System.arraycopy(payload, 0, uData.payload, udhBytes, payload.length);
+        } catch (BitwiseOutputStream.AccessException ex) {
+            throw new CodingException("7bit ASCII encode failed: " + ex);
+        }
+    }
+
     private static void encodeEmsUserDataPayload(UserData uData)
         throws CodingException
     {
@@ -605,6 +644,8 @@
                 encode7bitEms(uData, headerData, true);
             } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
                 encode16bitEms(uData, headerData);
+            } else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) {
+                encode7bitAsciiEms(uData, headerData, true);
             } else {
                 throw new CodingException("unsupported EMS user data encoding (" +
                                           uData.msgEncoding + ")");
@@ -1056,15 +1097,18 @@
         throws CodingException
     {
         try {
-            offset *= 8;
+            int offsetBits = offset * 8;
+            int offsetSeptets = (offsetBits + 6) / 7;
+            numFields -= offsetSeptets;
+
             StringBuffer strBuf = new StringBuffer(numFields);
             BitwiseInputStream inStream = new BitwiseInputStream(data);
-            int wantedBits = (offset * 8) + (numFields * 7);
+            int wantedBits = (offsetSeptets * 7) + (numFields * 7);
             if (inStream.available() < wantedBits) {
                 throw new CodingException("insufficient data (wanted " + wantedBits +
                                           " bits, but only have " + inStream.available() + ")");
             }
-            inStream.skip(offset);
+            inStream.skip(offsetSeptets * 7);
             for (int i = 0; i < numFields; i++) {
                 int charCode = inStream.read(7);
                 if ((charCode >= UserData.ASCII_MAP_BASE_INDEX) &&
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 9080e23..1da5eac 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -864,8 +864,9 @@
             Rlog.d(LOG_TAG, "MO raw BearerData = '" + HexDump.toHexString(encodedBearerData) + "'");
         }
 
-        int teleservice = bearerData.hasUserDataHeader ?
-                SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT;
+        int teleservice = (bearerData.hasUserDataHeader
+                && userData.msgEncoding != UserData.ENCODING_7BIT_ASCII)
+                ? SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT;
 
         SmsEnvelope envelope = new SmsEnvelope();
         envelope.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 85bf6f2..582a5b8 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -294,22 +294,6 @@
       }
     }
 
-    if (el->FindAttribute("", "platformBuildVersionCode") == nullptr) {
-      auto versionCode = el->FindAttribute(xml::kSchemaAndroid, "versionCode");
-      if (versionCode != nullptr) {
-        el->attributes.push_back(xml::Attribute{"", "platformBuildVersionCode",
-                                                versionCode->value});
-      }
-    }
-
-    if (el->FindAttribute("", "platformBuildVersionName") == nullptr) {
-      auto versionName = el->FindAttribute(xml::kSchemaAndroid, "versionName");
-      if (versionName != nullptr) {
-        el->attributes.push_back(xml::Attribute{"", "platformBuildVersionName",
-                                                versionName->value});
-      }
-    }
-
     return true;
   });
 
@@ -489,8 +473,14 @@
 
     // Make sure we un-compile the value if it was set to something else.
     attr->compiled_value = {};
-
     attr->value = options_.compile_sdk_version.value();
+
+    attr = root->FindOrCreateAttribute("", "platformBuildVersionCode");
+
+    // Make sure we un-compile the value if it was set to something else.
+    attr->compiled_value = {};
+    attr->value = options_.compile_sdk_version.value();
+
   }
 
   if (options_.compile_sdk_version_codename) {
@@ -499,7 +489,12 @@
 
     // Make sure we un-compile the value if it was set to something else.
     attr->compiled_value = {};
+    attr->value = options_.compile_sdk_version_codename.value();
 
+    attr = root->FindOrCreateAttribute("", "platformBuildVersionName");
+
+    // Make sure we un-compile the value if it was set to something else.
+    attr->compiled_value = {};
     attr->value = options_.compile_sdk_version_codename.value();
   }
 
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index adea627..4842f62 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -725,6 +725,43 @@
   attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
   ASSERT_THAT(attr, NotNull());
   EXPECT_THAT(attr->value, StrEq("P"));
+
+  attr = manifest->root->FindAttribute("", "platformBuildVersionCode");
+  ASSERT_THAT(attr, NotNull());
+  EXPECT_THAT(attr->value, StrEq("28"));
+
+  attr = manifest->root->FindAttribute("", "platformBuildVersionName");
+  ASSERT_THAT(attr, NotNull());
+  EXPECT_THAT(attr->value, StrEq("P"));
+}
+
+TEST_F(ManifestFixerTest, OverrideCompileSdkVersions) {
+  std::string input = R"(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"
+          compileSdkVersion="27" compileSdkVersionCodename="O"
+          platformBuildVersionCode="27" platformBuildVersionName="O"/>)";
+  ManifestFixerOptions options;
+  options.compile_sdk_version = {"28"};
+  options.compile_sdk_version_codename = {"P"};
+
+  std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options);
+  ASSERT_THAT(manifest, NotNull());
+
+  xml::Attribute* attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersion");
+  ASSERT_THAT(attr, NotNull());
+  EXPECT_THAT(attr->value, StrEq("28"));
+
+  attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
+  ASSERT_THAT(attr, NotNull());
+  EXPECT_THAT(attr->value, StrEq("P"));
+
+  attr = manifest->root->FindAttribute("", "platformBuildVersionCode");
+  ASSERT_THAT(attr, NotNull());
+  EXPECT_THAT(attr->value, StrEq("28"));
+
+  attr = manifest->root->FindAttribute("", "platformBuildVersionName");
+  ASSERT_THAT(attr, NotNull());
+  EXPECT_THAT(attr->value, StrEq("P"));
 }
 
 TEST_F(ManifestFixerTest, UnexpectedElementsInManifest) {
@@ -750,59 +787,6 @@
   ASSERT_THAT(manifest, IsNull());
 }
 
-TEST_F(ManifestFixerTest, InsertPlatformBuildVersions) {
-  // Test for insertion when versionCode and versionName are included in the manifest
-  {
-    std::string input = R"(
-        <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"
-          android:versionCode="27" android:versionName="O"/>)";
-    std::unique_ptr<xml::XmlResource> manifest = Verify(input);
-    ASSERT_THAT(manifest, NotNull());
-
-    xml::Attribute* attr = manifest->root->FindAttribute("", "platformBuildVersionCode");
-    ASSERT_THAT(attr, NotNull());
-    EXPECT_THAT(attr->value, StrEq("27"));
-    attr = manifest->root->FindAttribute("", "platformBuildVersionName");
-    ASSERT_THAT(attr, NotNull());
-    EXPECT_THAT(attr->value, StrEq("O"));
-  }
-
-  // Test for insertion when versionCode and versionName defaults are specified
-  {
-    std::string input = R"(
-      <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"/>)";
-    ManifestFixerOptions options;
-    options.version_code_default = {"27"};
-    options.version_name_default = {"O"};
-    std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options);
-    ASSERT_THAT(manifest, NotNull());
-
-    xml::Attribute* attr = manifest->root->FindAttribute("", "platformBuildVersionCode");
-    ASSERT_THAT(attr, NotNull());
-    EXPECT_THAT(attr->value, StrEq("27"));
-    attr = manifest->root->FindAttribute("", "platformBuildVersionName");
-    ASSERT_THAT(attr, NotNull());
-    EXPECT_THAT(attr->value, StrEq("O"));
-  }
-
-  // Test that the platform build version attributes are not changed if they are currently present
-  {
-    std::string input = R"(
-        <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"
-          android:versionCode="28" android:versionName="P"
-          platformBuildVersionCode="27" platformBuildVersionName="O"/>)";
-    std::unique_ptr<xml::XmlResource> manifest = Verify(input);
-    ASSERT_THAT(manifest, NotNull());
-
-    xml::Attribute* attr = manifest->root->FindAttribute("", "platformBuildVersionCode");
-    ASSERT_THAT(attr, NotNull());
-    EXPECT_THAT(attr->value, StrEq("27"));
-    attr = manifest->root->FindAttribute("", "platformBuildVersionName");
-    ASSERT_THAT(attr, NotNull());
-    EXPECT_THAT(attr->value, StrEq("O"));
-  }
-}
-
 TEST_F(ManifestFixerTest, UsesLibraryMustHaveNonEmptyName) {
   std::string input = R"(
       <manifest xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 2cc1d83..5e5a595 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1149,9 +1149,6 @@
      * Return a list of all the networks configured for the current foreground
      * user.
      *
-     * Requires the same permissions as {@link #getScanResults}.
-     * If such access is not allowed, this API will always return an empty list.
-     *
      * Not all fields of WifiConfiguration are returned. Only the following
      * fields are filled in:
      * <ul>
@@ -1176,8 +1173,12 @@
      * when auto-connecting to wifi.
      * <b>Compatibility Note:</b> For applications targeting
      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will return an empty list,
-     * except to callers with Carrier privilege which will receive a restricted list only
-     * containing configurations which they created.
+     * except for:
+     * <ul>
+     * <li>Device Owner (DO) & Profile Owner (PO) apps will have access to the full list.
+     * <li>Callers with Carrier privilege will receive a restricted list only containing
+     * configurations which they created.
+     * </ul>
      */
     @Deprecated
     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
@@ -4721,7 +4722,6 @@
      *
      * @hide
      */
-    @SystemApi
     private static class EasyConnectCallbackProxy extends IDppCallback.Stub {
         private final Executor mExecutor;
         private final EasyConnectStatusCallback mEasyConnectStatusCallback;