Merge "Removed Settings.Global.LAST_ACTIVE_USER_ID." into rvc-dev
diff --git a/apex/permission/service/java/com/android/permission/persistence/IoUtils.java b/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
index 0ae4460..569a78c 100644
--- a/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
+++ b/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
@@ -20,6 +20,8 @@
 
 /**
  * Utility class for IO.
+ *
+ * @hide
  */
 public class IoUtils {
 
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 36a8b2c..81d059e 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -444,6 +444,11 @@
         TvTunerStateChanged tv_tuner_state_changed = 276 [(module) = "framework"];
         MediaOutputOpSwitchReported mediaoutput_op_switch_reported =
             277 [(module) = "settings"];
+        CellBroadcastMessageFiltered cb_message_filtered =
+            278 [(module) = "cellbroadcast"];
+        TvTunerDvrStatus tv_tuner_dvr_status = 279 [(module) = "framework"];
+        TvCasSessionOpenStatus tv_cas_session_open_status =
+            280 [(module) = "framework"];
 
         // StatsdStats tracks platform atoms with ids upto 500.
         // Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
@@ -9134,8 +9139,10 @@
 /**
  * Logs when a cell broadcast message is received on the device.
  *
- * Logged from CellBroadcastService module:
+ * Logged from Cell Broadcast module and platform:
  *   packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/
+ *   packages/apps/CellBroadcastReceiver/
+ *   frameworks/opt/telephony/src/java/com/android/internal/telephony/CellBroadcastServiceManager.java
  */
 message CellBroadcastMessageReported {
     // The type of Cell Broadcast message
@@ -9146,8 +9153,40 @@
         CDMA_SPC = 3;
     }
 
+    // The parts of the cell broadcast message pipeline
+    enum ReportSource {
+        UNKNOWN_SOURCE = 0;
+        FRAMEWORK = 1;
+        CB_SERVICE = 2;
+        CB_RECEIVER_APP = 3;
+    }
+
     // GSM, CDMA, CDMA-SCP
     optional CbType type = 1;
+
+    // The source of the report
+    optional ReportSource source = 2;
+}
+
+/**
+ * Logs when a cell broadcast message is filtered out, or otherwise intentionally not sent to CBR.
+ *
+ * Logged from CellBroadcastService module:
+ *   packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/
+ */
+message CellBroadcastMessageFiltered {
+    enum FilterReason {
+        NOT_FILTERED = 0;
+        DUPLICATE_MESSAGE = 1;
+        GEOFENCED_MESSAGE = 2;
+        AREA_INFO_MESSAGE = 3;
+    }
+
+    // GSM, CDMA, CDMA-SCP
+    optional CellBroadcastMessageReported.CbType type = 1;
+
+    // The source of the report
+    optional FilterReason filter = 2;
 }
 
 /**
@@ -9174,6 +9213,7 @@
         UNEXPECTED_GSM_MESSAGE_TYPE_FROM_FWK = 12;
         UNEXPECTED_CDMA_MESSAGE_TYPE_FROM_FWK = 13;
         UNEXPECTED_CDMA_SCP_MESSAGE_TYPE_FROM_FWK = 14;
+        NO_CONNECTION_TO_CB_SERVICE = 15;
     }
 
     // What kind of error occurred
@@ -9205,6 +9245,58 @@
     //  new state
     optional State state = 2;
 }
+
+/**
+ * Logs the status of a dvr playback or record.
+ * This is atom ID 279.
+ *
+ * Logged from:
+ *   frameworks/base/media/java/android/media/tv/tuner/dvr
+ */
+message TvTunerDvrStatus {
+    enum Type {
+        UNKNOWN_TYPE = 0;
+        PLAYBACK = 1; // is a playback
+        RECORD = 2; // is a record
+    }
+    enum State {
+        UNKNOWN_STATE = 0;
+        STARTED = 1; // DVR is started
+        STOPPED = 2; // DVR is stopped
+    }
+    // The uid of the application that sent this custom atom.
+    optional int32 uid = 1 [(is_uid) = true];
+    // DVR type
+    optional Type type = 2;
+    //  DVR state
+    optional State state = 3;
+    //  Identify the segment of a record or playback
+    optional int32 segment_id = 4;
+    // indicate how many overflow or underflow happened between started to stopped
+    optional int32 overflow_underflow_count = 5;
+}
+
+/**
+ * Logs when a cas session opened through MediaCas.
+ * This is atom ID 280.
+ *
+ * Logged from:
+ *   frameworks/base/media/java/android/media/MediaCas.java
+ */
+message TvCasSessionOpenStatus {
+    enum State {
+        UNKNOWN = 0;
+        SUCCEEDED = 1; // indicate that the session is opened successfully.
+        FAILED = 2; // indicate that the session isn’t opened successfully.
+    }
+    // The uid of the application that sent this custom atom.
+    optional int32 uid = 1 [(is_uid) = true];
+    //  Cas system Id
+    optional int32 cas_system_id = 2;
+    // State of the session
+    optional State state = 3;
+}
+
 /**
  * Logs when an app is frozen or unfrozen.
  *
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index ed0ea55..ac00a04 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -520,6 +520,12 @@
      */
     public static final int GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT = 13;
 
+    /**
+     * Action to show Launcher's all apps.
+     * @hide
+     */
+    public static final int GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS = 14;
+
     private static final String LOG_TAG = "AccessibilityService";
 
     /**
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index cffa59c..108b9ee 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3252,18 +3252,56 @@
     @Override
     public void handleFixedRotationAdjustments(@NonNull IBinder token,
             @Nullable FixedRotationAdjustments fixedRotationAdjustments) {
-        final Consumer<DisplayAdjustments> override = fixedRotationAdjustments != null
-                ? displayAdjustments -> displayAdjustments.setFixedRotationAdjustments(
-                        fixedRotationAdjustments)
-                : null;
+        handleFixedRotationAdjustments(token, fixedRotationAdjustments, null /* overrideConfig */);
+    }
+
+    /**
+     * Applies the rotation adjustments to override display information in resources belong to the
+     * provided token. If the token is activity token, the adjustments also apply to application
+     * because the appearance of activity is usually more sensitive to the application resources.
+     *
+     * @param token The token to apply the adjustments.
+     * @param fixedRotationAdjustments The information to override the display adjustments of
+     *                                 corresponding resources. If it is null, the exiting override
+     *                                 will be cleared.
+     * @param overrideConfig The override configuration of activity. It is used to override
+     *                       application configuration. If it is non-null, it means the token is
+     *                       confirmed as activity token. Especially when launching new activity,
+     *                       {@link #mActivities} hasn't put the new token.
+     */
+    private void handleFixedRotationAdjustments(@NonNull IBinder token,
+            @Nullable FixedRotationAdjustments fixedRotationAdjustments,
+            @Nullable Configuration overrideConfig) {
+        // The element of application configuration override is set only if the application
+        // adjustments are needed, because activity already has its own override configuration.
+        final Configuration[] appConfigOverride;
+        final Consumer<DisplayAdjustments> override;
+        if (fixedRotationAdjustments != null) {
+            appConfigOverride = new Configuration[1];
+            override = displayAdjustments -> {
+                displayAdjustments.setFixedRotationAdjustments(fixedRotationAdjustments);
+                if (appConfigOverride[0] != null) {
+                    displayAdjustments.getConfiguration().updateFrom(appConfigOverride[0]);
+                }
+            };
+        } else {
+            appConfigOverride = null;
+            override = null;
+        }
         if (!mResourcesManager.overrideTokenDisplayAdjustments(token, override)) {
             // No resources are associated with the token.
             return;
         }
-        if (mActivities.get(token) == null) {
-            // Only apply the override to application for activity token because the appearance of
-            // activity is usually more sensitive to the application resources.
-            return;
+        if (overrideConfig == null) {
+            final ActivityClientRecord r = mActivities.get(token);
+            if (r == null) {
+                // It is not an activity token. Nothing to do for application.
+                return;
+            }
+            overrideConfig = r.overrideConfig;
+        }
+        if (appConfigOverride != null) {
+            appConfigOverride[0] = overrideConfig;
         }
 
         // Apply the last override to application resources for compatibility. Because the Resources
@@ -3503,7 +3541,8 @@
         // The rotation adjustments must be applied before creating the activity, so the activity
         // can get the adjusted display info during creation.
         if (r.mPendingFixedRotationAdjustments != null) {
-            handleFixedRotationAdjustments(r.token, r.mPendingFixedRotationAdjustments);
+            handleFixedRotationAdjustments(r.token, r.mPendingFixedRotationAdjustments,
+                    r.overrideConfig);
             r.mPendingFixedRotationAdjustments = null;
         }
 
@@ -7388,6 +7427,10 @@
         }
     }
 
+    public Bundle getCoreSettings() {
+        return mCoreSettings;
+    }
+
     public int getIntCoreSetting(String key, int defaultValue) {
         synchronized (mResourcesManager) {
             if (mCoreSettings != null) {
@@ -7397,6 +7440,18 @@
         }
     }
 
+    /**
+     * Get the string value of the given key from core settings.
+     */
+    public String getStringCoreSetting(String key, String defaultValue) {
+        synchronized (mResourcesManager) {
+            if (mCoreSettings != null) {
+                return mCoreSettings.getString(key, defaultValue);
+            }
+            return defaultValue;
+        }
+    }
+
     float getFloatCoreSetting(String key, float defaultValue) {
         synchronized (mResourcesManager) {
             if (mCoreSettings != null) {
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 2d06ee8..b68639e 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -216,4 +216,14 @@
      *                             in {@link android.content.pm.ActivityInfo}.
      */
      void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation);
+
+    /**
+     * Called when a rotation is about to start on the foreground activity.
+     * This applies for:
+     *   * free sensor rotation
+     *   * forced rotation
+     *   * rotation settings set through adb command line
+     *   * rotation that occurs when rotation tile is toggled in quick settings
+     */
+     void onActivityRotation();
 }
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 10f7835..f9b48e7 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -38,6 +38,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.FileUtils;
+import android.os.GraphicsEnvironment;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Process;
@@ -46,6 +47,7 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.security.net.config.NetworkSecurityConfigProvider;
 import android.sysprop.VndkProperties;
 import android.text.TextUtils;
@@ -824,6 +826,32 @@
 
         final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
 
+        if (mActivityThread != null) {
+            final String gpuDebugApp = mActivityThread.getStringCoreSetting(
+                    Settings.Global.GPU_DEBUG_APP, "");
+            if (!gpuDebugApp.isEmpty() && mPackageName.equals(gpuDebugApp)) {
+
+                // The current application is used to debug, attempt to get the debug layers.
+                try {
+                    // Get the ApplicationInfo from PackageManager so that metadata fields present.
+                    final ApplicationInfo ai = ActivityThread.getPackageManager()
+                            .getApplicationInfo(mPackageName, PackageManager.GET_META_DATA,
+                                    UserHandle.myUserId());
+                    final String debugLayerPath = GraphicsEnvironment.getInstance()
+                            .getDebugLayerPathsFromSettings(mActivityThread.getCoreSettings(),
+                                    ActivityThread.getPackageManager(), mPackageName, ai);
+                    if (debugLayerPath != null) {
+                        libraryPermittedPath += File.pathSeparator + debugLayerPath;
+                    }
+                } catch (RemoteException e) {
+                    // Unlikely to fail for applications, but in case of failure, something is wrong
+                    // inside the system server, hence just skip.
+                    Slog.e(ActivityThread.TAG,
+                            "RemoteException when fetching debug layer paths for: " + mPackageName);
+                }
+            }
+        }
+
         // If we're not asked to include code, we construct a classloader that has
         // no code path included. We still need to set up the library search paths
         // and permitted path because NativeActivity relies on it (it attempts to
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 5d8daf8..843d1c7 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -199,4 +199,8 @@
     @Override
     public void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation) {
     }
+
+    @Override
+    public void onActivityRotation() {
+    }
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e331471..be3cfef 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1884,6 +1884,9 @@
 
     /**
      * Activity action: Launch UI to manage auto-revoke state.
+     *
+     * This is equivalent to Intent#ACTION_APPLICATION_DETAILS_SETTINGS
+     *
      * <p>
      * Input: {@link Intent#setData data} should be a {@code package}-scheme {@link Uri} with
      * a package name, whose auto-revoke state will be reviewed (mandatory).
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index ed75504..fc4ccd0 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1449,6 +1449,13 @@
         /** {@hide} */
         public static final int UID_UNKNOWN = -1;
 
+        /**
+         * This value is derived from the maximum file name length. No package above this limit
+         * can ever be successfully installed on the device.
+         * @hide
+         */
+        public static final int MAX_PACKAGE_NAME_LENGTH = 255;
+
         /** {@hide} */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public int mode = MODE_INVALID;
@@ -1642,6 +1649,8 @@
 
         /**
          * Optionally set a label representing the app being installed.
+         *
+         * This value will be trimmed to the first 1000 characters.
          */
         public void setAppLabel(@Nullable CharSequence appLabel) {
             this.appLabel = (appLabel != null) ? appLabel.toString() : null;
@@ -1711,7 +1720,8 @@
          *
          * <p>Initially, all restricted permissions are whitelisted but you can change
          * which ones are whitelisted by calling this method or the corresponding ones
-         * on the {@link PackageManager}.
+         * on the {@link PackageManager}. Only soft or hard restricted permissions on the current
+         * Android version are supported and any invalid entries will be removed.
          *
          * @see PackageManager#addWhitelistedRestrictedPermission(String, String, int)
          * @see PackageManager#removeWhitelistedRestrictedPermission(String, String, int)
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index f354bdb..65ce1e7 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -49,8 +49,16 @@
  * in the implementation of Parcelable in subclasses.
  */
 public class PackageItemInfo {
-    /** The maximum length of a safe label, in characters */
-    private static final int MAX_SAFE_LABEL_LENGTH = 50000;
+
+    /**
+     * The maximum length of a safe label, in characters
+     *
+     * TODO(b/157997155): It may make sense to expose this publicly so that apps can check for the
+     *  value and truncate the strings/use a different label, without having to hardcode and make
+     *  assumptions about the value.
+     * @hide
+     */
+    public static final int MAX_SAFE_LABEL_LENGTH = 1000;
 
     /** @hide */
     public static final float DEFAULT_MAX_LABEL_SIZE_PX = 500f;
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index f64560a..fb8fd74 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -302,7 +302,14 @@
         }
 
         String permission = array.getNonConfigurationString(permissionAttr, 0);
-        activity.setPermission(permission != null ? permission : pkg.getPermission());
+        if (isAlias) {
+            // An alias will override permissions to allow referencing an Activity through its alias
+            // without needing the original permission. If an alias needs the same permission,
+            // it must be re-declared.
+            activity.setPermission(permission);
+        } else {
+            activity.setPermission(permission != null ? permission : pkg.getPermission());
+        }
 
         final boolean setExported = array.hasValue(exportedAttr);
         if (setExported) {
diff --git a/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
index b37b617..6811e06 100644
--- a/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
@@ -20,7 +20,10 @@
 import android.annotation.Nullable;
 import android.content.pm.PackageManager;
 import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
 import android.content.pm.parsing.ParsingUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
@@ -29,9 +32,6 @@
 import android.util.TypedValue;
 
 import com.android.internal.annotations.VisibleForTesting;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.result.ParseInput;
-import android.content.pm.parsing.result.ParseResult;
 
 /** @hide */
 class ParsedComponentUtils {
@@ -60,16 +60,27 @@
         component.setName(className);
         component.setPackageName(packageName);
 
-        if (useRoundIcon) {
-            component.icon = array.getResourceId(roundIconAttr, 0);
+        int roundIconVal = useRoundIcon ? array.getResourceId(roundIconAttr, 0) : 0;
+        if (roundIconVal != 0) {
+            component.icon = roundIconVal;
+            component.nonLocalizedLabel = null;
+        } else {
+            int iconVal = array.getResourceId(iconAttr, 0);
+            if (iconVal != 0) {
+                component.icon = iconVal;
+                component.nonLocalizedLabel = null;
+            }
         }
 
-        if (component.icon == 0) {
-            component.icon = array.getResourceId(iconAttr, 0);
+        int logoVal = array.getResourceId(logoAttr, 0);
+        if (logoVal != 0) {
+            component.logo = logoVal;
         }
 
-        component.logo = array.getResourceId(logoAttr, 0);
-        component.banner = array.getResourceId(bannerAttr, 0);
+        int bannerVal = array.getResourceId(bannerAttr, 0);
+        if (bannerVal != 0) {
+            component.banner = bannerVal;
+        }
 
         if (descriptionAttr != null) {
             component.descriptionRes = array.getResourceId(descriptionAttr, 0);
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 6bc962b..2084065 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -18,6 +18,7 @@
 
 import static com.android.internal.os.RoSystemProperties.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -30,6 +31,7 @@
 import android.annotation.SystemService;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.os.Binder;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.util.ArrayMap;
@@ -40,6 +42,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 
 /**
  * The {@link HdmiControlManager} class is used to send HDMI control messages
@@ -818,6 +821,24 @@
             mHdmiControlStatusChangeListeners = new ArrayMap<>();
 
     /**
+     * Listener used to get the status of the HDMI CEC volume control feature (enabled/disabled).
+     * @hide
+     */
+    public interface HdmiCecVolumeControlFeatureListener {
+        /**
+         * Called when the HDMI Control (CEC) volume control feature is enabled/disabled.
+         *
+         * @param enabled status of HDMI CEC volume control feature
+         * @see {@link HdmiControlManager#setHdmiCecVolumeControlEnabled(boolean)} ()}
+         **/
+        void onHdmiCecVolumeControlFeature(boolean enabled);
+    }
+
+    private final ArrayMap<HdmiCecVolumeControlFeatureListener,
+            IHdmiCecVolumeControlFeatureListener>
+            mHdmiCecVolumeControlFeatureListeners = new ArrayMap<>();
+
+    /**
      * Listener used to get vendor-specific commands.
      */
     public interface VendorCommandListener {
@@ -979,4 +1000,76 @@
         };
     }
 
+    /**
+     * Adds a listener to get informed of changes to the state of the HDMI CEC volume control
+     * feature.
+     *
+     * Upon adding a listener, the current state of the HDMI CEC volume control feature will be
+     * sent immediately.
+     *
+     * <p>To stop getting the notification,
+     * use {@link #removeHdmiCecVolumeControlFeatureListener(HdmiCecVolumeControlFeatureListener)}.
+     *
+     * @param listener {@link HdmiCecVolumeControlFeatureListener} instance
+     * @hide
+     * @see #removeHdmiCecVolumeControlFeatureListener(HdmiCecVolumeControlFeatureListener)
+     */
+    @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+    public void addHdmiCecVolumeControlFeatureListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull HdmiCecVolumeControlFeatureListener listener) {
+        if (mService == null) {
+            Log.e(TAG, "HdmiControlService is not available");
+            return;
+        }
+        if (mHdmiCecVolumeControlFeatureListeners.containsKey(listener)) {
+            Log.e(TAG, "listener is already registered");
+            return;
+        }
+        IHdmiCecVolumeControlFeatureListener wrappedListener =
+                createHdmiCecVolumeControlFeatureListenerWrapper(executor, listener);
+        mHdmiCecVolumeControlFeatureListeners.put(listener, wrappedListener);
+        try {
+            mService.addHdmiCecVolumeControlFeatureListener(wrappedListener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Removes a listener to stop getting informed of changes to the state of the HDMI CEC volume
+     * control feature.
+     *
+     * @param listener {@link HdmiCecVolumeControlFeatureListener} instance to be removed
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+    public void removeHdmiCecVolumeControlFeatureListener(
+            HdmiCecVolumeControlFeatureListener listener) {
+        if (mService == null) {
+            Log.e(TAG, "HdmiControlService is not available");
+            return;
+        }
+        IHdmiCecVolumeControlFeatureListener wrappedListener =
+                mHdmiCecVolumeControlFeatureListeners.remove(listener);
+        if (wrappedListener == null) {
+            Log.e(TAG, "tried to remove not-registered listener");
+            return;
+        }
+        try {
+            mService.removeHdmiCecVolumeControlFeatureListener(wrappedListener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private IHdmiCecVolumeControlFeatureListener createHdmiCecVolumeControlFeatureListenerWrapper(
+            Executor executor, final HdmiCecVolumeControlFeatureListener listener) {
+        return new android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener.Stub() {
+            @Override
+            public void onHdmiCecVolumeControlFeature(boolean enabled) {
+                Binder.clearCallingIdentity();
+                executor.execute(() -> listener.onHdmiCecVolumeControlFeature(enabled));
+            }
+        };
+    }
 }
diff --git a/core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl b/core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl
new file mode 100644
index 0000000..873438b
--- /dev/null
+++ b/core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.hardware.hdmi;
+
+/**
+ * Listener used to get the status of the HDMI CEC volume control feature (enabled/disabled).
+ * @hide
+ */
+oneway interface IHdmiCecVolumeControlFeatureListener {
+
+    /**
+     * Called when the HDMI Control (CEC) volume control feature is enabled/disabled.
+     *
+     * @param enabled status of HDMI CEC volume control feature
+     * @see {@link HdmiControlManager#setHdmiCecVolumeControlEnabled(boolean)} ()}
+     **/
+    void onHdmiCecVolumeControlFeature(boolean enabled);
+}
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 3582a92..4c724ef 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.hdmi.IHdmiControlStatusChangeListener;
 import android.hardware.hdmi.IHdmiDeviceEventListener;
@@ -44,6 +45,8 @@
     void queryDisplayStatus(IHdmiControlCallback callback);
     void addHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener);
     void removeHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener);
+    void addHdmiCecVolumeControlFeatureListener(IHdmiCecVolumeControlFeatureListener listener);
+    void removeHdmiCecVolumeControlFeatureListener(IHdmiCecVolumeControlFeatureListener listener);
     void addHotplugEventListener(IHdmiHotplugEventListener listener);
     void removeHotplugEventListener(IHdmiHotplugEventListener listener);
     void addDeviceEventListener(IHdmiDeviceEventListener listener);
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 034e6a7..df58a6c 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -93,8 +94,8 @@
     private static final int GAME_DRIVER_GLOBAL_OPT_IN_OFF = 3;
 
     private ClassLoader mClassLoader;
-    private String mLayerPath;
-    private String mDebugLayerPath;
+    private String mLibrarySearchPaths;
+    private String mLibraryPermittedPaths;
 
     /**
      * Set up GraphicsEnvironment
@@ -185,118 +186,131 @@
     }
 
     /**
-     * Store the layer paths available to the loader.
+     * Store the class loader for namespace lookup later.
      */
     public void setLayerPaths(ClassLoader classLoader,
-                              String layerPath,
-                              String debugLayerPath) {
+                              String searchPaths,
+                              String permittedPaths) {
         // We have to store these in the class because they are set up before we
         // have access to the Context to properly set up GraphicsEnvironment
         mClassLoader = classLoader;
-        mLayerPath = layerPath;
-        mDebugLayerPath = debugLayerPath;
+        mLibrarySearchPaths = searchPaths;
+        mLibraryPermittedPaths = permittedPaths;
+    }
+
+    /**
+     * Returns the debug layer paths from settings.
+     * Returns null if:
+     *     1) The application process is not debuggable or layer injection metadata flag is not
+     *        true; Or
+     *     2) ENABLE_GPU_DEBUG_LAYERS is not true; Or
+     *     3) Package name is not equal to GPU_DEBUG_APP.
+     */
+    public String getDebugLayerPathsFromSettings(
+            Bundle coreSettings, IPackageManager pm, String packageName,
+            ApplicationInfo ai) {
+        if (!debugLayerEnabled(coreSettings, packageName, ai)) {
+            return null;
+        }
+        Log.i(TAG, "GPU debug layers enabled for " + packageName);
+        String debugLayerPaths = "";
+
+        // Grab all debug layer apps and add to paths.
+        final String gpuDebugLayerApps =
+                coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP, "");
+        if (!gpuDebugLayerApps.isEmpty()) {
+            Log.i(TAG, "GPU debug layer apps: " + gpuDebugLayerApps);
+            // If a colon is present, treat this as multiple apps, so Vulkan and GLES
+            // layer apps can be provided at the same time.
+            final String[] layerApps = gpuDebugLayerApps.split(":");
+            for (int i = 0; i < layerApps.length; i++) {
+                String paths = getDebugLayerAppPaths(pm, layerApps[i]);
+                if (!paths.isEmpty()) {
+                    // Append the path so files placed in the app's base directory will
+                    // override the external path
+                    debugLayerPaths += paths + File.pathSeparator;
+                }
+            }
+        }
+        return debugLayerPaths;
     }
 
     /**
      * Return the debug layer app's on-disk and in-APK lib directories
      */
-    private static String getDebugLayerAppPaths(PackageManager pm, String app) {
+    private static String getDebugLayerAppPaths(IPackageManager pm, String packageName) {
         final ApplicationInfo appInfo;
         try {
-            appInfo = pm.getApplicationInfo(app, PackageManager.MATCH_ALL);
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(TAG, "Debug layer app '" + app + "' not installed");
-
-            return null;
+            appInfo = pm.getApplicationInfo(packageName, PackageManager.MATCH_ALL,
+                    UserHandle.myUserId());
+        } catch (RemoteException e) {
+            return "";
+        }
+        if (appInfo == null) {
+            Log.w(TAG, "Debug layer app '" + packageName + "' not installed");
         }
 
         final String abi = chooseAbi(appInfo);
-
         final StringBuilder sb = new StringBuilder();
         sb.append(appInfo.nativeLibraryDir)
-            .append(File.pathSeparator);
-        sb.append(appInfo.sourceDir)
+            .append(File.pathSeparator)
+            .append(appInfo.sourceDir)
             .append("!/lib/")
             .append(abi);
         final String paths = sb.toString();
-
         if (DEBUG) Log.v(TAG, "Debug layer app libs: " + paths);
 
         return paths;
     }
 
-    /**
-     * Set up layer search paths for all apps
-     * If debuggable, check for additional debug settings
-     */
-    private void setupGpuLayers(
-            Context context, Bundle coreSettings, PackageManager pm, String packageName,
-            ApplicationInfo ai) {
-        String layerPaths = "";
-
+    private boolean debugLayerEnabled(Bundle coreSettings, String packageName, ApplicationInfo ai) {
         // Only enable additional debug functionality if the following conditions are met:
         // 1. App is debuggable or device is rooted or layer injection metadata flag is true
         // 2. ENABLE_GPU_DEBUG_LAYERS is true
         // 3. Package name is equal to GPU_DEBUG_APP
+        if (!isDebuggable() && !canInjectLayers(ai)) {
+            return false;
+        }
+        final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
+        if (enable == 0) {
+            return false;
+        }
+        final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP, "");
+        if (packageName == null
+                || (gpuDebugApp.isEmpty() || packageName.isEmpty())
+                || !gpuDebugApp.equals(packageName)) {
+            return false;
+        }
+        return true;
+    }
 
-        if (isDebuggable() || canInjectLayers(ai)) {
+    /**
+     * Set up layer search paths for all apps
+     */
+    private void setupGpuLayers(
+            Context context, Bundle coreSettings, PackageManager pm, String packageName,
+            ApplicationInfo ai) {
+        final boolean enabled = debugLayerEnabled(coreSettings, packageName, ai);
+        String layerPaths = "";
+        if (enabled) {
+            layerPaths = mLibraryPermittedPaths;
 
-            final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
+            final String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
+            Log.i(TAG, "Vulkan debug layer list: " + layers);
+            if (layers != null && !layers.isEmpty()) {
+                setDebugLayers(layers);
+            }
 
-            if (enable != 0) {
-
-                final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);
-
-                if ((gpuDebugApp != null && packageName != null)
-                        && (!gpuDebugApp.isEmpty() && !packageName.isEmpty())
-                        && gpuDebugApp.equals(packageName)) {
-                    Log.i(TAG, "GPU debug layers enabled for " + packageName);
-
-                    // Prepend the debug layer path as a searchable path.
-                    // This will ensure debug layers added will take precedence over
-                    // the layers specified by the app.
-                    layerPaths = mDebugLayerPath + ":";
-
-                    // If there is a debug layer app specified, add its path.
-                    final String gpuDebugLayerApp =
-                            coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP);
-
-                    if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
-                        Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
-                        // If a colon is present, treat this as multiple apps, so Vulkan and GLES
-                        // layer apps can be provided at the same time.
-                        String[] layerApps = gpuDebugLayerApp.split(":");
-                        for (int i = 0; i < layerApps.length; i++) {
-                            String paths = getDebugLayerAppPaths(pm, layerApps[i]);
-                            if (paths != null) {
-                                // Append the path so files placed in the app's base directory will
-                                // override the external path
-                                layerPaths += paths + ":";
-                            }
-                        }
-                    }
-
-                    final String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
-
-                    Log.i(TAG, "Vulkan debug layer list: " + layers);
-                    if (layers != null && !layers.isEmpty()) {
-                        setDebugLayers(layers);
-                    }
-
-                    final String layersGLES =
-                            coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES);
-
-                    Log.i(TAG, "GLES debug layer list: " + layersGLES);
-                    if (layersGLES != null && !layersGLES.isEmpty()) {
-                        setDebugLayersGLES(layersGLES);
-                    }
-                }
+            final String layersGLES =
+                    coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES);
+            Log.i(TAG, "GLES debug layer list: " + layersGLES);
+            if (layersGLES != null && !layersGLES.isEmpty()) {
+                setDebugLayersGLES(layersGLES);
             }
         }
 
         // Include the app's lib directory in all cases
-        layerPaths += mLayerPath;
-
+        layerPaths += mLibrarySearchPaths;
         setLayerPaths(mClassLoader, layerPaths);
     }
 
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7845200..a8391c2 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4090,13 +4090,6 @@
     public static int getMaxSupportedUsers() {
         // Don't allow multiple users on certain builds
         if (android.os.Build.ID.startsWith("JVP")) return 1;
-        if (ActivityManager.isLowRamDeviceStatic()) {
-            // Low-ram devices are Svelte. Most of the time they don't get multi-user.
-            if ((Resources.getSystem().getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK)
-                    != Configuration.UI_MODE_TYPE_TELEVISION) {
-                return 1;
-            }
-        }
         return SystemProperties.getInt("fw.max_users",
                 Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers));
     }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a8af310..e10fcea 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1778,6 +1778,15 @@
             = "android.settings.NOTIFICATION_SETTINGS";
 
     /**
+     * Activity Action: Show conversation settings.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_CONVERSATION_SETTINGS
+            = "android.settings.CONVERSATION_SETTINGS";
+
+    /**
      * Activity Action: Show notification history screen.
      *
      * @hide
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index b34268d..a2489b9 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -4325,6 +4325,15 @@
         public static final String ETWS_WARNING_TYPE = "etws_warning_type";
 
         /**
+         * ETWS (Earthquake and Tsunami Warning System) primary message or not (ETWS alerts only).
+         * <p>See {@link android.telephony.SmsCbEtwsInfo}</p>
+         * <P>Type: BOOLEAN</P>
+         *
+         * @hide        // TODO: Unhide this for S.
+         */
+        public static final String ETWS_IS_PRIMARY = "etws_is_primary";
+
+        /**
          * CMAS (Commercial Mobile Alert System) message class (CMAS alerts only).
          * <p>See {@link android.telephony.SmsCbCmasInfo}</p>
          * <P>Type: INTEGER</P>
@@ -4464,37 +4473,6 @@
                 CMAS_URGENCY,
                 CMAS_CERTAINTY
         };
-
-        /**
-         * Query columns for instantiating {@link android.telephony.SmsCbMessage} objects.
-         * @hide
-         */
-        public static final String[] QUERY_COLUMNS_FWK = {
-                _ID,
-                SLOT_INDEX,
-                SUBSCRIPTION_ID,
-                GEOGRAPHICAL_SCOPE,
-                PLMN,
-                LAC,
-                CID,
-                SERIAL_NUMBER,
-                SERVICE_CATEGORY,
-                LANGUAGE_CODE,
-                MESSAGE_BODY,
-                MESSAGE_FORMAT,
-                MESSAGE_PRIORITY,
-                ETWS_WARNING_TYPE,
-                CMAS_MESSAGE_CLASS,
-                CMAS_CATEGORY,
-                CMAS_RESPONSE_TYPE,
-                CMAS_SEVERITY,
-                CMAS_URGENCY,
-                CMAS_CERTAINTY,
-                RECEIVED_TIME,
-                MESSAGE_BROADCASTED,
-                GEOMETRIES,
-                MAXIMUM_WAIT_TIME
-        };
     }
 
     /**
diff --git a/core/java/android/service/autofill/InlineSuggestionRoot.java b/core/java/android/service/autofill/InlineSuggestionRoot.java
index c879653..16c3f1d 100644
--- a/core/java/android/service/autofill/InlineSuggestionRoot.java
+++ b/core/java/android/service/autofill/InlineSuggestionRoot.java
@@ -58,7 +58,9 @@
             case MotionEvent.ACTION_DOWN: {
                 mDownX = event.getX();
                 mDownY = event.getY();
-            } break;
+            }
+            // Intentionally fall through to the next case so that when the window is obscured
+            // we transfer the touch to the remote IME window and don't handle it locally.
 
             case MotionEvent.ACTION_MOVE: {
                 final float distance = MathUtils.dist(mDownX, mDownY,
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index a9af595..f6c72c4 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -289,11 +289,6 @@
     private VelocityTracker mVelocityTracker;
 
     /**
-     * True if the detector can throw exception when touch steam is unexpected .
-     */
-    private boolean mExceptionForTouchStream;
-
-    /**
      * Consistency verifier for debugging purposes.
      */
     private final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
@@ -472,8 +467,6 @@
         mTouchSlopSquare = touchSlop * touchSlop;
         mDoubleTapTouchSlopSquare = doubleTapTouchSlop * doubleTapTouchSlop;
         mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop;
-        mExceptionForTouchStream = context != null
-                && context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R;
     }
 
     /**
@@ -646,13 +639,6 @@
                 break;
 
             case MotionEvent.ACTION_MOVE:
-                if (mExceptionForTouchStream && !mStillDown) {
-                    throw new IllegalStateException("Incomplete event stream received: "
-                            + "Received ACTION_MOVE before ACTION_DOWN. ACTION_DOWN must precede "
-                            + "ACTION_MOVE following ACTION_UP or ACTION_CANCEL, or when this "
-                            + "GestureDetector has not yet received any events.");
-                }
-
                 if (mInLongPress || mInContextClick) {
                     break;
                 }
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 7042f29..4a65511 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -205,6 +205,8 @@
      * <p>Note that if the {@link WebChromeClient} is set to be {@code null},
      * or if {@link WebChromeClient} is not set at all, the default dialog will
      * be suppressed and Javascript execution will continue immediately.
+     * <p>Note that the default dialog does not inherit the {@link
+     * android.view.Display#FLAG_SECURE} flag from the parent window.
      *
      * @param view The WebView that initiated the callback.
      * @param url The url of the page requesting the dialog.
@@ -240,6 +242,8 @@
      * or if {@link WebChromeClient} is not set at all, the default dialog will
      * be suppressed and the default value of {@code false} will be returned to
      * the JavaScript code immediately.
+     * <p>Note that the default dialog does not inherit the {@link
+     * android.view.Display#FLAG_SECURE} flag from the parent window.
      *
      * @param view The WebView that initiated the callback.
      * @param url The url of the page requesting the dialog.
@@ -274,6 +278,8 @@
      * or if {@link WebChromeClient} is not set at all, the default dialog will
      * be suppressed and {@code null} will be returned to the JavaScript code
      * immediately.
+     * <p>Note that the default dialog does not inherit the {@link
+     * android.view.Display#FLAG_SECURE} flag from the parent window.
      *
      * @param view The WebView that initiated the callback.
      * @param url The url of the page requesting the dialog.
@@ -308,6 +314,8 @@
      * <p>Note that if the {@link WebChromeClient} is set to be {@code null},
      * or if {@link WebChromeClient} is not set at all, the default dialog will
      * be suppressed and the navigation will be resumed immediately.
+     * <p>Note that the default dialog does not inherit the {@link
+     * android.view.Display#FLAG_SECURE} flag from the parent window.
      *
      * @param view The WebView that initiated the callback.
      * @param url The url of the page requesting the dialog.
diff --git a/core/java/android/window/VirtualDisplayTaskEmbedder.java b/core/java/android/window/VirtualDisplayTaskEmbedder.java
index d2614da..9ccb4c1 100644
--- a/core/java/android/window/VirtualDisplayTaskEmbedder.java
+++ b/core/java/android/window/VirtualDisplayTaskEmbedder.java
@@ -365,8 +365,8 @@
             // Found the topmost stack on target display. Now check if the topmost task's
             // description changed.
             if (taskInfo.taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
-                mHost.onTaskBackgroundColorChanged(VirtualDisplayTaskEmbedder.this,
-                        taskInfo.taskDescription.getBackgroundColor());
+                mHost.post(()-> mHost.onTaskBackgroundColorChanged(VirtualDisplayTaskEmbedder.this,
+                        taskInfo.taskDescription.getBackgroundColor()));
             }
         }
 
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index 493865a..b723db2 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -151,6 +151,13 @@
                     mOnProfileSelectedListener.onProfileSelected(position);
                 }
             }
+
+            @Override
+            public void onPageScrollStateChanged(int state) {
+                if (mOnProfileSelectedListener != null) {
+                    mOnProfileSelectedListener.onProfilePageStateChanged(state);
+                }
+            }
         });
         viewPager.setAdapter(this);
         viewPager.setCurrentItem(mCurrentPage);
@@ -606,6 +613,17 @@
          * {@link #PROFILE_WORK} if the work profile was selected.
          */
         void onProfileSelected(int profileIndex);
+
+
+        /**
+         * Callback for when the scroll state changes. Useful for discovering when the user begins
+         * dragging, when the pager is automatically settling to the current page, or when it is
+         * fully stopped/idle.
+         * @param state {@link ViewPager#SCROLL_STATE_IDLE}, {@link ViewPager#SCROLL_STATE_DRAGGING}
+         *              or {@link ViewPager#SCROLL_STATE_SETTLING}
+         * @see ViewPager.OnPageChangeListener#onPageScrollStateChanged
+         */
+        void onProfilePageStateChanged(int state);
     }
 
     /**
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 2a43287..049a76c 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -102,6 +102,7 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.Button;
@@ -129,6 +130,7 @@
 import com.android.internal.widget.GridLayoutManager;
 import com.android.internal.widget.RecyclerView;
 import com.android.internal.widget.ResolverDrawerLayout;
+import com.android.internal.widget.ViewPager;
 
 import com.google.android.collect.Lists;
 
@@ -204,6 +206,10 @@
     public static final int SELECTION_TYPE_STANDARD = 3;
     public static final int SELECTION_TYPE_COPY = 4;
 
+    private static final int SCROLL_STATUS_IDLE = 0;
+    private static final int SCROLL_STATUS_SCROLLING_VERTICAL = 1;
+    private static final int SCROLL_STATUS_SCROLLING_HORIZONTAL = 2;
+
     // statsd logger wrapper
     protected ChooserActivityLogger mChooserActivityLogger;
 
@@ -293,6 +299,7 @@
     protected MetricsLogger mMetricsLogger;
 
     private ContentPreviewCoordinator mPreviewCoord;
+    private int mScrollStatus = SCROLL_STATUS_IDLE;
 
     @VisibleForTesting
     protected ChooserMultiProfilePagerAdapter mChooserMultiProfilePagerAdapter;
@@ -2680,7 +2687,7 @@
                         offset = Math.min(offset, minHeight);
                     }
                 } else {
-                    ViewGroup currentEmptyStateView = getCurrentEmptyStateView();
+                    ViewGroup currentEmptyStateView = getActiveEmptyStateView();
                     if (currentEmptyStateView.getVisibility() == View.VISIBLE) {
                         offset += currentEmptyStateView.getHeight();
                     }
@@ -2705,7 +2712,7 @@
         return -1;
     }
 
-    private ViewGroup getCurrentEmptyStateView() {
+    private ViewGroup getActiveEmptyStateView() {
         int currentPage = mChooserMultiProfilePagerAdapter.getCurrentPage();
         return mChooserMultiProfilePagerAdapter.getItem(currentPage).getEmptyStateView();
     }
@@ -2822,10 +2829,20 @@
         final float defaultElevation = elevatedView.getElevation();
         final float chooserHeaderScrollElevation =
                 getResources().getDimensionPixelSize(R.dimen.chooser_header_scroll_elevation);
-
         mChooserMultiProfilePagerAdapter.getActiveAdapterView().addOnScrollListener(
                 new RecyclerView.OnScrollListener() {
                     public void onScrollStateChanged(RecyclerView view, int scrollState) {
+                        if (scrollState == RecyclerView.SCROLL_STATE_IDLE) {
+                            if (mScrollStatus == SCROLL_STATUS_SCROLLING_VERTICAL) {
+                                mScrollStatus = SCROLL_STATUS_IDLE;
+                                setHorizontalScrollingEnabled(true);
+                            }
+                        } else if (scrollState == RecyclerView.SCROLL_STATE_DRAGGING) {
+                            if (mScrollStatus == SCROLL_STATUS_IDLE) {
+                                mScrollStatus = SCROLL_STATUS_SCROLLING_VERTICAL;
+                                setHorizontalScrollingEnabled(false);
+                            }
+                        }
                     }
 
                     public void onScrolled(RecyclerView view, int dx, int dy) {
@@ -3026,8 +3043,42 @@
         currentRootAdapter.updateDirectShareExpansion();
     }
 
-    void prepareIntentForCrossProfileLaunch(Intent intent) {
-        intent.fixUris(UserHandle.myUserId());
+    @Override
+    protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+        if (shouldShowTabs()) {
+            mChooserMultiProfilePagerAdapter
+                    .setEmptyStateBottomOffset(insets.getSystemWindowInsetBottom());
+            mChooserMultiProfilePagerAdapter.setupContainerPadding(
+                    getActiveEmptyStateView().findViewById(R.id.resolver_empty_state_container));
+        }
+        return super.onApplyWindowInsets(v, insets);
+    }
+
+    private void setHorizontalScrollingEnabled(boolean enabled) {
+        ResolverViewPager viewPager = findViewById(R.id.profile_pager);
+        viewPager.setSwipingEnabled(enabled);
+    }
+
+    private void setVerticalScrollEnabled(boolean enabled) {
+        ChooserGridLayoutManager layoutManager =
+                (ChooserGridLayoutManager) mChooserMultiProfilePagerAdapter.getActiveAdapterView()
+                        .getLayoutManager();
+        layoutManager.setVerticalScrollEnabled(enabled);
+    }
+
+    @Override
+    void onHorizontalSwipeStateChanged(int state) {
+        if (state == ViewPager.SCROLL_STATE_DRAGGING) {
+            if (mScrollStatus == SCROLL_STATUS_IDLE) {
+                mScrollStatus = SCROLL_STATUS_SCROLLING_HORIZONTAL;
+                setVerticalScrollEnabled(false);
+            }
+        } else if (state == ViewPager.SCROLL_STATE_IDLE) {
+            if (mScrollStatus == SCROLL_STATUS_SCROLLING_VERTICAL) {
+                mScrollStatus = SCROLL_STATUS_IDLE;
+                setVerticalScrollEnabled(true);
+            }
+        }
     }
 
     /**
diff --git a/core/java/com/android/internal/app/ChooserGridLayoutManager.java b/core/java/com/android/internal/app/ChooserGridLayoutManager.java
index 317a987..c50ebd9 100644
--- a/core/java/com/android/internal/app/ChooserGridLayoutManager.java
+++ b/core/java/com/android/internal/app/ChooserGridLayoutManager.java
@@ -28,6 +28,8 @@
  */
 public class ChooserGridLayoutManager extends GridLayoutManager {
 
+    private boolean mVerticalScrollEnabled = true;
+
     /**
      * Constructor used when layout manager is set in XML by RecyclerView attribute
      * "layoutManager". If spanCount is not specified in the XML, it defaults to a
@@ -67,4 +69,13 @@
         // Do not count the footer view in the official count
         return super.getRowCountForAccessibility(recycler, state) - 1;
     }
+
+    void setVerticalScrollEnabled(boolean verticalScrollEnabled) {
+        mVerticalScrollEnabled = verticalScrollEnabled;
+    }
+
+    @Override
+    public boolean canScrollVertically() {
+        return mVerticalScrollEnabled && super.canScrollVertically();
+    }
 }
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index 774be3c..ffa6041 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -38,6 +38,7 @@
 
     private final ChooserProfileDescriptor[] mItems;
     private final boolean mIsSendAction;
+    private int mBottomOffset;
 
     ChooserMultiProfilePagerAdapter(Context context,
             ChooserActivity.ChooserGridAdapter adapter,
@@ -245,6 +246,16 @@
         }
     }
 
+    void setEmptyStateBottomOffset(int bottomOffset) {
+        mBottomOffset = bottomOffset;
+    }
+
+    @Override
+    protected void setupContainerPadding(View container) {
+        container.setPadding(container.getPaddingLeft(), container.getPaddingTop(),
+                container.getPaddingRight(), container.getPaddingBottom() + mBottomOffset);
+    }
+
     class ChooserProfileDescriptor extends ProfileDescriptor {
         private ChooserActivity.ChooserGridAdapter chooserGridAdapter;
         private RecyclerView recyclerView;
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index e65d1fe..61a52bc 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
 
+import static com.android.internal.app.ResolverActivity.EXTRA_CALLING_USER;
 import static com.android.internal.app.ResolverActivity.EXTRA_SELECTED_PROFILE;
 
 import android.annotation.Nullable;
@@ -246,6 +247,7 @@
         int selectedProfile = findSelectedProfile(className);
         sanitizeIntent(intentReceived);
         intentReceived.putExtra(EXTRA_SELECTED_PROFILE, selectedProfile);
+        intentReceived.putExtra(EXTRA_CALLING_USER, UserHandle.of(callingUserId));
         startActivityAsCaller(intentReceived, null, null, false, userId);
         finish();
     }
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index f96f560..f8eec57 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -184,6 +184,18 @@
     static final String EXTRA_SELECTED_PROFILE =
             "com.android.internal.app.ResolverActivity.EXTRA_SELECTED_PROFILE";
 
+    /**
+     * {@link UserHandle} extra to indicate the user of the user that the starting intent
+     * originated from.
+     * <p>This is not necessarily the same as {@link #getUserId()} or {@link UserHandle#myUserId()},
+     * as there are edge cases when the intent resolver is launched in the other profile.
+     * For example, when we have 0 resolved apps in current profile and multiple resolved
+     * apps in the other profile, opening a link from the current profile launches the intent
+     * resolver in the other one. b/148536209 for more info.
+     */
+    static final String EXTRA_CALLING_USER =
+            "com.android.internal.app.ResolverActivity.EXTRA_CALLING_USER";
+
     static final int PROFILE_PERSONAL = AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL;
     static final int PROFILE_WORK = AbstractMultiProfilePagerAdapter.PROFILE_WORK;
 
@@ -470,17 +482,20 @@
         // the intent resolver is started in the other profile. Since this is the only case when
         // this happens, we check for it here and set the current profile's tab.
         int selectedProfile = getCurrentProfile();
-        UserHandle intentUser = UserHandle.of(getLaunchingUserId());
+        UserHandle intentUser = getIntent().hasExtra(EXTRA_CALLING_USER)
+                ? getIntent().getParcelableExtra(EXTRA_CALLING_USER)
+                : getUser();
         if (!getUser().equals(intentUser)) {
             if (getPersonalProfileUserHandle().equals(intentUser)) {
                 selectedProfile = PROFILE_PERSONAL;
             } else if (getWorkProfileUserHandle().equals(intentUser)) {
                 selectedProfile = PROFILE_WORK;
             }
-        }
-        int selectedProfileExtra = getSelectedProfileExtra();
-        if (selectedProfileExtra != -1) {
-            selectedProfile = selectedProfileExtra;
+        } else {
+            int selectedProfileExtra = getSelectedProfileExtra();
+            if (selectedProfileExtra != -1) {
+                selectedProfile = selectedProfileExtra;
+            }
         }
         // We only show the default app for the profile of the current user. The filterLastUsed
         // flag determines whether to show a default app and that app is not shown in the
@@ -535,22 +550,6 @@
         return selectedProfile;
     }
 
-    /**
-     * Returns the user id of the user that the starting intent originated from.
-     * <p>This is not necessarily equal to {@link #getUserId()} or {@link UserHandle#myUserId()},
-     * as there are edge cases when the intent resolver is launched in the other profile.
-     * For example, when we have 0 resolved apps in current profile and multiple resolved apps
-     * in the other profile, opening a link from the current profile launches the intent resolver
-     * in the other one. b/148536209 for more info.
-     */
-    private int getLaunchingUserId() {
-        int contentUserHint = getIntent().getContentUserHint();
-        if (contentUserHint == UserHandle.USER_CURRENT) {
-            return UserHandle.myUserId();
-        }
-        return contentUserHint;
-    }
-
     protected @Profile int getCurrentProfile() {
         return (UserHandle.myUserId() == UserHandle.USER_SYSTEM ? PROFILE_PERSONAL : PROFILE_WORK);
     }
@@ -1250,7 +1249,9 @@
         return true;
     }
 
-    void prepareIntentForCrossProfileLaunch(Intent intent) {}
+    private void prepareIntentForCrossProfileLaunch(Intent intent) {
+        intent.fixUris(UserHandle.myUserId());
+    }
 
     private boolean isLaunchingTargetInOtherProfile() {
         return mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier()
@@ -1653,10 +1654,18 @@
         viewPager.setVisibility(View.VISIBLE);
         tabHost.setCurrentTab(mMultiProfilePagerAdapter.getCurrentPage());
         mMultiProfilePagerAdapter.setOnProfileSelectedListener(
-                index -> {
-                    tabHost.setCurrentTab(index);
-                    resetButtonBar();
-                    resetCheckedItem();
+                new AbstractMultiProfilePagerAdapter.OnProfileSelectedListener() {
+                    @Override
+                    public void onProfileSelected(int index) {
+                        tabHost.setCurrentTab(index);
+                        resetButtonBar();
+                        resetCheckedItem();
+                    }
+
+                    @Override
+                    public void onProfilePageStateChanged(int state) {
+                        onHorizontalSwipeStateChanged(state);
+                    }
                 });
         mMultiProfilePagerAdapter.setOnSwitchOnWorkSelectedListener(
                 () -> {
@@ -1668,6 +1677,8 @@
         findViewById(R.id.resolver_tab_divider).setVisibility(View.VISIBLE);
     }
 
+    void onHorizontalSwipeStateChanged(int state) {}
+
     private void maybeHideDivider() {
         if (!isIntentPicker()) {
             return;
diff --git a/core/java/com/android/internal/app/ResolverViewPager.java b/core/java/com/android/internal/app/ResolverViewPager.java
index 4eb6e3b..9cdfc2f 100644
--- a/core/java/com/android/internal/app/ResolverViewPager.java
+++ b/core/java/com/android/internal/app/ResolverViewPager.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.View;
 
 import com.android.internal.widget.ViewPager;
@@ -30,6 +31,8 @@
  */
 public class ResolverViewPager extends ViewPager {
 
+    private boolean mSwipingEnabled = true;
+
     public ResolverViewPager(Context context) {
         super(context);
     }
@@ -70,4 +73,13 @@
         heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
+
+    void setSwipingEnabled(boolean swipingEnabled) {
+        mSwipingEnabled = swipingEnabled;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        return mSwipingEnabled && super.onInterceptTouchEvent(ev);
+    }
 }
diff --git a/core/java/com/android/internal/logging/UiEventLogger.java b/core/java/com/android/internal/logging/UiEventLogger.java
index 67ffd4d..5212265 100644
--- a/core/java/com/android/internal/logging/UiEventLogger.java
+++ b/core/java/com/android/internal/logging/UiEventLogger.java
@@ -60,4 +60,28 @@
      */
     void logWithInstanceId(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
             @Nullable InstanceId instance);
+
+    /**
+     * Log an event with ranked-choice information along with package.
+     * Does nothing if event.getId() <= 0.
+     * @param event an enum implementing UiEventEnum interface.
+     * @param uid the uid of the relevant app, if known (0 otherwise).
+     * @param packageName the package name of the relevant app, if known (null otherwise).
+     * @param position the position picked.
+     */
+    void logWithPosition(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
+            int position);
+
+    /**
+     * Log an event with ranked-choice information along with package and instance ID.
+     * Does nothing if event.getId() <= 0.
+     * @param event an enum implementing UiEventEnum interface.
+     * @param uid the uid of the relevant app, if known (0 otherwise).
+     * @param packageName the package name of the relevant app, if known (null otherwise).
+     * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to
+     *                 logWithPosition().
+     * @param position the position picked.
+     */
+    void logWithInstanceIdAndPosition(@NonNull UiEventEnum event, int uid,
+            @Nullable String packageName, @Nullable InstanceId instance, int position);
 }
diff --git a/core/java/com/android/internal/logging/UiEventLoggerImpl.java b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
index 4d171ec..c9156c1 100644
--- a/core/java/com/android/internal/logging/UiEventLoggerImpl.java
+++ b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
@@ -48,4 +48,31 @@
             log(event, uid, packageName);
         }
     }
+
+    @Override
+    public void logWithPosition(UiEventEnum event, int uid, String packageName, int position) {
+        final int eventID = event.getId();
+        if (eventID > 0) {
+            FrameworkStatsLog.write(FrameworkStatsLog.RANKING_SELECTED,
+                    /* event_id = 1 */ eventID,
+                    /* package_name = 2 */ packageName,
+                    /* instance_id = 3 */ 0,
+                    /* position_picked = 4 */ position);
+        }
+    }
+
+    @Override
+    public void logWithInstanceIdAndPosition(UiEventEnum event, int uid, String packageName,
+            InstanceId instance, int position) {
+        final int eventID = event.getId();
+        if ((eventID > 0)  && (instance != null)) {
+            FrameworkStatsLog.write(FrameworkStatsLog.RANKING_SELECTED,
+                    /* event_id = 1 */ eventID,
+                    /* package_name = 2 */ packageName,
+                    /* instance_id = 3 */ instance.getId(),
+                    /* position_picked = 4 */ position);
+        } else {
+            logWithPosition(event, uid, packageName, position);
+        }
+    }
 }
diff --git a/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
index 180ab08..2d09434 100644
--- a/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
+++ b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
@@ -35,13 +35,15 @@
         public final int eventId;
         public final int uid;
         public final String packageName;
-        public final InstanceId instanceId;  // Used only for WithInstanceId variant
+        public final InstanceId instanceId;  // Used only for WithInstanceId variants
+        public final int position;  // Used only for Position variants
 
         FakeUiEvent(int eventId, int uid, String packageName) {
             this.eventId = eventId;
             this.uid = uid;
             this.packageName = packageName;
             this.instanceId = null;
+            this.position = 0;
         }
 
         FakeUiEvent(int eventId, int uid, String packageName, InstanceId instanceId) {
@@ -49,6 +51,15 @@
             this.uid = uid;
             this.packageName = packageName;
             this.instanceId = instanceId;
+            this.position = 0;
+        }
+
+        FakeUiEvent(int eventId, int uid, String packageName, InstanceId instanceId, int position) {
+            this.eventId = eventId;
+            this.uid = uid;
+            this.packageName = packageName;
+            this.instanceId = instanceId;
+            this.position = position;
         }
     }
 
@@ -92,4 +103,21 @@
             mLogs.add(new FakeUiEvent(eventId, uid, packageName, instance));
         }
     }
+
+    @Override
+    public void logWithPosition(UiEventEnum event, int uid, String packageName, int position) {
+        final int eventId = event.getId();
+        if (eventId > 0) {
+            mLogs.add(new FakeUiEvent(eventId, uid, packageName, null, position));
+        }
+    }
+
+    @Override
+    public void logWithInstanceIdAndPosition(UiEventEnum event, int uid, String packageName,
+            InstanceId instance, int position) {
+        final int eventId = event.getId();
+        if (eventId > 0) {
+            mLogs.add(new FakeUiEvent(eventId, uid, packageName, instance, position));
+        }
+    }
 }
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index ad6c7e8..adc7ba3 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -8,10 +8,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.graphics.Bitmap;
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -37,10 +37,12 @@
         private int mSource;
         private boolean mHasStatusBar;
         private boolean mHasNavBar;
-        private Bitmap mBitmap;
+        private Bundle mBitmapBundle;
         private Rect mBoundsInScreen;
         private Insets mInsets;
         private int mTaskId;
+        private int mUserId;
+        private ComponentName mTopComponent;
 
         ScreenshotRequest(int source, boolean hasStatus, boolean hasNav) {
             mSource = source;
@@ -48,24 +50,29 @@
             mHasNavBar = hasNav;
         }
 
-        ScreenshotRequest(
-                int source, Bitmap bitmap, Rect boundsInScreen, Insets insets, int taskId) {
+        ScreenshotRequest(int source, Bundle bitmapBundle, Rect boundsInScreen, Insets insets,
+                int taskId, int userId, ComponentName topComponent) {
             mSource = source;
-            mBitmap = bitmap;
+            mBitmapBundle = bitmapBundle;
             mBoundsInScreen = boundsInScreen;
             mInsets = insets;
             mTaskId = taskId;
+            mUserId = userId;
+            mTopComponent = topComponent;
         }
 
         ScreenshotRequest(Parcel in) {
             mSource = in.readInt();
             mHasStatusBar = in.readBoolean();
             mHasNavBar = in.readBoolean();
+
             if (in.readInt() == 1) {
-                mBitmap = in.readParcelable(Bitmap.class.getClassLoader());
+                mBitmapBundle = in.readBundle(getClass().getClassLoader());
                 mBoundsInScreen = in.readParcelable(Rect.class.getClassLoader());
                 mInsets = in.readParcelable(Insets.class.getClassLoader());
                 mTaskId = in.readInt();
+                mUserId = in.readInt();
+                mTopComponent = in.readParcelable(ComponentName.class.getClassLoader());
             }
         }
 
@@ -81,8 +88,8 @@
             return mHasNavBar;
         }
 
-        public Bitmap getBitmap() {
-            return mBitmap;
+        public Bundle getBitmapBundle() {
+            return mBitmapBundle;
         }
 
         public Rect getBoundsInScreen() {
@@ -97,6 +104,15 @@
             return mTaskId;
         }
 
+
+        public int getUserId() {
+            return mUserId;
+        }
+
+        public ComponentName getTopComponent() {
+            return mTopComponent;
+        }
+
         @Override
         public int describeContents() {
             return 0;
@@ -107,14 +123,16 @@
             dest.writeInt(mSource);
             dest.writeBoolean(mHasStatusBar);
             dest.writeBoolean(mHasNavBar);
-            if (mBitmap == null) {
+            if (mBitmapBundle == null) {
                 dest.writeInt(0);
             } else {
                 dest.writeInt(1);
-                dest.writeParcelable(mBitmap, 0);
+                dest.writeBundle(mBitmapBundle);
                 dest.writeParcelable(mBoundsInScreen, 0);
                 dest.writeParcelable(mInsets, 0);
                 dest.writeInt(mTaskId);
+                dest.writeInt(mUserId);
+                dest.writeParcelable(mTopComponent, 0);
             }
         }
 
@@ -234,19 +252,22 @@
     /**
      * Request that provided image be handled as if it was a screenshot.
      *
-     * @param screenshot         The bitmap to treat as the screen shot.
+     * @param screenshotBundle   Bundle containing the buffer and color space of the screenshot.
      * @param boundsInScreen     The bounds in screen coordinates that the bitmap orginated from.
      * @param insets             The insets that the image was shown with, inside the screenbounds.
      * @param taskId             The taskId of the task that the screen shot was taken of.
+     * @param userId             The userId of user running the task provided in taskId.
+     * @param topComponent       The component name of the top component running in the task.
      * @param handler            A handler used in case the screenshot times out
      * @param completionConsumer Consumes `false` if a screenshot was not taken, and `true` if the
      *                           screenshot was taken.
      */
-    public void provideScreenshot(@NonNull Bitmap screenshot, @NonNull Rect boundsInScreen,
-            @NonNull Insets insets, int taskId, int source,
+    public void provideScreenshot(@NonNull Bundle screenshotBundle, @NonNull Rect boundsInScreen,
+            @NonNull Insets insets, int taskId, int userId, ComponentName topComponent, int source,
             @NonNull Handler handler, @Nullable Consumer<Uri> completionConsumer) {
         ScreenshotRequest screenshotRequest =
-                new ScreenshotRequest(source, screenshot, boundsInScreen, insets, taskId);
+                new ScreenshotRequest(source, screenshotBundle, boundsInScreen, insets, taskId,
+                        userId, topComponent);
         takeScreenshot(WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_TIMEOUT_MS,
                 handler, screenshotRequest, completionConsumer);
     }
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index c75f72b..0d2dbef 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -1223,7 +1223,6 @@
             mExpandButtonContainer.setVisibility(VISIBLE);
             mExpandButtonInnerContainer.setOnClickListener(onClickListener);
         } else {
-            // TODO: handle content paddings to end of layout
             mExpandButtonContainer.setVisibility(GONE);
         }
         updateContentEndPaddings();
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index fc2005a..3d8cae8 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -526,8 +526,16 @@
 
 // Calls POSIX setgroups() using the int[] object as an argument.
 // A nullptr argument is tolerated.
-static void SetGids(JNIEnv* env, jintArray managed_gids, fail_fn_t fail_fn) {
+static void SetGids(JNIEnv* env, jintArray managed_gids, jboolean is_child_zygote,
+                    fail_fn_t fail_fn) {
   if (managed_gids == nullptr) {
+    if (is_child_zygote) {
+      // For child zygotes like webview and app zygote, we want to clear out
+      // any supplemental groups the parent zygote had.
+      if (setgroups(0, NULL) == -1) {
+        fail_fn(CREATE_ERROR("Failed to remove supplementary groups for child zygote"));
+      }
+    }
     return;
   }
 
@@ -1665,7 +1673,7 @@
     }
   }
 
-  SetGids(env, gids, fail_fn);
+  SetGids(env, gids, is_child_zygote, fail_fn);
   SetRLimits(env, rlimits, fail_fn);
 
   if (need_pre_initialize_native_bridge) {
diff --git a/core/proto/android/server/connectivity/data_stall_event.proto b/core/proto/android/server/connectivity/data_stall_event.proto
index 23fcf6e..787074b 100644
--- a/core/proto/android/server/connectivity/data_stall_event.proto
+++ b/core/proto/android/server/connectivity/data_stall_event.proto
@@ -32,6 +32,7 @@
     AP_BAND_UNKNOWN = 0;
     AP_BAND_2GHZ = 1;
     AP_BAND_5GHZ = 2;
+    AP_BAND_6GHZ = 3;
 }
 
 // Refer to definition in TelephonyManager.java.
diff --git a/core/proto/android/stats/mediametrics/mediametrics.proto b/core/proto/android/stats/mediametrics/mediametrics.proto
index e1af962..9f0ff59 100644
--- a/core/proto/android/stats/mediametrics/mediametrics.proto
+++ b/core/proto/android/stats/mediametrics/mediametrics.proto
@@ -131,7 +131,7 @@
  * Logged from:
  *   frameworks/av/media/libstagefright/MediaCodec.cpp
  *   frameworks/av/services/mediaanalytics/statsd_codec.cpp
- * Next Tag: 21
+ * Next Tag: 26
  */
 message CodecData {
     optional string codec = 1;
@@ -156,6 +156,9 @@
     optional int64 latency_unknown = 20;
     optional int32 queue_input_buffer_error = 21;
     optional int32 queue_secure_input_buffer_error = 22;
+    optional string bitrate_mode = 23;
+    optional int32 bitrate = 24;
+    optional int64 lifetime_millis = 25;
 }
 
 /**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fd8460f..464a470 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3656,7 +3656,8 @@
          <p>The package installer v2 APIs are still a work in progress and we're
          currently validating they work in all scenarios.
          <p>Not for use by third-party applications.
-         TODO(b/152310230): remove this permission once the APIs are confirmed to be sufficient.
+         TODO(b/152310230): use this permission to protect only Incremental installations
+         once the APIs are confirmed to be sufficient.
          @hide
     -->
     <permission android:name="com.android.permission.USE_INSTALLER_V2"
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c962256..f42b248 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1830,30 +1830,13 @@
         <!-- @hide no longer used, kept to preserve padding -->
         <attr name="allowAutoRevokePermissionsExemption" format="boolean" />
 
-        <!-- Declare the app's tolerance to having its permissions automatically revoked when unused for an extended
-             period of time -->
+        <!-- No longer used. Declaring this does nothing -->
         <attr name="autoRevokePermissions">
-            <!-- App supports re-requesting its permissions if revoked.
-                 Revoking app's permissions doesn't cause user experience issues, aside from a repeated permission request.
-
-                 Permissions may be automatically revoked from an app if unused. The app must check and possibly request the
-                 necessary permission on each permission-gated call-->
+            <!-- No longer used -->
             <enum name="allowed" value="0" />
-            <!-- App may experience degraded functionality when its previously-granted permissions are revoked.
-                 Revoking app's permissions may cause user experience issues, that are not critical to the user.
-
-                 Apps with this declaration can choose to request an exemption from auto revoke from user by starting
-                 an activity with {@code Intent.ACTION_AUTO_REVOKE_PERMISSIONS}. -->
+            <!-- No longer used -->
             <enum name="discouraged" value="1" />
-            <!-- User may experience severe consequences if this app's permissions are revoked unexpectedly.
-
-                 E.g. app may fail to do a user-critical background job that may likely impact user's
-                 safety/security/device accessibility.
-
-                 This declaration may cause an additional review when publishing your app.
-
-                 Apps with this declaration are exempt from auto revoke by default, though the user has the final say
-                 in both revoking the permissions as well as the app's auto revoke exemption status. -->
+            <!-- No longer used -->
             <enum name="disallowed" value="2" />
         </attr>
     </declare-styleable>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index dc21e87..a1c2450 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1613,15 +1613,15 @@
     <string name="face_error_no_space">Can\u2019t store new face data. Delete an old one first.</string>
     <!-- Generic error message shown when the face operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user. [CHAR LIMIT=50] -->
     <string name="face_error_canceled">Face operation canceled.</string>
-    <!-- Generic error message shown when the face unlock operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=54] -->
+    <!-- Generic error message shown when the face unlock operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=68] -->
     <string name="face_error_user_canceled">Face unlock canceled by user.</string>
     <!-- Generic error message shown when the face operation fails because too many attempts have been made. [CHAR LIMIT=50] -->
     <string name="face_error_lockout">Too many attempts. Try again later.</string>
-    <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=71] -->
+    <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=77] -->
     <string name="face_error_lockout_permanent">Too many attempts. Face unlock disabled.</string>
     <!-- Generic error message shown when the face hardware can't recognize the face. [CHAR LIMIT=50] -->
     <string name="face_error_unable_to_process">Can\u2019t verify face. Try again.</string>
-    <!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=52] -->
+    <!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=59] -->
     <string name="face_error_not_enrolled">You haven\u2019t set up face unlock.</string>
     <!-- Generic error message shown when the app requests face unlock on a device without a sensor. [CHAR LIMIT=61] -->
     <string name="face_error_hw_not_present">Face unlock is not supported on this device.</string>
diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp
new file mode 100644
index 0000000..e74f30e
--- /dev/null
+++ b/core/tests/PackageInstallerSessions/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_test {
+    name: "FrameworksCorePackageInstallerSessionsTests",
+
+    srcs: [
+        "src/**/*.kt",
+    ],
+    static_libs: [
+        "androidx.test.rules",
+        "compatibility-device-util-axt",
+        "frameworks-base-testutils",
+        "platform-test-annotations",
+        "testng",
+        "truth-prebuilt",
+    ],
+
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+        "framework",
+        "framework-res",
+    ],
+
+    platform_apis: true,
+    sdk_version: "core_platform",
+    test_suites: ["device-tests"],
+}
diff --git a/core/tests/PackageInstallerSessions/AndroidManifest.xml b/core/tests/PackageInstallerSessions/AndroidManifest.xml
new file mode 100644
index 0000000..5b22d2b
--- /dev/null
+++ b/core/tests/PackageInstallerSessions/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 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.frameworks.coretests.package_installer_sessions"
+    >
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.frameworks.coretests.package_installer_sessions"/>
+</manifest>
diff --git a/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt b/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt
new file mode 100644
index 0000000..494c92a
--- /dev/null
+++ b/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2020 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.content.pm
+
+import android.content.Context
+import android.content.pm.PackageInstaller.SessionParams
+import android.platform.test.annotations.Presubmit
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.LargeTest
+import com.android.compatibility.common.util.ShellIdentityUtils
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.testng.Assert.assertThrows
+import kotlin.random.Random
+
+/**
+ * For verifying public [PackageInstaller] session APIs. This differs from
+ * [com.android.server.pm.PackageInstallerSessionTest] in services because that mocks the session,
+ * whereas this test uses the installer on device.
+ */
+@Presubmit
+class PackageSessionTests {
+
+    companion object {
+        /**
+         * Permissions marked "hardRestricted" or "softRestricted" in core/res/AndroidManifest.xml.
+         */
+        private val RESTRICTED_PERMISSIONS = listOf(
+                "android.permission.SEND_SMS",
+                "android.permission.RECEIVE_SMS",
+                "android.permission.READ_SMS",
+                "android.permission.RECEIVE_WAP_PUSH",
+                "android.permission.RECEIVE_MMS",
+                "android.permission.READ_CELL_BROADCASTS",
+                "android.permission.ACCESS_BACKGROUND_LOCATION",
+                "android.permission.READ_CALL_LOG",
+                "android.permission.WRITE_CALL_LOG",
+                "android.permission.PROCESS_OUTGOING_CALLS"
+        )
+    }
+
+    private val context: Context = InstrumentationRegistry.getContext()
+
+    private val installer = context.packageManager.packageInstaller
+
+    @Before
+    @After
+    fun abandonAllSessions() {
+        installer.mySessions.asSequence()
+                .map { it.sessionId }
+                .forEach {
+                    try {
+                        installer.abandonSession(it)
+                    } catch (ignored: Exception) {
+                        // Querying for sessions checks by calling package name, but abandoning
+                        // checks by UID, which won't match if this test failed to clean up
+                        // on a previous install + run + uninstall, so ignore these failures.
+                    }
+                }
+    }
+
+    @Test
+    fun truncateAppLabel() {
+        val longLabel = invalidAppLabel()
+        val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+            setAppLabel(longLabel)
+        }
+
+        createSession(params) {
+            assertThat(installer.getSessionInfo(it)?.appLabel)
+                    .isEqualTo(longLabel.take(PackageItemInfo.MAX_SAFE_LABEL_LENGTH))
+        }
+    }
+
+    @Test
+    fun removeInvalidAppPackageName() {
+        val longName = invalidPackageName()
+        val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+            setAppPackageName(longName)
+        }
+
+        createSession(params) {
+            assertThat(installer.getSessionInfo(it)?.appPackageName)
+                    .isEqualTo(null)
+        }
+    }
+
+    @Test
+    fun removeInvalidInstallerPackageName() {
+        val longName = invalidPackageName()
+        val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+            setInstallerPackageName(longName)
+        }
+
+        createSession(params) {
+            // If a custom installer name is dropped, it defaults to the caller
+            assertThat(installer.getSessionInfo(it)?.installerPackageName)
+                    .isEqualTo(context.packageName)
+        }
+    }
+
+    @Test
+    fun truncateWhitelistPermissions() {
+        val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+            setWhitelistedRestrictedPermissions(invalidPermissions())
+        }
+
+        createSession(params) {
+            assertThat(installer.getSessionInfo(it)?.whitelistedRestrictedPermissions!!)
+                    .containsExactlyElementsIn(RESTRICTED_PERMISSIONS)
+        }
+    }
+
+    @LargeTest
+    @Test
+    fun allocateMaxSessionsWithPermission() {
+        ShellIdentityUtils.invokeWithShellPermissions {
+            repeat(1024) { createDummySession() }
+            assertThrows(IllegalStateException::class.java) { createDummySession() }
+        }
+    }
+
+    @LargeTest
+    @Test
+    fun allocateMaxSessionsNoPermission() {
+        repeat(50) { createDummySession() }
+        assertThrows(IllegalStateException::class.java) { createDummySession() }
+    }
+
+    private fun createDummySession() {
+        installer.createSession(SessionParams(SessionParams.MODE_FULL_INSTALL)
+                .apply {
+                    setAppPackageName(invalidPackageName())
+                    setAppLabel(invalidAppLabel())
+                    setWhitelistedRestrictedPermissions(invalidPermissions())
+                })
+    }
+
+    private fun invalidPackageName(maxLength: Int = SessionParams.MAX_PACKAGE_NAME_LENGTH): String {
+        return (0 until (maxLength + 10))
+                .asSequence()
+                .mapIndexed { index, _ ->
+                    // A package name needs at least one separator
+                    if (index == 2) {
+                        '.'
+                    } else {
+                        Random.nextInt('z' - 'a').toChar() + 'a'.toInt()
+                    }
+                }
+                .joinToString(separator = "")
+    }
+
+    private fun invalidAppLabel() = (0 until PackageItemInfo.MAX_SAFE_LABEL_LENGTH + 10)
+            .asSequence()
+            .map { Random.nextInt(Char.MAX_VALUE.toInt()).toChar() }
+            .joinToString(separator = "")
+
+    private fun invalidPermissions() = RESTRICTED_PERMISSIONS.toMutableSet()
+            .apply {
+                // Add some invalid permission names
+                repeat(10) { add(invalidPackageName(300)) }
+            }
+
+    private fun createSession(params: SessionParams, block: (Int) -> Unit = {}) {
+        val sessionId = installer.createSession(params)
+        try {
+            block(sessionId)
+        } finally {
+            installer.abandonSession(sessionId)
+        }
+    }
+}
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index 7cd2f3b..a4f2065 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -363,6 +363,16 @@
         public boolean isHdmiCecVolumeControlEnabled() {
             return true;
         }
+
+        @Override
+        public void addHdmiCecVolumeControlFeatureListener(
+                IHdmiCecVolumeControlFeatureListener listener) {
+        }
+
+        @Override
+        public void removeHdmiCecVolumeControlFeatureListener(
+                IHdmiCecVolumeControlFeatureListener listener) {
+        }
     }
 
 }
diff --git a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
index fe33cd8..4b81737 100644
--- a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
+++ b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
@@ -29,11 +29,12 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.Bitmap;
 import android.graphics.Insets;
 import android.graphics.Rect;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.view.WindowManager;
@@ -91,8 +92,7 @@
     @Test
     public void testProvidedImageScreenshot() {
         mScreenshotHelper.provideScreenshot(
-                Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888), new Rect(),
-                Insets.of(0, 0, 0, 0), 1,
+                new Bundle(), new Rect(), Insets.of(0, 0, 0, 0), 1, 1, new ComponentName("", ""),
                 WindowManager.ScreenshotSource.SCREENSHOT_OTHER, mHandler, null);
     }
 
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index e00813c..aa4e9f2 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -418,6 +418,8 @@
         <permission name="android.permission.TV_INPUT_HARDWARE" />
         <!-- Permission required for CTS test - PrivilegedLocationPermissionTest -->
         <permission name="android.permission.LOCATION_HARDWARE" />
+        <!-- Permissions required for GTS test - GtsDialerAudioTestCases -->
+        <permission name="android.permission.CAPTURE_AUDIO_OUTPUT" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/data/keyboards/Vendor_045e_Product_0b12.kl b/data/keyboards/Vendor_045e_Product_0b12.kl
new file mode 100644
index 0000000..0b44c743
--- /dev/null
+++ b/data/keyboards/Vendor_045e_Product_0b12.kl
@@ -0,0 +1,59 @@
+# Copyright (C) 2020 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.
+
+#
+# XBox USB Controller
+#
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+
+# The branded "X" button in the center of the controller
+key 316   BUTTON_MODE
+
+# Three parallel horizontal lines (hamburger menu)
+key 315   BUTTON_START
+
+#Button below the "X" button
+key 167   MEDIA_RECORD
+
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index c652628..590def4 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
+import android.app.ActivityManager;
 import android.content.Context;
 import android.hardware.cas.V1_0.HidlCasPluginDescriptor;
 import android.hardware.cas.V1_0.ICas;
@@ -43,6 +44,8 @@
 import android.util.Log;
 import android.util.Singleton;
 
+import com.android.internal.util.FrameworkStatsLog;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -122,6 +125,7 @@
     private String mTvInputServiceSessionId;
     private int mClientId;
     private int mCasSystemId;
+    private int mUserId;
     private TunerResourceManager mTunerResourceManager = null;
     private final Map<Session, Integer> mSessionMap = new HashMap<>();
 
@@ -673,6 +677,8 @@
      */
     public MediaCas(int CA_system_id) throws UnsupportedCasException {
         try {
+            mCasSystemId = CA_system_id;
+            mUserId = ActivityManager.getCurrentUser();
             IMediaCasService service = getService();
             android.hardware.cas.V1_2.IMediaCasService serviceV12 =
                     android.hardware.cas.V1_2.IMediaCasService.castFrom(service);
@@ -721,7 +727,6 @@
         this(casSystemId);
 
         Objects.requireNonNull(context, "context must not be null");
-        mCasSystemId = casSystemId;
         mTunerResourceManager = (TunerResourceManager)
                 context.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
         if (mTunerResourceManager != null) {
@@ -925,10 +930,18 @@
             mICas.openSession(cb);
             MediaCasException.throwExceptionIfNeeded(cb.mStatus);
             addSessionToResourceMap(cb.mSession, sessionResourceHandle);
+            Log.d(TAG, "Write Stats Log for succeed to Open Session.");
+            FrameworkStatsLog
+                    .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+                        FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED);
             return cb.mSession;
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
+        Log.d(TAG, "Write Stats Log for fail to Open Session.");
+        FrameworkStatsLog
+                .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+                    FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__FAILED);
         return null;
     }
 
@@ -964,10 +977,18 @@
             mICasV12.openSession_1_2(sessionUsage, scramblingMode, cb);
             MediaCasException.throwExceptionIfNeeded(cb.mStatus);
             addSessionToResourceMap(cb.mSession, sessionResourceHandle);
+            Log.d(TAG, "Write Stats Log for succeed to Open Session.");
+            FrameworkStatsLog
+                    .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+                        FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED);
             return cb.mSession;
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
+        Log.d(TAG, "Write Stats Log for fail to Open Session.");
+        FrameworkStatsLog
+                .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+                    FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__FAILED);
         return null;
     }
 
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 981bf7a..05c6e3a 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -137,7 +137,7 @@
     private final AtomicBoolean mStatePublishScheduled = new AtomicBoolean(false);
     private MediaRoute2ProviderServiceStub mStub;
     private IMediaRoute2ProviderServiceCallback mRemoteCallback;
-    private MediaRoute2ProviderInfo mProviderInfo;
+    private volatile MediaRoute2ProviderInfo mProviderInfo;
 
     @GuardedBy("mSessionLock")
     private ArrayMap<String, RoutingSessionInfo> mSessionInfo = new ArrayMap<>();
@@ -167,8 +167,8 @@
     /**
      * Called when a volume setting is requested on a route of the provider
      *
-     * @param requestId the id of this request
-     * @param routeId the id of the route
+     * @param requestId the ID of this request
+     * @param routeId the ID of the route
      * @param volume the target volume
      * @see MediaRoute2Info.Builder#setVolume(int)
      */
@@ -178,8 +178,8 @@
      * Called when {@link MediaRouter2.RoutingController#setVolume(int)} is called on
      * a routing session of the provider
      *
-     * @param requestId the id of this request
-     * @param sessionId the id of the routing session
+     * @param requestId the ID of this request
+     * @param sessionId the ID of the routing session
      * @param volume the target volume
      * @see RoutingSessionInfo.Builder#setVolume(int)
      */
@@ -188,7 +188,7 @@
     /**
      * Gets information of the session with the given id.
      *
-     * @param sessionId id of the session
+     * @param sessionId the ID of the session
      * @return information of the session with the given id.
      *         null if the session is released or ID is not valid.
      */
@@ -218,7 +218,7 @@
      * If this session is created without any creation request, use {@link #REQUEST_ID_NONE}
      * as the request ID.
      *
-     * @param requestId id of the previous request to create this session provided in
+     * @param requestId the ID of the previous request to create this session provided in
      *                  {@link #onCreateSession(long, String, String, Bundle)}. Can be
      *                  {@link #REQUEST_ID_NONE} if this session is created without any request.
      * @param sessionInfo information of the new session.
@@ -237,18 +237,15 @@
                 return;
             }
             mSessionInfo.put(sessionInfo.getId(), sessionInfo);
-        }
 
-        if (mRemoteCallback == null) {
-            return;
-        }
-        try {
-            // TODO(b/157873487): Calling binder calls in multiple thread may cause timing issue.
-            //       Consider to change implementations to avoid the problems.
-            //       For example, post binder calls, always send all sessions at once, etc.
-            mRemoteCallback.notifySessionCreated(requestId, sessionInfo);
-        } catch (RemoteException ex) {
-            Log.w(TAG, "Failed to notify session created.");
+            if (mRemoteCallback == null) {
+                return;
+            }
+            try {
+                mRemoteCallback.notifySessionCreated(requestId, sessionInfo);
+            } catch (RemoteException ex) {
+                Log.w(TAG, "Failed to notify session created.");
+            }
         }
     }
 
@@ -267,22 +264,22 @@
                 Log.w(TAG, "Ignoring unknown session info.");
                 return;
             }
-        }
 
-        if (mRemoteCallback == null) {
-            return;
-        }
-        try {
-            mRemoteCallback.notifySessionUpdated(sessionInfo);
-        } catch (RemoteException ex) {
-            Log.w(TAG, "Failed to notify session info changed.");
+            if (mRemoteCallback == null) {
+                return;
+            }
+            try {
+                mRemoteCallback.notifySessionUpdated(sessionInfo);
+            } catch (RemoteException ex) {
+                Log.w(TAG, "Failed to notify session info changed.");
+            }
         }
     }
 
     /**
      * Notifies that the session is released.
      *
-     * @param sessionId id of the released session.
+     * @param sessionId the ID of the released session.
      * @see #onReleaseSession(long, String)
      */
     public final void notifySessionReleased(@NonNull String sessionId) {
@@ -292,20 +289,20 @@
         RoutingSessionInfo sessionInfo;
         synchronized (mSessionLock) {
             sessionInfo = mSessionInfo.remove(sessionId);
-        }
 
-        if (sessionInfo == null) {
-            Log.w(TAG, "Ignoring unknown session info.");
-            return;
-        }
+            if (sessionInfo == null) {
+                Log.w(TAG, "Ignoring unknown session info.");
+                return;
+            }
 
-        if (mRemoteCallback == null) {
-            return;
-        }
-        try {
-            mRemoteCallback.notifySessionReleased(sessionInfo);
-        } catch (RemoteException ex) {
-            Log.w(TAG, "Failed to notify session info changed.");
+            if (mRemoteCallback == null) {
+                return;
+            }
+            try {
+                mRemoteCallback.notifySessionReleased(sessionInfo);
+            } catch (RemoteException ex) {
+                Log.w(TAG, "Failed to notify session info changed.");
+            }
         }
     }
 
@@ -348,9 +345,9 @@
      * If you can't create the session or want to reject the request, call
      * {@link #notifyRequestFailed(long, int)} with the given {@code requestId}.
      *
-     * @param requestId the id of this request
+     * @param requestId the ID of this request
      * @param packageName the package name of the application that selected the route
-     * @param routeId the id of the route initially being connected
+     * @param routeId the ID of the route initially being connected
      * @param sessionHints an optional bundle of app-specific arguments sent by
      *                     {@link MediaRouter2}, or null if none. The contents of this bundle
      *                     may affect the result of session creation.
@@ -372,8 +369,8 @@
      * Note: Calling {@link #notifySessionReleased(String)} will <em>NOT</em> trigger
      * this method to be called.
      *
-     * @param requestId the id of this request
-     * @param sessionId id of the session being released.
+     * @param requestId the ID of this request
+     * @param sessionId the ID of the session being released.
      * @see #notifySessionReleased(String)
      * @see #getSessionInfo(String)
      */
@@ -384,9 +381,9 @@
      * After the route is selected, call {@link #notifySessionUpdated(RoutingSessionInfo)}
      * to update session info.
      *
-     * @param requestId the id of this request
-     * @param sessionId id of the session
-     * @param routeId id of the route
+     * @param requestId the ID of this request
+     * @param sessionId the ID of the session
+     * @param routeId the ID of the route
      */
     public abstract void onSelectRoute(long requestId, @NonNull String sessionId,
             @NonNull String routeId);
@@ -396,9 +393,9 @@
      * After the route is deselected, call {@link #notifySessionUpdated(RoutingSessionInfo)}
      * to update session info.
      *
-     * @param requestId the id of this request
-     * @param sessionId id of the session
-     * @param routeId id of the route
+     * @param requestId the ID of this request
+     * @param sessionId the ID of the session
+     * @param routeId the ID of the route
      */
     public abstract void onDeselectRoute(long requestId, @NonNull String sessionId,
             @NonNull String routeId);
@@ -408,9 +405,9 @@
      * After the transfer is finished, call {@link #notifySessionUpdated(RoutingSessionInfo)}
      * to update session info.
      *
-     * @param requestId the id of this request
-     * @param sessionId id of the session
-     * @param routeId id of the route
+     * @param requestId the ID of this request
+     * @param sessionId the ID of the session
+     * @param routeId the ID of the route
      */
     public abstract void onTransferToRoute(long requestId, @NonNull String sessionId,
             @NonNull String routeId);
@@ -475,13 +472,39 @@
     final class MediaRoute2ProviderServiceStub extends IMediaRoute2ProviderService.Stub {
         MediaRoute2ProviderServiceStub() { }
 
-        boolean checkCallerisSystem() {
+        private boolean checkCallerIsSystem() {
             return Binder.getCallingUid() == Process.SYSTEM_UID;
         }
 
+        private boolean checkSessionIdIsValid(String sessionId, String description) {
+            if (TextUtils.isEmpty(sessionId)) {
+                Log.w(TAG, description + ": Ignoring empty sessionId from system service.");
+                return false;
+            }
+            if (getSessionInfo(sessionId) == null) {
+                Log.w(TAG, description + ": Ignoring unknown session from system service. "
+                        + "sessionId=" + sessionId);
+                return false;
+            }
+            return true;
+        }
+
+        private boolean checkRouteIdIsValid(String routeId, String description) {
+            if (TextUtils.isEmpty(routeId)) {
+                Log.w(TAG, description + ": Ignoring empty routeId from system service.");
+                return false;
+            }
+            if (mProviderInfo == null || mProviderInfo.getRoute(routeId) == null) {
+                Log.w(TAG, description + ": Ignoring unknown route from system service. "
+                        + "routeId=" + routeId);
+                return false;
+            }
+            return true;
+        }
+
         @Override
         public void setCallback(IMediaRoute2ProviderServiceCallback callback) {
-            if (!checkCallerisSystem()) {
+            if (!checkCallerIsSystem()) {
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::setCallback,
@@ -490,7 +513,7 @@
 
         @Override
         public void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference) {
-            if (!checkCallerisSystem()) {
+            if (!checkCallerIsSystem()) {
                 return;
             }
             mHandler.sendMessage(obtainMessage(
@@ -500,7 +523,10 @@
 
         @Override
         public void setRouteVolume(long requestId, String routeId, int volume) {
-            if (!checkCallerisSystem()) {
+            if (!checkCallerIsSystem()) {
+                return;
+            }
+            if (!checkRouteIdIsValid(routeId, "setRouteVolume")) {
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSetRouteVolume,
@@ -510,7 +536,10 @@
         @Override
         public void requestCreateSession(long requestId, String packageName, String routeId,
                 @Nullable Bundle requestCreateSession) {
-            if (!checkCallerisSystem()) {
+            if (!checkCallerIsSystem()) {
+                return;
+            }
+            if (!checkRouteIdIsValid(routeId, "requestCreateSession")) {
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onCreateSession,
@@ -518,14 +547,13 @@
                     requestCreateSession));
         }
 
-        //TODO(b/157873546): Ignore requests with unknown session ID. -> For all similar commands.
         @Override
         public void selectRoute(long requestId, String sessionId, String routeId) {
-            if (!checkCallerisSystem()) {
+            if (!checkCallerIsSystem()) {
                 return;
             }
-            if (TextUtils.isEmpty(sessionId)) {
-                Log.w(TAG, "selectRoute: Ignoring empty sessionId from system service.");
+            if (!checkSessionIdIsValid(sessionId, "selectRoute")
+                    || !checkRouteIdIsValid(routeId, "selectRoute")) {
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
@@ -534,11 +562,11 @@
 
         @Override
         public void deselectRoute(long requestId, String sessionId, String routeId) {
-            if (!checkCallerisSystem()) {
+            if (!checkCallerIsSystem()) {
                 return;
             }
-            if (TextUtils.isEmpty(sessionId)) {
-                Log.w(TAG, "deselectRoute: Ignoring empty sessionId from system service.");
+            if (!checkSessionIdIsValid(sessionId, "deselectRoute")
+                    || !checkRouteIdIsValid(routeId, "deselectRoute")) {
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onDeselectRoute,
@@ -547,11 +575,11 @@
 
         @Override
         public void transferToRoute(long requestId, String sessionId, String routeId) {
-            if (!checkCallerisSystem()) {
+            if (!checkCallerIsSystem()) {
                 return;
             }
-            if (TextUtils.isEmpty(sessionId)) {
-                Log.w(TAG, "transferToRoute: Ignoring empty sessionId from system service.");
+            if (!checkSessionIdIsValid(sessionId, "transferToRoute")
+                    || !checkRouteIdIsValid(routeId, "transferToRoute")) {
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onTransferToRoute,
@@ -560,7 +588,10 @@
 
         @Override
         public void setSessionVolume(long requestId, String sessionId, int volume) {
-            if (!checkCallerisSystem()) {
+            if (!checkCallerIsSystem()) {
+                return;
+            }
+            if (!checkSessionIdIsValid(sessionId, "setSessionVolume")) {
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSetSessionVolume,
@@ -569,11 +600,10 @@
 
         @Override
         public void releaseSession(long requestId, String sessionId) {
-            if (!checkCallerisSystem()) {
+            if (!checkCallerIsSystem()) {
                 return;
             }
-            if (TextUtils.isEmpty(sessionId)) {
-                Log.w(TAG, "releaseSession: Ignoring empty sessionId from system service.");
+            if (!checkSessionIdIsValid(sessionId, "releaseSession")) {
                 return;
             }
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onReleaseSession,
diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
index 68071b0..bb00bb3 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
@@ -20,12 +20,16 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.app.ActivityManager;
 import android.hardware.tv.tuner.V1_0.Constants;
 import android.media.tv.tuner.Tuner;
 import android.media.tv.tuner.Tuner.Result;
 import android.media.tv.tuner.TunerUtils;
 import android.media.tv.tuner.filter.Filter;
 import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.android.internal.util.FrameworkStatsLog;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -72,9 +76,15 @@
      */
     public static final int PLAYBACK_STATUS_FULL = Constants.PlaybackStatus.SPACE_FULL;
 
+    private static final String TAG = "TvTunerPlayback";
+
     private long mNativeContext;
     private OnPlaybackStatusChangedListener mListener;
     private Executor mExecutor;
+    private int mUserId;
+    private static int sInstantId = 0;
+    private int mSegmentId = 0;
+    private int mUnderflow;
 
     private native int nativeAttachFilter(Filter filter);
     private native int nativeDetachFilter(Filter filter);
@@ -88,6 +98,9 @@
     private native long nativeRead(byte[] bytes, long offset, long size);
 
     private DvrPlayback() {
+        mUserId = ActivityManager.getCurrentUser();
+        mSegmentId = (sInstantId & 0x0000ffff) << 16;
+        sInstantId++;
     }
 
     /** @hide */
@@ -98,6 +111,9 @@
     }
 
     private void onPlaybackStatusChanged(int status) {
+        if (status == PLAYBACK_STATUS_EMPTY) {
+            mUnderflow++;
+        }
         if (mExecutor != null && mListener != null) {
             mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status));
         }
@@ -154,6 +170,13 @@
      */
     @Result
     public int start() {
+        mSegmentId =  (mSegmentId & 0xffff0000) | (((mSegmentId & 0x0000ffff) + 1) & 0x0000ffff);
+        mUnderflow = 0;
+        Log.d(TAG, "Write Stats Log for Playback.");
+        FrameworkStatsLog
+                .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
+                    FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__PLAYBACK,
+                    FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STARTED, mSegmentId, 0);
         return nativeStartDvr();
     }
 
@@ -167,6 +190,11 @@
      */
     @Result
     public int stop() {
+        Log.d(TAG, "Write Stats Log for Playback.");
+        FrameworkStatsLog
+                .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
+                    FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__PLAYBACK,
+                    FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STOPPED, mSegmentId, mUnderflow);
         return nativeStopDvr();
     }
 
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index 198bd0f..8871167 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -19,14 +19,19 @@
 import android.annotation.BytesLong;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.app.ActivityManager;
 import android.media.tv.tuner.Tuner;
 import android.media.tv.tuner.Tuner.Result;
 import android.media.tv.tuner.TunerUtils;
 import android.media.tv.tuner.filter.Filter;
 import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.android.internal.util.FrameworkStatsLog;
 
 import java.util.concurrent.Executor;
 
+
 /**
  * Digital Video Record (DVR) recorder class which provides record control on Demux's output buffer.
  *
@@ -34,9 +39,14 @@
  */
 @SystemApi
 public class DvrRecorder implements AutoCloseable {
+    private static final String TAG = "TvTunerRecord";
     private long mNativeContext;
     private OnRecordStatusChangedListener mListener;
     private Executor mExecutor;
+    private int mUserId;
+    private static int sInstantId = 0;
+    private int mSegmentId = 0;
+    private int mOverflow;
 
     private native int nativeAttachFilter(Filter filter);
     private native int nativeDetachFilter(Filter filter);
@@ -50,6 +60,9 @@
     private native long nativeWrite(byte[] bytes, long offset, long size);
 
     private DvrRecorder() {
+        mUserId = ActivityManager.getCurrentUser();
+        mSegmentId = (sInstantId & 0x0000ffff) << 16;
+        sInstantId++;
     }
 
     /** @hide */
@@ -60,6 +73,9 @@
     }
 
     private void onRecordStatusChanged(int status) {
+        if (status == Filter.STATUS_OVERFLOW) {
+            mOverflow++;
+        }
         if (mExecutor != null && mListener != null) {
             mExecutor.execute(() -> mListener.onRecordStatusChanged(status));
         }
@@ -112,6 +128,13 @@
      */
     @Result
     public int start() {
+        mSegmentId =  (mSegmentId & 0xffff0000) | (((mSegmentId & 0x0000ffff) + 1) & 0x0000ffff);
+        mOverflow = 0;
+        Log.d(TAG, "Write Stats Log for Record.");
+        FrameworkStatsLog
+                .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
+                    FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD,
+                    FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STARTED, mSegmentId, 0);
         return nativeStartDvr();
     }
 
@@ -124,6 +147,11 @@
      */
     @Result
     public int stop() {
+        Log.d(TAG, "Write Stats Log for Playback.");
+        FrameworkStatsLog
+                .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
+                    FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD,
+                    FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STOPPED, mSegmentId, mOverflow);
         return nativeStopDvr();
     }
 
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 2a8a39a..32b33a7 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -32,6 +32,7 @@
         "SystemUIPluginLib",
         "SystemUISharedLib",
         "SettingsLib",
+        "car-ui-lib",
         "android.car.userlib",
         "androidx.legacy_legacy-support-v4",
         "androidx.recyclerview_recyclerview",
@@ -95,6 +96,7 @@
         "androidx.slice_slice-builders",
         "androidx.arch.core_core-runtime",
         "androidx.lifecycle_lifecycle-extensions",
+        "car-ui-lib",
         "SystemUI-tags",
         "SystemUI-proto",
         "metrics-helper-lib",
diff --git a/packages/CarSystemUI/res/drawable/nav_button_background.xml b/packages/CarSystemUI/res/drawable/nav_button_background.xml
deleted file mode 100644
index 376347c..0000000
--- a/packages/CarSystemUI/res/drawable/nav_button_background.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2018 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="@color/nav_bar_ripple_background_color">
-    <item android:id="@android:id/mask">
-        <shape android:shape="rectangle">
-            <solid android:color="?android:colorAccent"/>
-            <corners android:radius="6dp"/>
-        </shape>
-    </item>
-</ripple>
diff --git a/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
index a8c7098..94816f8 100644
--- a/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
@@ -79,7 +79,7 @@
         android:gravity="bottom"
         android:orientation="vertical">
 
-        <com.android.keyguard.AlphaOptimizedImageButton
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
             android:id="@+id/note"
             android:layout_height="wrap_content"
             android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
index 2a715d0..9317498 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
@@ -29,9 +29,10 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_weight="1"
-        android:paddingStart="20dp"
+        android:gravity="center"
+        android:layoutDirection="ltr"
         android:paddingEnd="20dp"
-        android:gravity="center">
+        android:paddingStart="20dp">
 
         <com.android.systemui.car.navigationbar.CarNavigationButton
             android:id="@+id/home"
@@ -135,9 +136,10 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_weight="1"
-        android:paddingStart="@dimen/car_keyline_1"
-        android:paddingEnd="@dimen/car_keyline_1"
         android:gravity="center"
+        android:layoutDirection="ltr"
+        android:paddingEnd="@dimen/car_keyline_1"
+        android:paddingStart="@dimen/car_keyline_1"
         android:visibility="gone"
     />
 
diff --git a/packages/CarSystemUI/res/layout/car_navigation_button.xml b/packages/CarSystemUI/res/layout/car_navigation_button.xml
index ca4e76e..a8f1157 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_button.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_button.xml
@@ -27,7 +27,7 @@
         android:animateLayoutChanges="true"
         android:orientation="vertical">
 
-        <com.android.keyguard.AlphaOptimizedImageButton
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
             android:id="@+id/car_nav_button_icon_image"
             android:layout_height="@dimen/car_navigation_button_icon_height"
             android:layout_width="match_parent"
@@ -40,7 +40,7 @@
             android:clickable="false"
         />
 
-        <com.android.keyguard.AlphaOptimizedImageButton
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
             android:id="@+id/car_nav_button_more_icon"
             android:layout_height="wrap_content"
             android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
index fd75570..dc95833 100644
--- a/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
@@ -82,7 +82,7 @@
         android:gravity="bottom"
         android:orientation="vertical">
 
-        <com.android.keyguard.AlphaOptimizedImageButton
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
             android:id="@+id/note"
             android:layout_height="wrap_content"
             android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
index 60e0d7e..cdc29eec 100644
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
@@ -27,7 +27,8 @@
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_weight="1">
+        android:layout_weight="1"
+        android:layoutDirection="ltr">
 
         <FrameLayout
             android:id="@+id/left_hvac_container"
diff --git a/packages/CarSystemUI/res/layout/headsup_container_bottom.xml b/packages/CarSystemUI/res/layout/headsup_container_bottom.xml
index caf1677..1782d25 100644
--- a/packages/CarSystemUI/res/layout/headsup_container_bottom.xml
+++ b/packages/CarSystemUI/res/layout/headsup_container_bottom.xml
@@ -29,6 +29,15 @@
         android:orientation="horizontal"
         app:layout_constraintGuide_begin="@dimen/headsup_scrim_height"/>
 
+    <!-- Include a FocusParkingView at the beginning or end. The rotary controller "parks" the
+         focus here when the user navigates to another window. This is also used to prevent
+         wrap-around which is why it must be first or last in Tab order. -->
+    <com.android.car.ui.FocusParkingView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent"/>
+
     <View
         android:id="@+id/scrim"
         android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml
index 371bebd..7fc69e6 100644
--- a/packages/CarSystemUI/res/values/styles.xml
+++ b/packages/CarSystemUI/res/values/styles.xml
@@ -44,6 +44,6 @@
     <style name="NavigationBarButton">
         <item name="android:layout_height">96dp</item>
         <item name="android:layout_width">96dp</item>
-        <item name="android:background">@drawable/nav_button_background</item>
+        <item name="android:background">@*android:drawable/item_background_material</item>
     </style>
 </resources>
\ No newline at end of file
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
index ab61b44..2dad5f8 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
@@ -219,6 +219,14 @@
     }
 
     @Override
+    public void setOccluded(boolean occluded, boolean animate) {
+        getOverlayViewGlobalStateController().setOccluded(occluded);
+        if (!occluded) {
+            reset(/* hideBouncerWhenShowing= */ false);
+        }
+    }
+
+    @Override
     public void onCancelClicked() {
         if (mBouncer == null) return;
 
@@ -315,11 +323,6 @@
     }
 
     @Override
-    public void setOccluded(boolean occluded, boolean animate) {
-        // no-op
-    }
-
-    @Override
     public boolean shouldDisableWindowAnimationsForUnlock() {
         return false;
     }
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
index 20fc1bc..0ced402 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
@@ -74,8 +74,10 @@
             mDarkIconManager.setShouldLog(true);
             Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
         }
-        // needs to be clickable so that it will receive ACTION_MOVE events
+        // Needs to be clickable so that it will receive ACTION_MOVE events.
         setClickable(true);
+        // Needs to not be focusable so rotary won't highlight the entire nav bar.
+        setFocusable(false);
     }
 
     @Override
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java
index 5e113d6..e7e33a5 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java
@@ -32,8 +32,8 @@
 import android.widget.LinearLayout;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.keyguard.AlphaOptimizedImageButton;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.AlphaOptimizedImageView;
 
 import java.net.URISyntaxException;
 
@@ -53,8 +53,8 @@
     private static final String EXTRA_BUTTON_PACKAGES = "packages";
 
     private Context mContext;
-    private AlphaOptimizedImageButton mIcon;
-    private AlphaOptimizedImageButton mMoreIcon;
+    private AlphaOptimizedImageView mIcon;
+    private AlphaOptimizedImageView mMoreIcon;
     private ImageView mUnseenIcon;
     private String mIntent;
     private String mLongIntent;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java
index 3b7b48a..d60bc41 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java
@@ -24,6 +24,7 @@
 
 import androidx.annotation.LayoutRes;
 
+import com.android.car.ui.FocusParkingView;
 import com.android.systemui.R;
 
 import javax.inject.Inject;
@@ -146,6 +147,12 @@
 
         CarNavigationBarView view = (CarNavigationBarView) View.inflate(mContext, barLayout,
                 /* root= */ null);
+
+        // Include a FocusParkingView at the end. The rotary controller "parks" the focus here when
+        // the user navigates to another window. This is also used to prevent wrap-around which is
+        // why it must be first or last in Tab order.
+        view.addView(new FocusParkingView(mContext));
+
         mCachedViewMap.put(type, view);
         return mCachedViewMap.get(type);
     }
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
index aeb1d39..d4f72071 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
@@ -24,7 +24,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
-import android.widget.FrameLayout;
 
 import com.android.car.notification.R;
 import com.android.car.notification.headsup.CarHeadsUpNotificationContainer;
@@ -44,7 +43,7 @@
     private final OverlayViewGlobalStateController mOverlayViewGlobalStateController;
 
     private final ViewGroup mWindow;
-    private final FrameLayout mHeadsUpContentFrame;
+    private final ViewGroup mHeadsUpContentFrame;
 
     @Inject
     CarHeadsUpNotificationSystemContainer(Context context,
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
index 30e2657..3969f92 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
@@ -138,4 +138,11 @@
     protected boolean shouldShowNavigationBar() {
         return false;
     }
+
+    /**
+     * Returns {@code true} if this view should be hidden during the occluded state.
+     */
+    protected boolean shouldShowWhenOccluded() {
+        return false;
+    }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
index 70260b0..8e94109 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
@@ -24,7 +24,9 @@
 import com.android.systemui.car.navigationbar.CarNavigationBarController;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
@@ -47,11 +49,16 @@
     private static final int UNKNOWN_Z_ORDER = -1;
     private final SystemUIOverlayWindowController mSystemUIOverlayWindowController;
     private final CarNavigationBarController mCarNavigationBarController;
+
+    private boolean mIsOccluded;
+
     @VisibleForTesting
     Map<OverlayViewController, Integer> mZOrderMap;
     @VisibleForTesting
     SortedMap<Integer, OverlayViewController> mZOrderVisibleSortedMap;
     @VisibleForTesting
+    Set<OverlayViewController> mViewsHiddenForOcclusion;
+    @VisibleForTesting
     OverlayViewController mHighestZOrder;
 
     @Inject
@@ -63,6 +70,7 @@
         mCarNavigationBarController = carNavigationBarController;
         mZOrderMap = new HashMap<>();
         mZOrderVisibleSortedMap = new TreeMap<>();
+        mViewsHiddenForOcclusion = new HashSet<>();
     }
 
     /**
@@ -91,6 +99,10 @@
      */
     public void showView(OverlayViewController viewController, @Nullable Runnable show) {
         debugLog();
+        if (mIsOccluded && !viewController.shouldShowWhenOccluded()) {
+            mViewsHiddenForOcclusion.add(viewController);
+            return;
+        }
         if (mZOrderVisibleSortedMap.isEmpty()) {
             setWindowVisible(true);
         }
@@ -147,6 +159,10 @@
      */
     public void hideView(OverlayViewController viewController, @Nullable Runnable hide) {
         debugLog();
+        if (mIsOccluded && mViewsHiddenForOcclusion.contains(viewController)) {
+            mViewsHiddenForOcclusion.remove(viewController);
+            return;
+        }
         if (!viewController.isInflated()) {
             Log.d(TAG, "Content cannot be hidden since it isn't inflated: "
                     + viewController.getClass().getName());
@@ -240,6 +256,43 @@
         return mZOrderVisibleSortedMap.isEmpty() || mHighestZOrder.shouldShowHUN();
     }
 
+    /**
+     * Set the OverlayViewWindow to be in occluded or unoccluded state. When OverlayViewWindow is
+     * occluded, all views mounted to it that are not configured to be shown during occlusion will
+     * be hidden.
+     */
+    public void setOccluded(boolean occluded) {
+        if (occluded) {
+            // Hide views before setting mIsOccluded to true so the regular hideView logic is used,
+            // not the one used during occlusion.
+            hideViewsForOcclusion();
+            mIsOccluded = true;
+        } else {
+            mIsOccluded = false;
+            // show views after setting mIsOccluded to false so the regular showView logic is used,
+            // not the one used during occlusion.
+            showViewsHiddenForOcclusion();
+        }
+    }
+
+    private void hideViewsForOcclusion() {
+        HashSet<OverlayViewController> viewsCurrentlyShowing = new HashSet<>(
+                mZOrderVisibleSortedMap.values());
+        viewsCurrentlyShowing.forEach(overlayController -> {
+            if (!overlayController.shouldShowWhenOccluded()) {
+                hideView(overlayController, overlayController::hideInternal);
+                mViewsHiddenForOcclusion.add(overlayController);
+            }
+        });
+    }
+
+    private void showViewsHiddenForOcclusion() {
+        mViewsHiddenForOcclusion.forEach(overlayViewController -> {
+            showView(overlayViewController, overlayViewController::showInternal);
+        });
+        mViewsHiddenForOcclusion.clear();
+    }
+
     private void debugLog() {
         if (!DEBUG) {
             return;
@@ -250,5 +303,8 @@
         Log.d(TAG, "mZOrderVisibleSortedMap: " + mZOrderVisibleSortedMap);
         Log.d(TAG, "mZOrderMap.size(): " + mZOrderMap.size());
         Log.d(TAG, "mZOrderMap: " + mZOrderMap);
+        Log.d(TAG, "mIsOccluded: " + mIsOccluded);
+        Log.d(TAG, "mViewsHiddenForOcclusion: " + mViewsHiddenForOcclusion);
+        Log.d(TAG, "mViewsHiddenForOcclusion.size(): " + mViewsHiddenForOcclusion.size());
     }
 }
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
index 38836d8..189e240 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
@@ -22,6 +22,7 @@
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -169,6 +170,18 @@
     }
 
     @Test
+    public void setOccludedFalse_currentlyOccluded_bouncerReset() {
+        when(mBouncer.isSecure()).thenReturn(true);
+        mCarKeyguardViewController.show(/* options= */ null);
+        mCarKeyguardViewController.setOccluded(/* occluded= */ true, /* animate= */ false);
+        reset(mBouncer);
+
+        mCarKeyguardViewController.setOccluded(/* occluded= */ false, /* animate= */ false);
+
+        verify(mBouncer).show(/* resetSecuritySelection= */ true);
+    }
+
+    @Test
     public void onCancelClicked_callsCancelClickedListener() {
         when(mBouncer.isSecure()).thenReturn(true);
         mCarKeyguardViewController.show(/* options= */ null);
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
index 54282d3..bcaa5e9 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
@@ -36,8 +36,8 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.keyguard.AlphaOptimizedImageButton;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.AlphaOptimizedImageView;
 import com.android.systemui.tests.R;
 
 import org.junit.Before;
@@ -74,7 +74,7 @@
 
     @Test
     public void onCreate_iconIsVisible() {
-        AlphaOptimizedImageButton icon = mDefaultButton.findViewById(
+        AlphaOptimizedImageView icon = mDefaultButton.findViewById(
                 R.id.car_nav_button_icon_image);
 
         assertThat(icon.getDrawable()).isNotNull();
@@ -83,12 +83,12 @@
     @Test
     public void onSelected_selectedIconDefined_togglesIcon() {
         mDefaultButton.setSelected(true);
-        Drawable selectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById(
+        Drawable selectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
                 R.id.car_nav_button_icon_image)).getDrawable();
 
 
         mDefaultButton.setSelected(false);
-        Drawable unselectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById(
+        Drawable unselectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
                 R.id.car_nav_button_icon_image)).getDrawable();
 
         assertThat(selectedIconDrawable).isNotEqualTo(unselectedIconDrawable);
@@ -100,12 +100,12 @@
                 R.id.selected_icon_undefined);
 
         selectedIconUndefinedButton.setSelected(true);
-        Drawable selectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById(
+        Drawable selectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
                 R.id.car_nav_button_icon_image)).getDrawable();
 
 
         selectedIconUndefinedButton.setSelected(false);
-        Drawable unselectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById(
+        Drawable unselectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
                 R.id.car_nav_button_icon_image)).getDrawable();
 
         assertThat(selectedIconDrawable).isEqualTo(unselectedIconDrawable);
@@ -150,7 +150,7 @@
     @Test
     public void onSelected_doesNotShowMoreWhenSelected_doesNotShowMoreIcon() {
         mDefaultButton.setSelected(true);
-        AlphaOptimizedImageButton moreIcon = mDefaultButton.findViewById(
+        AlphaOptimizedImageView moreIcon = mDefaultButton.findViewById(
                 R.id.car_nav_button_more_icon);
 
         assertThat(moreIcon.getVisibility()).isEqualTo(View.GONE);
@@ -161,7 +161,7 @@
         CarNavigationButton showMoreWhenSelected = mTestView.findViewById(
                 R.id.not_highlightable_more_button);
         showMoreWhenSelected.setSelected(true);
-        AlphaOptimizedImageButton moreIcon = showMoreWhenSelected.findViewById(
+        AlphaOptimizedImageView moreIcon = showMoreWhenSelected.findViewById(
                 R.id.car_nav_button_more_icon);
 
         assertThat(moreIcon.getVisibility()).isEqualTo(View.VISIBLE);
@@ -173,7 +173,7 @@
                 R.id.highlightable_no_more_button);
         showMoreWhenSelected.setSelected(true);
         showMoreWhenSelected.setSelected(false);
-        AlphaOptimizedImageButton moreIcon = showMoreWhenSelected.findViewById(
+        AlphaOptimizedImageView moreIcon = showMoreWhenSelected.findViewById(
                 R.id.car_nav_button_more_icon);
 
         assertThat(moreIcon.getVisibility()).isEqualTo(View.GONE);
@@ -187,7 +187,7 @@
         roleBasedButton.setSelected(false);
         roleBasedButton.setAppIcon(appIcon);
 
-        Drawable currentDrawable = ((AlphaOptimizedImageButton) roleBasedButton.findViewById(
+        Drawable currentDrawable = ((AlphaOptimizedImageView) roleBasedButton.findViewById(
                 R.id.car_nav_button_icon_image)).getDrawable();
 
         assertThat(currentDrawable).isEqualTo(appIcon);
@@ -212,7 +212,7 @@
         roleBasedButton.setSelected(true);
         roleBasedButton.setAppIcon(appIcon);
 
-        Drawable currentDrawable = ((AlphaOptimizedImageButton) roleBasedButton.findViewById(
+        Drawable currentDrawable = ((AlphaOptimizedImageView) roleBasedButton.findViewById(
                 R.id.car_nav_button_icon_image)).getDrawable();
 
         assertThat(currentDrawable).isEqualTo(appIcon);
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
index 9e6e616..cba42e5 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
@@ -491,6 +491,81 @@
     }
 
     @Test
+    public void setOccludedTrue_viewToHideWhenOccludedVisible_viewHidden() {
+        setupOverlayViewController1();
+        setOverlayViewControllerAsShowing(mOverlayViewController1);
+        when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
+
+        mOverlayViewGlobalStateController.setOccluded(true);
+
+        assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+                mOverlayViewController1)).isFalse();
+    }
+
+    @Test
+    public void setOccludedTrue_viewToNotHideWhenOccludedVisible_viewShown() {
+        setupOverlayViewController1();
+        setOverlayViewControllerAsShowing(mOverlayViewController1);
+        when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(true);
+
+        mOverlayViewGlobalStateController.setOccluded(true);
+
+        assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+                mOverlayViewController1)).isTrue();
+    }
+
+    @Test
+    public void hideViewAndThenSetOccludedTrue_viewHiddenForOcclusion_viewHiddenAfterOcclusion() {
+        setupOverlayViewController1();
+        setOverlayViewControllerAsShowing(mOverlayViewController1);
+        when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
+        mOverlayViewGlobalStateController.setOccluded(true);
+
+        mOverlayViewGlobalStateController.hideView(mOverlayViewController1, /* runnable= */ null);
+        mOverlayViewGlobalStateController.setOccluded(false);
+
+        assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+                mOverlayViewController1)).isFalse();
+    }
+
+    @Test
+    public void setOccludedTrueAndThenShowView_viewToNotHideForOcclusion_viewShown() {
+        setupOverlayViewController1();
+        when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(true);
+
+        mOverlayViewGlobalStateController.setOccluded(true);
+        setOverlayViewControllerAsShowing(mOverlayViewController1);
+
+        assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+                mOverlayViewController1)).isTrue();
+    }
+
+    @Test
+    public void setOccludedTrueAndThenShowView_viewToHideForOcclusion_viewHidden() {
+        setupOverlayViewController1();
+        when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
+
+        mOverlayViewGlobalStateController.setOccluded(true);
+        setOverlayViewControllerAsShowing(mOverlayViewController1);
+
+        assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+                mOverlayViewController1)).isFalse();
+    }
+
+    @Test
+    public void setOccludedFalse_viewShownAfterSetOccludedTrue_viewToHideForOcclusion_viewShown() {
+        setupOverlayViewController1();
+        when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
+        mOverlayViewGlobalStateController.setOccluded(true);
+        setOverlayViewControllerAsShowing(mOverlayViewController1);
+
+        mOverlayViewGlobalStateController.setOccluded(false);
+
+        assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+                mOverlayViewController1)).isTrue();
+    }
+
+    @Test
     public void inflateView_notInflated_inflates() {
         when(mOverlayViewController2.isInflated()).thenReturn(false);
 
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index d039c9f..1b5062e 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -140,8 +140,8 @@
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Адкрытая сетка"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Бяспечная сетка"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"АС Android"</string>
-    <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Выдаленыя прыкладанні"</string>
-    <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Выдаленыя прыкладанні і карыстальнiкi"</string>
+    <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Выдаленыя праграмы"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Выдаленыя праграмы і карыстальнiкi"</string>
     <string name="data_usage_ota" msgid="7984667793701597001">"Абнаўленні сістэмы"</string>
     <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB-мадэм"</string>
     <string name="tether_settings_title_wifi" msgid="4803402057533895526">"Партатыўны хот-спот"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 65f456e..d003ef0 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -449,7 +449,7 @@
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> täislaadimiseni"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Tundmatu"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Laadimine"</string>
-    <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiiresti laadimine"</string>
+    <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiirlaadimine"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Aeglaselt laadimine"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Ei lae"</string>
     <string name="battery_info_status_not_charging" msgid="8330015078868707899">"Vooluvõrgus, praegu ei saa laadida"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
index a6202956..38eeda2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -19,10 +19,13 @@
 import android.app.Application;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.hardware.usb.IUsbManager;
+import android.net.Uri;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -44,6 +47,15 @@
      */
     private static InstantAppDataProvider sInstantAppDataProvider = null;
 
+    private static final Intent sBrowserIntent;
+
+    static {
+        sBrowserIntent = new Intent()
+                .setAction(Intent.ACTION_VIEW)
+                .addCategory(Intent.CATEGORY_BROWSABLE)
+                .setData(Uri.parse("http:"));
+    }
+
     public static CharSequence getLaunchByDefaultSummary(ApplicationsState.AppEntry appEntry,
             IUsbManager usbManager, PackageManager pm, Context context) {
         String packageName = appEntry.info.packageName;
@@ -153,4 +165,22 @@
         return com.android.settingslib.utils.applications.AppUtils.getAppContentDescription(context,
                 packageName, userId);
     }
+
+    /**
+     * Returns a boolean indicating whether a given package is a browser app.
+     *
+     * An app is a "browser" if it has an activity resolution that wound up
+     * marked with the 'handleAllWebDataURI' flag.
+     */
+    public static boolean isBrowserApp(Context context, String packageName, int userId) {
+        sBrowserIntent.setPackage(packageName);
+        final List<ResolveInfo> list = context.getPackageManager().queryIntentActivitiesAsUser(
+                sBrowserIntent, PackageManager.MATCH_ALL, userId);
+        for (ResolveInfo info : list) {
+            if (info.activityInfo != null && info.handleAllWebDataURI) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index ae8e8e8..44349c5 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -306,6 +306,9 @@
     <!-- Permission needed for CTS test - PrivilegedLocationPermissionTest -->
     <uses-permission android:name="android.permission.LOCATION_HARDWARE" />
 
+    <!-- Permissions required for GTS test - GtsDialerAudioTestCases -->
+    <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/res/drawable/dismiss_circle_background.xml b/packages/SystemUI/res/drawable/dismiss_circle_background.xml
index e311c52..7809c83 100644
--- a/packages/SystemUI/res/drawable/dismiss_circle_background.xml
+++ b/packages/SystemUI/res/drawable/dismiss_circle_background.xml
@@ -21,8 +21,8 @@
 
     <stroke
         android:width="1dp"
-        android:color="#66FFFFFF" />
+        android:color="#AAFFFFFF" />
 
-    <solid android:color="#B3000000" />
+    <solid android:color="#77000000" />
 
 </shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/dismiss_target_x.xml b/packages/SystemUI/res/drawable/dismiss_target_x.xml
deleted file mode 100644
index 3672eff..0000000
--- a/packages/SystemUI/res/drawable/dismiss_target_x.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2020 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.
-  -->
-
-<!-- 'X' icon. -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
-        android:fillColor="#FFFFFFFF"
-        android:strokeColor="#FF000000"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/floating_dismiss_gradient.xml b/packages/SystemUI/res/drawable/floating_dismiss_gradient.xml
new file mode 100644
index 0000000..8f7fb10
--- /dev/null
+++ b/packages/SystemUI/res/drawable/floating_dismiss_gradient.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <gradient
+        android:angle="270"
+        android:startColor="#00000000"
+        android:endColor="#77000000"
+        android:type="linear" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml b/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml
new file mode 100644
index 0000000..6a0695e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@color/transparent" />
+    <item android:drawable="@drawable/floating_dismiss_gradient" />
+</transition>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/partial_conversation_info.xml b/packages/SystemUI/res/layout/partial_conversation_info.xml
index b348222..803b0c6 100644
--- a/packages/SystemUI/res/layout/partial_conversation_info.xml
+++ b/packages/SystemUI/res/layout/partial_conversation_info.xml
@@ -52,39 +52,20 @@
             android:gravity="center_vertical"
             android:layout_alignEnd="@id/conversation_icon"
             android:layout_toEndOf="@id/conversation_icon">
-            <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:gravity="start"
-                android:orientation="horizontal">
-                <TextView
-                    android:id="@+id/name"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    style="@style/TextAppearance.NotificationImportanceChannel"/>
-                <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_centerVertical="true"
-                    style="@style/TextAppearance.NotificationImportanceHeader"
-                    android:layout_marginStart="2dp"
-                    android:layout_marginEnd="2dp"
-                    android:text="@*android:string/notification_header_divider_symbol" />
-                <TextView
-                    android:id="@+id/parent_channel_name"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    style="@style/TextAppearance.NotificationImportanceChannel"/>
-
-            </LinearLayout>
             <TextView
-                android:id="@+id/pkg_name"
+                android:id="@+id/name"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                style="@style/TextAppearance.NotificationImportanceChannelGroup"
                 android:ellipsize="end"
                 android:textDirection="locale"
-                android:maxLines="1"/>
+                style="@style/TextAppearance.NotificationImportanceChannel"/>
+            <TextView
+                android:id="@+id/parent_channel_name"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:ellipsize="end"
+                android:textDirection="locale"
+                style="@style/TextAppearance.NotificationImportanceChannel"/>
             <TextView
                 android:id="@+id/group_name"
                 android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
index c27b3a9..bf2eac3 100644
--- a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
+++ b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
@@ -38,157 +38,67 @@
         android:background="@drawable/rounded_bg_full"
         >
 
-        <!--  We have a known number of rows that can be shown; just design them all here -->
-        <LinearLayout
-            android:id="@+id/show_at_top_tip"
+        <ImageView
+            android:id="@+id/conversation_icon"
+            android:layout_width="@dimen/notification_guts_conversation_icon_size"
+            android:layout_height="@dimen/notification_guts_conversation_icon_size"
+            android:layout_gravity="center_horizontal" />
+
+        <TextView
+            android:id="@+id/title"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingTop="8dp"
-            android:paddingBottom="8dp"
-            android:paddingStart="4dp"
-            android:paddingEnd="4dp"
-            android:orientation="horizontal"
-            >
-            <ImageView
-                android:id="@+id/bell_icon"
-                android:layout_width="24dp"
-                android:layout_height="24dp"
-                android:layout_gravity="center_vertical"
-                android:src="@drawable/ic_notifications_alert"
-                android:tint="?android:attr/colorControlNormal" />
+            android:gravity="center_horizontal"
+            android:layout_marginTop="16dp"
+            android:text="@string/priority_onboarding_title"
+            style="@style/TextAppearance.NotificationImportanceChannel"
+        />
 
-            <TextView
-                android:id="@+id/show_at_top_text"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingStart="16dp"
-                android:paddingEnd="16dp"
-                android:gravity="center_vertical|start"
-                android:textSize="15sp"
-                android:ellipsize="end"
-                android:maxLines="2"
-                android:text="@string/priority_onboarding_show_at_top_text"
-                style="@style/TextAppearance.NotificationInfo"
-                />
+        <View
+            android:id="@+id/divider"
+            android:layout_width="match_parent"
+            android:layout_height="0.5dp"
+            android:layout_marginTop="20dp"
+            android:layout_marginBottom="20dp"
+            android:background="@color/material_grey_300" />
 
-        </LinearLayout>
-
-        <LinearLayout
-            android:id="@+id/show_avatar_tip"
+        <TextView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingTop="8dp"
-            android:paddingBottom="8dp"
-            android:paddingStart="4dp"
-            android:paddingEnd="4dp"
-            android:orientation="horizontal"
-            >
-            <ImageView
-                android:id="@+id/avatar_icon"
-                android:layout_width="24dp"
-                android:layout_height="24dp"
-                android:layout_gravity="center_vertical"
-                android:src="@drawable/ic_person"
-                android:tint="?android:attr/colorControlNormal" />
+            android:gravity="start"
+            android:text="@string/priority_onboarding_behavior"
+            style="@style/TextAppearance.NotificationImportanceChannelGroup"
+        />
 
-            <TextView
-                android:id="@+id/avatar_text"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingStart="16dp"
-                android:paddingEnd="16dp"
-                android:gravity="center_vertical|start"
-                android:textSize="15sp"
-                android:ellipsize="end"
-                android:maxLines="2"
-                android:text="@string/priority_onboarding_show_avatar_text"
-                style="@style/TextAppearance.NotificationInfo"
-                />
-
-        </LinearLayout>
-
-        <!-- These rows show optionally -->
-
-        <LinearLayout
-            android:id="@+id/floating_bubble_tip"
+        <TextView
+            android:id="@+id/behaviors"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingTop="8dp"
-            android:paddingBottom="8dp"
-            android:paddingStart="4dp"
-            android:paddingEnd="4dp"
-            android:orientation="horizontal"
-            >
-
-            <ImageView
-                android:id="@+id/bubble_icon"
-                android:layout_width="24dp"
-                android:layout_height="24dp"
-                android:layout_gravity="center_vertical"
-                android:src="@drawable/ic_create_bubble"
-                android:tint="?android:attr/colorControlNormal" />
-
-            <TextView
-                android:id="@+id/bubble_text"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingStart="16dp"
-                android:paddingEnd="16dp"
-                android:gravity="center_vertical|start"
-                android:textSize="15sp"
-                android:ellipsize="end"
-                android:maxLines="2"
-                android:text="@string/priority_onboarding_appear_as_bubble_text"
-                style="@style/TextAppearance.NotificationInfo"
-                />
-
-        </LinearLayout>
-
-        <LinearLayout
-            android:id="@+id/ignore_dnd_tip"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="8dp"
-            android:paddingBottom="8dp"
-            android:paddingStart="4dp"
-            android:paddingEnd="4dp"
-            android:orientation="horizontal"
-            >
-
-            <ImageView
-                android:id="@+id/dnd_icon"
-                android:layout_width="24dp"
-                android:layout_height="24dp"
-                android:layout_gravity="center_vertical"
-                android:src="@drawable/moon"
-                android:tint="?android:attr/colorControlNormal" />
-
-            <TextView
-                android:id="@+id/dnd_text"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingStart="16dp"
-                android:paddingEnd="16dp"
-                android:gravity="center_vertical|start"
-                android:textSize="15sp"
-                android:ellipsize="end"
-                android:maxLines="2"
-                android:text="@string/priority_onboarding_ignores_dnd_text"
-                style="@style/TextAppearance.NotificationInfo"
-                />
-
-        </LinearLayout>
+            android:gravity="start"
+            android:layout_marginTop="8dp"
+            style="@style/TextAppearance.NotificationImportanceChannelGroup"
+        />
 
         <!-- Bottom button container -->
         <RelativeLayout
             android:id="@+id/button_container"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingStart="4dp"
-            android:paddingEnd="4dp"
+            android:layout_marginTop="32dp"
             android:orientation="horizontal"
             >
             <TextView
+                android:id="@+id/settings_button"
+                android:text="@string/priority_onboarding_settings_button_title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentStart="true"
+                android:gravity="start|center_vertical"
+                android:minWidth="@dimen/notification_importance_toggle_size"
+                android:minHeight="@dimen/notification_importance_toggle_size"
+                android:maxWidth="125dp"
+                style="@style/TextAppearance.NotificationInfo.Button"/>
+            <TextView
                 android:id="@+id/done_button"
                 android:text="@string/priority_onboarding_done_button_title"
                 android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/quick_settings_footer.xml b/packages/SystemUI/res/layout/quick_settings_footer.xml
index 846c538..15f398a 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer.xml
@@ -23,7 +23,7 @@
     android:paddingStart="@dimen/qs_footer_padding_start"
     android:paddingEnd="@dimen/qs_footer_padding_end"
     android:gravity="center_vertical"
-    android:background="?android:attr/colorPrimary" >
+    android:background="@android:color/transparent">
 
     <TextView
         android:id="@+id/footer_text"
@@ -32,7 +32,7 @@
         android:gravity="start"
         android:layout_weight="1"
         android:textAppearance="@style/TextAppearance.QS.TileLabel"
-        android:textColor="?android:attr/textColorSecondary"/>
+        style="@style/qs_security_footer"/>
 
     <ImageView
         android:id="@+id/footer_icon"
@@ -40,6 +40,6 @@
         android:layout_height="@dimen/qs_footer_icon_size"
         android:contentDescription="@null"
         android:src="@drawable/ic_info_outline"
-        android:tint="?android:attr/textColorSecondary"/>
+        style="@style/qs_security_footer"/>
 
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml b/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
index af6f9bb..0c4d5a2 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
@@ -16,21 +16,20 @@
   -->
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
+    android:layout_width="250dp"
     android:layout_height="48dp"
     android:orientation="vertical"
-    android:padding="10dp"
-    android:layout_weight="1">
+    android:padding="13dp">
     <TextView
         android:id="@+id/screen_recording_dialog_source_text"
-        android:layout_width="match_parent"
+        android:layout_width="250dp"
         android:layout_height="match_parent"
         android:layout_gravity="center_vertical"
         android:textAppearance="?android:attr/textAppearanceSmall"
         android:textColor="?android:attr/textColorPrimary"/>
     <TextView
         android:id="@+id/screen_recording_dialog_source_description"
-        android:layout_width="wrap_content"
+        android:layout_width="250dp"
         android:layout_height="wrap_content"
         android:textAppearance="?android:attr/textAppearanceSmall"
         android:textColor="?android:attr/textColorSecondary"/>
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index 4fdeb6f..50261e1 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -29,4 +29,9 @@
         <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
 
+    <style name="qs_security_footer" parent="@style/qs_theme">
+        <item name="android:textColor">#B3FFFFFF</item> <!-- 70% white -->
+        <item name="android:tint">#FFFFFFFF</item>
+    </style>
+
 </resources>
diff --git a/packages/SystemUI/res/values-sw320dp/dimens.xml b/packages/SystemUI/res/values-sw320dp/dimens.xml
deleted file mode 100644
index c110113..0000000
--- a/packages/SystemUI/res/values-sw320dp/dimens.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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>
-    <!-- Global actions grid -->
-    <dimen name="global_actions_grid_vertical_padding">3dp</dimen>
-    <dimen name="global_actions_grid_horizontal_padding">3dp</dimen>
-
-    <dimen name="global_actions_grid_item_side_margin">5dp</dimen>
-    <dimen name="global_actions_grid_item_vertical_margin">4dp</dimen>
-    <dimen name="global_actions_grid_item_width">64dp</dimen>
-    <dimen name="global_actions_grid_item_height">64dp</dimen>
-
-    <dimen name="global_actions_grid_item_icon_width">20dp</dimen>
-    <dimen name="global_actions_grid_item_icon_height">20dp</dimen>
-    <dimen name="global_actions_grid_item_icon_top_margin">12dp</dimen>
-    <dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen>
-    <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
-
-    <!-- Home Controls -->
-    <dimen name="global_actions_side_margin">10dp</dimen>
-</resources>
-
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index e26f31c..73d8e9a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -224,6 +224,7 @@
     <dimen name="notification_guts_conversation_icon_size">56dp</dimen>
     <dimen name="notification_guts_conversation_action_height">56dp</dimen>
     <dimen name="notification_guts_conversation_action_text_padding_start">32dp</dimen>
+    <dimen name="conversation_onboarding_bullet_gap_width">6dp</dimen>
 
     <!-- The height of the header in inline settings -->
     <dimen name="notification_guts_header_height">24dp</dimen>
@@ -973,7 +974,9 @@
     <dimen name="recents_quick_scrub_onboarding_margin_start">8dp</dimen>
 
     <!-- The height of the gradient indicating the dismiss edge when moving a PIP. -->
-    <dimen name="floating_dismiss_gradient_height">176dp</dimen>
+    <dimen name="floating_dismiss_gradient_height">250dp</dimen>
+
+    <dimen name="floating_dismiss_bottom_margin">50dp</dimen>
 
     <!-- The bottom margin of the PIP drag to dismiss info text shown when moving a PIP. -->
     <dimen name="pip_dismiss_text_bottom_margin">24dp</dimen>
@@ -1031,8 +1034,23 @@
     <dimen name="global_actions_grid_container_shadow_offset">20dp</dimen>
     <dimen name="global_actions_grid_container_negative_shadow_offset">-20dp</dimen>
 
+    <!-- Global actions grid -->
+    <dimen name="global_actions_grid_vertical_padding">3dp</dimen>
+    <dimen name="global_actions_grid_horizontal_padding">3dp</dimen>
+
+    <dimen name="global_actions_grid_item_side_margin">5dp</dimen>
+    <dimen name="global_actions_grid_item_vertical_margin">4dp</dimen>
+    <dimen name="global_actions_grid_item_width">64dp</dimen>
+    <dimen name="global_actions_grid_item_height">64dp</dimen>
+
+    <dimen name="global_actions_grid_item_icon_width">20dp</dimen>
+    <dimen name="global_actions_grid_item_icon_height">20dp</dimen>
+    <dimen name="global_actions_grid_item_icon_top_margin">12dp</dimen>
+    <dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen>
+    <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
+
     <!-- Margins at the left and right of the power menu and home controls widgets. -->
-    <dimen name="global_actions_side_margin">16dp</dimen>
+    <dimen name="global_actions_side_margin">10dp</dimen>
 
     <!-- Amount to shift the layout when exiting/entering for controls activities -->
     <dimen name="global_actions_controls_y_translation">20dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 97a0d03..39237ac 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2667,6 +2667,11 @@
     <string name="inattentive_sleep_warning_title">Standby</string>
 
     <!-- Priority conversation onboarding screen -->
+    <!--  title of priority onboarding [CHAR LIMIT=75]  -->
+    <string name="priority_onboarding_title">Conversation set to priority</string>
+    <!--  Text explaining that the following actions are the behaviors of priority conversations.
+    E.g. priority conversations will show at the top of the conversation section [CHAR LIMIT=75]  -->
+    <string name="priority_onboarding_behavior">Priority conversations will:</string>
     <!--  Text explaining that priority conversations show at the top of the conversation section [CHAR LIMIT=75]  -->
     <string name="priority_onboarding_show_at_top_text">Show at top of conversation section</string>
     <!--  Text explaining that priority conversations show an avatar on the lock screen [CHAR LIMIT=75]  -->
@@ -2677,6 +2682,8 @@
     <string name="priority_onboarding_ignores_dnd_text">Interrupt Do Not Disturb</string>
     <!--  Title for the affirmative button [CHAR LIMIT=50]  -->
     <string name="priority_onboarding_done_button_title">Got it</string>
+    <!--  Title for the settings button button [CHAR LIMIT=50]  -->
+    <string name="priority_onboarding_settings_button_title">Settings</string>
 
     <!-- Window Magnification strings -->
     <!-- Title for Magnification Overlay Window [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index ed36bdb..39f78bf 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -387,6 +387,11 @@
         <item name="android:homeAsUpIndicator">@drawable/ic_arrow_back</item>
     </style>
 
+    <style name="qs_security_footer" parent="@style/qs_theme">
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+        <item name="android:tint">?android:attr/textColorSecondary</item>
+    </style>
+
     <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
         <item name="android:colorAccent">@color/remote_input_accent</item>
     </style>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 35ad422..655008b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -23,10 +23,11 @@
 import android.view.MotionEvent;
 
 import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
+import com.android.systemui.shared.recents.model.Task;
 
 /**
  * Temporary callbacks into SystemUI.
- * Next id = 26
+ * Next id = 27
  */
 interface ISystemUiProxy {
 
@@ -122,6 +123,9 @@
 
     /**
      * Handle the provided image as if it was a screenshot.
+     *
+     * Deprecated, use handleImageBundleAsScreenshot with image bundle and UserTask
+     * @deprecated
      */
     void handleImageAsScreenshot(in Bitmap screenImage, in Rect locationInScreen,
               in Insets visibleInsets, int taskId) = 21;
@@ -146,4 +150,10 @@
      * @param rotation indicates which Surface.Rotation the gesture was started in
      */
     void onQuickSwitchToNewTask(int rotation) = 25;
+
+    /**
+     * Handle the provided image as if it was a screenshot.
+     */
+    void handleImageBundleAsScreenshot(in Bundle screenImageBundle, in Rect locationInScreen,
+              in Insets visibleInsets, in Task.TaskKey task) = 26;
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.aidl
new file mode 100644
index 0000000..e7cad2a
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 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.recents.model;
+
+parcelable Task.TaskKey;
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index dcb134e..186379a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -26,6 +26,8 @@
 import android.content.pm.ActivityInfo;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.view.ViewDebug;
 
 import com.android.systemui.shared.recents.utilities.Utilities;
@@ -52,8 +54,10 @@
         void onTaskWindowingModeChanged();
     }
 
-    /* The Task Key represents the unique primary key for the task */
-    public static class TaskKey {
+    /**
+     * The Task Key represents the unique primary key for the task
+     */
+    public static class TaskKey implements Parcelable {
         @ViewDebug.ExportedProperty(category="recents")
         public final int id;
         @ViewDebug.ExportedProperty(category="recents")
@@ -157,6 +161,48 @@
         private void updateHashCode() {
             mHashCode = Objects.hash(id, windowingMode, userId);
         }
+
+        public static final Parcelable.Creator<TaskKey> CREATOR =
+                new Parcelable.Creator<TaskKey>() {
+                    @Override
+                    public TaskKey createFromParcel(Parcel source) {
+                        return TaskKey.readFromParcel(source);
+                    }
+
+                    @Override
+                    public TaskKey[] newArray(int size) {
+                        return new TaskKey[size];
+                    }
+                };
+
+        @Override
+        public final void writeToParcel(Parcel parcel, int flags) {
+            parcel.writeInt(id);
+            parcel.writeInt(windowingMode);
+            parcel.writeTypedObject(baseIntent, flags);
+            parcel.writeInt(userId);
+            parcel.writeLong(lastActiveTime);
+            parcel.writeInt(displayId);
+            parcel.writeTypedObject(sourceComponent, flags);
+        }
+
+        private static TaskKey readFromParcel(Parcel parcel) {
+            int id = parcel.readInt();
+            int windowingMode = parcel.readInt();
+            Intent baseIntent = parcel.readTypedObject(Intent.CREATOR);
+            int userId = parcel.readInt();
+            long lastActiveTime = parcel.readLong();
+            int displayId = parcel.readInt();
+            ComponentName sourceComponent = parcel.readTypedObject(ComponentName.CREATOR);
+
+            return new TaskKey(id, windowingMode, baseIntent, sourceComponent, userId,
+                    lastActiveTime, displayId);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
     }
 
     @ViewDebug.ExportedProperty(deepExport=true, prefix="key_")
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java
new file mode 100644
index 0000000..b79fcbd
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 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.recents.utilities;
+
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.graphics.ParcelableColorSpace;
+import android.hardware.HardwareBuffer;
+import android.os.Bundle;
+
+import java.util.Objects;
+
+/**
+ * Utils for working with Bitmaps.
+ */
+public final class BitmapUtil {
+    private static final String KEY_BUFFER = "bitmap_util_buffer";
+    private static final String KEY_COLOR_SPACE = "bitmap_util_color_space";
+
+    private BitmapUtil(){ }
+
+    /**
+     * Creates a Bundle that represents the given Bitmap.
+     * <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will avoid
+     * copies when passing across processes, only pass to processes you trust.
+     *
+     * <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions, the
+     * returned Bundle should be treated as a standalone object.
+     *
+     * @param bitmap to convert to bundle
+     * @return a Bundle representing the bitmap, should only be parsed by
+     *         {@link #bundleToHardwareBitmap(Bundle)}
+     */
+    public static Bundle hardwareBitmapToBundle(Bitmap bitmap) {
+        if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
+            throw new IllegalArgumentException(
+                    "Passed bitmap must have hardware config, found: " + bitmap.getConfig());
+        }
+
+        // Bitmap assumes SRGB for null color space
+        ParcelableColorSpace colorSpace =
+                bitmap.getColorSpace() == null
+                        ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
+                        : new ParcelableColorSpace(bitmap.getColorSpace());
+
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());
+        bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);
+
+        return bundle;
+    }
+
+    /**
+     * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)} .}
+     *
+     * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful passing this
+     * Bitmap on to any other source.
+     *
+     * @param bundle containing the bitmap
+     * @return a hardware Bitmap
+     */
+    public static Bitmap bundleToHardwareBitmap(Bundle bundle) {
+        if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) {
+            throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
+        }
+
+        HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER);
+        ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE);
+
+        return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer), colorSpace);
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index dd5cc7c..796aaee 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -114,4 +114,7 @@
 
     /** @see ITaskStackListener#onRecentTaskListFrozenChanged(boolean) */
     public void onRecentTaskListFrozenChanged(boolean frozen) { }
+
+    /** @see ITaskStackListener#onActivityRotation()*/
+    public void onActivityRotation() { }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index a76a901..13f7993 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -237,6 +237,11 @@
         mHandler.obtainMessage(H.ON_TASK_DESCRIPTION_CHANGED, taskInfo).sendToTarget();
     }
 
+    @Override
+    public void onActivityRotation() {
+        mHandler.obtainMessage(H.ON_ACTIVITY_ROTATION).sendToTarget();
+    }
+
     private final class H extends Handler {
         private static final int ON_TASK_STACK_CHANGED = 1;
         private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
@@ -260,6 +265,7 @@
         private static final int ON_SINGLE_TASK_DISPLAY_EMPTY = 22;
         private static final int ON_TASK_LIST_FROZEN_UNFROZEN = 23;
         private static final int ON_TASK_DESCRIPTION_CHANGED = 24;
+        private static final int ON_ACTIVITY_ROTATION = 25;
 
 
         public H(Looper looper) {
@@ -427,6 +433,12 @@
                         }
                         break;
                     }
+                    case ON_ACTIVITY_ROTATION: {
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onActivityRotation();
+                        }
+                        break;
+                    }
                 }
             }
             if (msg.obj instanceof SomeArgs) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
index dd61326..73783ae 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
@@ -15,6 +15,7 @@
  */
 package com.android.systemui.shared.system;
 
+import android.graphics.HardwareRenderer;
 import android.view.SurfaceControl;
 import android.view.View;
 import android.view.ViewRootImpl;
@@ -50,7 +51,13 @@
 
     public void registerRtFrameCallback(LongConsumer callback) {
         if (mViewRoot != null) {
-            mViewRoot.registerRtFrameCallback(callback::accept);
+            mViewRoot.registerRtFrameCallback(
+                    new HardwareRenderer.FrameDrawingCallback() {
+                        @Override
+                        public void onFrameDraw(long l) {
+                            callback.accept(l);
+                        }
+                    });
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 87990cd..ccb506d 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -124,7 +124,7 @@
         String HAS_SEEN_BUBBLES_MANAGE_EDUCATION = "HasSeenBubblesManageOnboarding";
         String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount";
         /** Tracks whether the user has seen the onboarding screen for priority conversations */
-        String HAS_SEEN_PRIORITY_ONBOARDING = "HasSeenPriorityOnboarding";
+        String HAS_SEEN_PRIORITY_ONBOARDING = "HaveShownPriorityOnboarding";
     }
 
     public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index dfa71ba..8a80c4d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -47,6 +47,7 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
+import android.graphics.drawable.TransitionDrawable;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.util.Log;
@@ -133,6 +134,9 @@
     /** Percent to darken the bubbles when they're in the dismiss target. */
     private static final float DARKEN_PERCENT = 0.3f;
 
+    /** Duration of the dismiss scrim fading in/out. */
+    private static final int DISMISS_TRANSITION_DURATION_MS = 200;
+
     /** How long to wait, in milliseconds, before hiding the flyout. */
     @VisibleForTesting
     static final int FLYOUT_HIDE_AFTER = 5000;
@@ -752,7 +756,7 @@
         final View targetView = new DismissCircleView(context);
         final FrameLayout.LayoutParams newParams =
                 new FrameLayout.LayoutParams(targetSize, targetSize);
-        newParams.gravity = Gravity.CENTER;
+        newParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
         targetView.setLayoutParams(newParams);
         mDismissTargetAnimator = PhysicsAnimator.getInstance(targetView);
 
@@ -761,9 +765,16 @@
                 MATCH_PARENT,
                 getResources().getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height),
                 Gravity.BOTTOM));
+
+        final int bottomMargin =
+                getResources().getDimensionPixelSize(R.dimen.floating_dismiss_bottom_margin);
+        mDismissTargetContainer.setPadding(0, 0, 0, bottomMargin);
+        mDismissTargetContainer.setClipToPadding(false);
         mDismissTargetContainer.setClipChildren(false);
         mDismissTargetContainer.addView(targetView);
         mDismissTargetContainer.setVisibility(View.INVISIBLE);
+        mDismissTargetContainer.setBackgroundResource(
+                R.drawable.floating_dismiss_gradient_transition);
         addView(mDismissTargetContainer);
 
         // Start translated down so the target springs up.
@@ -1884,6 +1895,9 @@
         mDismissTargetContainer.setZ(Short.MAX_VALUE - 1);
         mDismissTargetContainer.setVisibility(VISIBLE);
 
+        ((TransitionDrawable) mDismissTargetContainer.getBackground()).startTransition(
+                DISMISS_TRANSITION_DURATION_MS);
+
         mDismissTargetAnimator.cancel();
         mDismissTargetAnimator
                 .spring(DynamicAnimation.TRANSLATION_Y, 0f, mDismissTargetSpring)
@@ -1901,6 +1915,9 @@
 
         mShowingDismiss = false;
 
+        ((TransitionDrawable) mDismissTargetContainer.getBackground()).reverseTransition(
+                DISMISS_TRANSITION_DURATION_MS);
+
         mDismissTargetAnimator
                 .spring(DynamicAnimation.TRANSLATION_Y, mDismissTargetContainer.getHeight(),
                         mDismissTargetSpring)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index fd9fda3..93f0c7f 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -44,6 +44,7 @@
 import com.android.systemui.controls.ui.ControlsUiController
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.globalactions.GlobalActionsDialog
 import com.android.systemui.util.concurrency.DelayableExecutor
 import java.io.FileDescriptor
 import java.io.PrintWriter
@@ -79,6 +80,7 @@
     }
 
     private var userChanging: Boolean = true
+    private var userStructure: UserStructure
 
     private var seedingInProgress = false
     private val seedingCallbacks = mutableListOf<Consumer<Boolean>>()
@@ -97,7 +99,7 @@
     internal var auxiliaryPersistenceWrapper: AuxiliaryPersistenceWrapper
 
     init {
-        val userStructure = UserStructure(context, currentUser)
+        userStructure = UserStructure(context, currentUser)
 
         persistenceWrapper = optionalWrapper.orElseGet {
             ControlsFavoritePersistenceWrapper(
@@ -116,7 +118,7 @@
     private fun setValuesForUser(newUser: UserHandle) {
         Log.d(TAG, "Changing to user: $newUser")
         currentUser = newUser
-        val userStructure = UserStructure(context, currentUser)
+        userStructure = UserStructure(context, currentUser)
         persistenceWrapper.changeFileAndBackupManager(
                 userStructure.file,
                 BackupManager(userStructure.userContext)
@@ -192,6 +194,16 @@
                     it.componentName
                 }.toSet()
 
+                // When a component is uninstalled, allow seeding to happen again if the user
+                // reinstalls the app
+                val prefs = userStructure.userContext.getSharedPreferences(
+                    GlobalActionsDialog.PREFS_CONTROLS_FILE, Context.MODE_PRIVATE)
+                val completedSeedingPackageSet = prefs.getStringSet(
+                    GlobalActionsDialog.PREFS_CONTROLS_SEEDING_COMPLETED, mutableSetOf<String>())
+                val favoritePackageSet = favoriteComponentSet.map { it.packageName }
+                prefs.edit().putStringSet(GlobalActionsDialog.PREFS_CONTROLS_SEEDING_COMPLETED,
+                    completedSeedingPackageSet.intersect(favoritePackageSet)).apply()
+
                 var changed = false
                 favoriteComponentSet.subtract(serviceInfoSet).forEach {
                     changed = true
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 35ebac5..d31b6eb 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -129,7 +129,10 @@
                         SelectionItem(it.loadLabel(), "", it.loadIcon(), it.componentName)
                     }
                     uiExecutor.execute {
-                        onResult(lastItems)
+                        parent.removeAllViews()
+                        if (lastItems.size > 0) {
+                            onResult(lastItems)
+                        }
                     }
                 }
             }
@@ -189,8 +192,6 @@
     }
 
     private fun showSeedingView(items: List<SelectionItem>) {
-        parent.removeAllViews()
-
         val inflater = LayoutInflater.from(context)
         inflater.inflate(R.layout.controls_no_favorites, parent, true)
         val subtitle = parent.requireViewById<TextView>(R.id.controls_subtitle)
@@ -198,8 +199,6 @@
     }
 
     private fun showInitialSetupView(items: List<SelectionItem>) {
-        parent.removeAllViews()
-
         val inflater = LayoutInflater.from(context)
         inflater.inflate(R.layout.controls_no_favorites, parent, true)
 
@@ -263,7 +262,6 @@
     }
 
     private fun showControlsView(items: List<SelectionItem>) {
-        parent.removeAllViews()
         controlViewsById.clear()
 
         createListView()
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index f970152..9ec1452 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -64,6 +64,10 @@
         }
 
         override fun onActivityViewDestroyed(view: ActivityView) {}
+
+        override fun onTaskRemovalStarted(taskId: Int) {
+            dismiss()
+        }
     }
 
     init {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index 0ec4cc5..4003f41 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -268,7 +268,7 @@
 
     private fun format(primaryFormat: String, backupFormat: String, value: Float): String {
         return try {
-            String.format(primaryFormat, value)
+            String.format(primaryFormat, findNearestStep(value))
         } catch (e: IllegalFormatException) {
             Log.w(ControlsUiController.TAG, "Illegal format in range template", e)
             if (backupFormat == "") {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 95a9006..951dc99 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -71,7 +71,7 @@
             DockManager dockManager, @Nullable IWallpaperManager wallpaperManager,
             ProximitySensor proximitySensor,
             DelayedWakeLock.Builder delayedWakeLockBuilder, @Main Handler handler,
-            DelayableExecutor delayableExecutor,
+            @Main DelayableExecutor delayableExecutor,
             BiometricUnlockController biometricUnlockController,
             BroadcastDispatcher broadcastDispatcher, DozeHost dozeHost) {
         mFalsingManager = falsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 1b13d4a..7e009b4 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -183,8 +183,8 @@
     static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency";
     static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
 
-    private static final String PREFS_CONTROLS_SEEDING_COMPLETED = "SeedingCompleted";
-    private static final String PREFS_CONTROLS_FILE = "controls_prefs";
+    public static final String PREFS_CONTROLS_SEEDING_COMPLETED = "SeedingCompleted";
+    public static final String PREFS_CONTROLS_FILE = "controls_prefs";
     private static final int SEEDING_MAX = 2;
 
     private final Context mContext;
@@ -391,7 +391,15 @@
 
         if (controlsComponent.getControlsListingController().isPresent()) {
             controlsComponent.getControlsListingController().get()
-                    .addCallback(list -> mControlsServiceInfos = list);
+                    .addCallback(list -> {
+                        mControlsServiceInfos = list;
+                        // This callback may occur after the dialog has been shown.
+                        // If so, add controls into the already visible space
+                        if (mDialog != null && !mDialog.isShowingControls()
+                                && shouldShowControls()) {
+                            mDialog.showControls(mControlsUiControllerOptional.get());
+                        }
+                    });
         }
 
         // Need to be user-specific with the context to make sure we read the correct prefs
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index b272b60..baa2dfd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -64,13 +64,16 @@
 import com.android.internal.policy.ScreenDecorationsUtils;
 import com.android.internal.util.ScreenshotHelper;
 import com.android.systemui.Dumpable;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.pip.PipAnimationController;
 import com.android.systemui.pip.PipUI;
 import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
+import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
 import com.android.systemui.shared.recents.ISystemUiProxy;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.stackdivider.Divider;
@@ -83,8 +86,6 @@
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
 import com.android.systemui.statusbar.policy.CallbackController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -101,8 +102,9 @@
  * Class to send information from overview to launcher with a binder.
  */
 @Singleton
-public class OverviewProxyService implements CallbackController<OverviewProxyListener>,
-        NavigationModeController.ModeChangedListener, Dumpable {
+public class OverviewProxyService extends CurrentUserTracker implements
+        CallbackController<OverviewProxyListener>, NavigationModeController.ModeChangedListener,
+        Dumpable {
 
     private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
 
@@ -123,7 +125,6 @@
     private final NotificationShadeWindowController mStatusBarWinController;
     private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
     private final ComponentName mRecentsComponentName;
-    private final DeviceProvisionedController mDeviceProvisionedController;
     private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
     private final Intent mQuickStepIntent;
     private final ScreenshotHelper mScreenshotHelper;
@@ -383,8 +384,7 @@
         @Override
         public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen,
                 Insets visibleInsets, int taskId) {
-            mScreenshotHelper.provideScreenshot(screenImage, locationInScreen, visibleInsets,
-                    taskId, SCREENSHOT_OVERVIEW, mHandler, null);
+            // Deprecated
         }
 
         @Override
@@ -434,6 +434,21 @@
             }
         }
 
+        @Override
+        public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
+                Insets visibleInsets, Task.TaskKey task) {
+            mScreenshotHelper.provideScreenshot(
+                    screenImageBundle,
+                    locationInScreen,
+                    visibleInsets,
+                    task.id,
+                    task.userId,
+                    task.sourceComponent,
+                    SCREENSHOT_OVERVIEW,
+                    mHandler,
+                    null);
+        }
+
         private boolean verifyCaller(String reason) {
             final int callerId = Binder.getCallingUserHandle().getIdentifier();
             if (callerId != mCurrentBoundedUserId) {
@@ -480,7 +495,7 @@
                 return;
             }
 
-            mCurrentBoundedUserId = mDeviceProvisionedController.getCurrentUser();
+            mCurrentBoundedUserId = getCurrentUserId();
             mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
 
             Bundle params = new Bundle();
@@ -523,22 +538,6 @@
         }
     };
 
-    private final DeviceProvisionedListener mDeviceProvisionedCallback =
-                new DeviceProvisionedListener() {
-        @Override
-        public void onUserSetupChanged() {
-            if (mDeviceProvisionedController.isCurrentUserSetup()) {
-                internalConnectToCurrentUser();
-            }
-        }
-
-        @Override
-        public void onUserSwitched() {
-            mConnectionBackoffAttempts = 0;
-            internalConnectToCurrentUser();
-        }
-    };
-
     private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged;
 
     // This is the death handler for the binder from the launcher service
@@ -548,18 +547,18 @@
     @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
     @Inject
     public OverviewProxyService(Context context, CommandQueue commandQueue,
-            DeviceProvisionedController provisionController,
             NavigationBarController navBarController, NavigationModeController navModeController,
             NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
             PipUI pipUI, Optional<Divider> dividerOptional,
-            Optional<Lazy<StatusBar>> statusBarOptionalLazy) {
+            Optional<Lazy<StatusBar>> statusBarOptionalLazy,
+            BroadcastDispatcher broadcastDispatcher) {
+        super(broadcastDispatcher);
         mContext = context;
         mPipUI = pipUI;
         mStatusBarOptionalLazy = statusBarOptionalLazy;
         mHandler = new Handler();
         mNavBarController = navBarController;
         mStatusBarWinController = statusBarWinController;
-        mDeviceProvisionedController = provisionController;
         mConnectionBackoffAttempts = 0;
         mDividerOptional = dividerOptional;
         mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
@@ -580,7 +579,7 @@
 
         // Listen for device provisioned/user setup
         updateEnabledState();
-        mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
+        startTracking();
 
         // Listen for launcher package changes
         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
@@ -604,6 +603,12 @@
         });
     }
 
+    @Override
+    public void onUserSwitched(int newUserId) {
+        mConnectionBackoffAttempts = 0;
+        internalConnectToCurrentUser();
+    }
+
     public void notifyBackAction(boolean completed, int downX, int downY, boolean isButton,
             boolean gestureSwipeLeft) {
         try {
@@ -709,10 +714,8 @@
         disconnectFromLauncherService();
 
         // If user has not setup yet or already connected, do not try to connect
-        if (!mDeviceProvisionedController.isCurrentUserSetup() || !isEnabled()) {
-            Log.v(TAG_OPS, "Cannot attempt connection, is setup "
-                + mDeviceProvisionedController.isCurrentUserSetup() + ", is enabled "
-                + isEnabled());
+        if (!isEnabled()) {
+            Log.v(TAG_OPS, "Cannot attempt connection, is enabled " + isEnabled());
             return;
         }
         mHandler.removeCallbacks(mConnectionRunnable);
@@ -722,7 +725,7 @@
             mBound = mContext.bindServiceAsUser(launcherServiceIntent,
                     mOverviewServiceConnection,
                     Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
-                    UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
+                    UserHandle.of(getCurrentUserId()));
         } catch (SecurityException e) {
             Log.e(TAG_OPS, "Unable to bind because of security error", e);
         }
@@ -881,8 +884,6 @@
         pw.println(TAG_OPS + " state:");
         pw.print("  recentsComponentName="); pw.println(mRecentsComponentName);
         pw.print("  isConnected="); pw.println(mOverviewProxy != null);
-        pw.print("  isCurrentUserSetup="); pw.println(mDeviceProvisionedController
-                .isCurrentUserSetup());
         pw.print("  connectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts);
 
         pw.print("  quickStepIntent="); pw.println(mQuickStepIntent);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 960c501..3e268f6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -225,8 +225,8 @@
                 res.getString(R.string.screenrecord_name));
 
         String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
-                ? res.getString(R.string.screenrecord_ongoing_screen_and_audio)
-                : res.getString(R.string.screenrecord_ongoing_screen_only);
+                ? res.getString(R.string.screenrecord_ongoing_screen_only)
+                : res.getString(R.string.screenrecord_ongoing_screen_and_audio);
 
         mRecordingNotificationBuilder = new Notification.Builder(this, CHANNEL_ID)
                 .setSmallIcon(R.drawable.ic_screenrecord)
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
index 752f4fd..edbc3cf 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
@@ -38,6 +38,7 @@
 public class ScreenInternalAudioRecorder {
     private static String TAG = "ScreenAudioRecorder";
     private static final int TIMEOUT = 500;
+    private static final float MIC_VOLUME_SCALE = 1.4f;
     private final Context mContext;
     private AudioRecord mAudioRecord;
     private AudioRecord mAudioRecordMic;
@@ -148,6 +149,10 @@
                     readShortsInternal = mAudioRecord.read(bufferInternal, 0,
                             bufferInternal.length);
                     readShortsMic = mAudioRecordMic.read(bufferMic, 0, bufferMic.length);
+
+                    // modify the volume
+                    bufferMic = scaleValues(bufferMic,
+                            readShortsMic, MIC_VOLUME_SCALE);
                     readBytes = Math.min(readShortsInternal, readShortsMic) * 2;
                     buffer = addAndConvertBuffers(bufferInternal, readShortsInternal, bufferMic,
                             readShortsMic);
@@ -168,6 +173,19 @@
         });
     }
 
+    private short[] scaleValues(short[] buff, int len, float scale) {
+        for (int i = 0; i < len; i++) {
+            int oldValue = buff[i];
+            int newValue = (int) (buff[i] * scale);
+            if (newValue > Short.MAX_VALUE) {
+                newValue = Short.MAX_VALUE;
+            } else if (newValue < Short.MIN_VALUE) {
+                newValue = Short.MIN_VALUE;
+            }
+            buff[i] = (short) (newValue);
+        }
+        return buff;
+    }
     private byte[] addAndConvertBuffers(short[] a1, int a1Limit, short[] a2, int a2Limit) {
         int size = Math.max(a1Limit, a2Limit);
         if (size < 0) return new byte[0];
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index c967648..8551c88 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -55,9 +55,9 @@
  */
 public class ScreenMediaRecorder {
     private static final int TOTAL_NUM_TRACKS = 1;
-    private static final int VIDEO_BIT_RATE = 10000000;
     private static final int VIDEO_FRAME_RATE = 30;
-    private static final int AUDIO_BIT_RATE = 16;
+    private static final int VIDEO_FRAME_RATE_TO_RESOLUTION_RATIO = 6;
+    private static final int AUDIO_BIT_RATE = 196000;
     private static final int AUDIO_SAMPLE_RATE = 44100;
     private static final int MAX_DURATION_MS = 60 * 60 * 1000;
     private static final long MAX_FILESIZE_BYTES = 5000000000L;
@@ -108,7 +108,7 @@
 
         // Set up audio source
         if (mAudioSource == MIC) {
-            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
         }
         mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
 
@@ -121,10 +121,13 @@
         wm.getDefaultDisplay().getRealMetrics(metrics);
         int screenWidth = metrics.widthPixels;
         int screenHeight = metrics.heightPixels;
+        int refereshRate = (int) wm.getDefaultDisplay().getRefreshRate();
+        int vidBitRate = screenHeight * screenWidth * refereshRate / VIDEO_FRAME_RATE
+                * VIDEO_FRAME_RATE_TO_RESOLUTION_RATIO;
         mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
         mMediaRecorder.setVideoSize(screenWidth, screenHeight);
-        mMediaRecorder.setVideoFrameRate(VIDEO_FRAME_RATE);
-        mMediaRecorder.setVideoEncodingBitRate(VIDEO_BIT_RATE);
+        mMediaRecorder.setVideoFrameRate(refereshRate);
+        mMediaRecorder.setVideoEncodingBitRate(vidBitRate);
         mMediaRecorder.setMaxDuration(MAX_DURATION_MS);
         mMediaRecorder.setMaxFileSize(MAX_FILESIZE_BYTES);
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index abd7e71..d057a8a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -24,12 +24,9 @@
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.Gravity;
-import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
-import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
 import android.widget.Button;
 import android.widget.Spinner;
@@ -88,8 +85,8 @@
         });
 
         mModes = new ArrayList<>();
-        mModes.add(INTERNAL);
         mModes.add(MIC);
+        mModes.add(INTERNAL);
         mModes.add(MIC_AND_INTERNAL);
 
         mAudioSwitch = findViewById(R.id.screenrecord_audio_switch);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
index 2e0e746..3e78489 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
@@ -88,12 +88,6 @@
         return layout;
     }
 
-    private void setDescription(LinearLayout layout, int description) {
-        if (description != Resources.ID_NULL) {
-            ((TextView) layout.getChildAt(1)).setText(description);
-        }
-    }
-
     @Override
     public View getDropDownView(int position, View convertView, ViewGroup parent) {
         switch (getItem(position)) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index a9d3772..9b1734d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -35,6 +35,7 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
@@ -494,8 +495,10 @@
     }
 
     void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
-            Insets visibleInsets, int taskId, Consumer<Uri> finisher, Runnable onComplete) {
-        // TODO use taskId and visibleInsets
+            Insets visibleInsets, int taskId, int userId, ComponentName topComponent,
+            Consumer<Uri> finisher, Runnable onComplete) {
+        // TODO: use task Id, userId, topComponent for smart handler
+        // TODO: use visibleInsets for animation
         mOnCompleteRunnable = onComplete;
         takeScreenshot(screenshot, finisher, screenshotScreenBounds);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
index 095c32f..0017b1f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
@@ -24,6 +24,7 @@
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.annotation.Nullable;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -234,8 +235,10 @@
     }
 
     void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
-            Insets visibleInsets, int taskId, Consumer<Uri> finisher) {
-        // TODO use taskId and visibleInsets
+            Insets visibleInsets, int taskId, int userId, ComponentName topComponent,
+            Consumer<Uri> finisher) {
+        // TODO: use task Id, userId, topComponent for smart handler
+        // TODO: use visibleInsets for animation
         takeScreenshot(screenshot, finisher, false, false, screenshotScreenBounds);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 98030d4..8322fe0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -20,6 +20,7 @@
 import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_URI;
 
 import android.app.Service;
+import android.content.ComponentName;
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.Insets;
@@ -37,6 +38,7 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.util.ScreenshotHelper;
+import com.android.systemui.shared.recents.utilities.BitmapUtil;
 
 import java.util.function.Consumer;
 
@@ -107,16 +109,19 @@
                     }
                     break;
                 case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
-                    Bitmap screenshot = screenshotRequest.getBitmap();
+                    Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap(
+                            screenshotRequest.getBitmapBundle());
                     Rect screenBounds = screenshotRequest.getBoundsInScreen();
                     Insets insets = screenshotRequest.getInsets();
                     int taskId = screenshotRequest.getTaskId();
+                    int userId = screenshotRequest.getUserId();
+                    ComponentName topComponent = screenshotRequest.getTopComponent();
                     if (useCornerFlow) {
-                        mScreenshot.handleImageAsScreenshot(
-                                screenshot, screenBounds, insets, taskId, uriConsumer, onComplete);
+                        mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,
+                                taskId, userId, topComponent, uriConsumer, onComplete);
                     } else {
-                        mScreenshotLegacy.handleImageAsScreenshot(
-                                screenshot, screenBounds, insets, taskId, uriConsumer);
+                        mScreenshotLegacy.handleImageAsScreenshot(screenshot, screenBounds, insets,
+                                taskId, userId, topComponent, uriConsumer);
                     }
                     break;
                 default:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 9925909..8a4fdc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -557,9 +557,9 @@
 
     private void focusExpandButtonIfNecessary() {
         if (mFocusOnVisibilityChange) {
-            NotificationHeaderView header = getVisibleNotificationHeader();
-            if (header != null) {
-                ImageView expandButton = header.getExpandButton();
+            NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
+            if (wrapper != null) {
+                View expandButton = wrapper.getExpandButton();
                 if (expandButton != null) {
                     expandButton.requestAccessibilityFocus();
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index daa4ffe..e9d8958 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -53,6 +53,7 @@
 import android.transition.TransitionSet;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
@@ -115,6 +116,7 @@
     private OnSnoozeClickListener mOnSnoozeClickListener;
     private OnSettingsClickListener mOnSettingsClickListener;
     private NotificationGuts mGutsContainer;
+    private OnConversationSettingsClickListener mOnConversationSettingsClickListener;
 
     @VisibleForTesting
     boolean mSkipPost = false;
@@ -164,6 +166,10 @@
 
     private OnClickListener mOnDone = v -> {
         mPressedApply = true;
+        // If the user selected Priority, maybe show the priority onboarding
+        if (mSelectedAction == ACTION_FAVORITE && shouldShowPriorityOnboarding()) {
+            showPriorityOnboarding();
+        }
         mGutsContainer.closeControls(v, true);
     };
 
@@ -175,6 +181,10 @@
         void onClick(View v, NotificationChannel channel, int appUid);
     }
 
+    public interface OnConversationSettingsClickListener {
+        void onClick();
+    }
+
     public interface OnAppSettingsClickListener {
         void onClick(View v, Intent intent);
     }
@@ -190,14 +200,6 @@
         }
 
         mSelectedAction = selectedAction;
-        onSelectedActionChanged();
-    }
-
-    private void onSelectedActionChanged() {
-        // If the user selected Priority, maybe show the priority onboarding
-        if (mSelectedAction == ACTION_FAVORITE && shouldShowPriorityOnboarding()) {
-            showPriorityOnboarding();
-        }
     }
 
     public void bindNotification(
@@ -216,7 +218,8 @@
             Provider<PriorityOnboardingDialogController.Builder> builderProvider,
             boolean isDeviceProvisioned,
             @Main Handler mainHandler,
-            @Background Handler bgHandler) {
+            @Background Handler bgHandler,
+            OnConversationSettingsClickListener onConversationSettingsClickListener) {
         mSelectedAction = -1;
         mINotificationManager = iNotificationManager;
         mVisualStabilityManager = visualStabilityManager;
@@ -231,6 +234,7 @@
         mDelegatePkg = mSbn.getOpPkg();
         mIsDeviceProvisioned = isDeviceProvisioned;
         mOnSnoozeClickListener = onSnoozeClickListener;
+        mOnConversationSettingsClickListener = onConversationSettingsClickListener;
         mIconFactory = conversationIconFactory;
         mUserContext = userContext;
         mBubbleMetadata = bubbleMetadata;
@@ -323,7 +327,6 @@
         ImageView image = findViewById(R.id.conversation_icon);
         image.setImageDrawable(mIconFactory.getConversationDrawable(
                 mShortcutInfo, mPackageName, mAppUid, important));
-
     }
 
     private void bindPackage() {
@@ -521,9 +524,9 @@
 
         boolean ignoreDnd = false;
         try {
-            ignoreDnd = (mINotificationManager
-                    .getConsolidatedNotificationPolicy().priorityConversationSenders
-                    & NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT) != 0;
+            ignoreDnd = mINotificationManager
+                    .getConsolidatedNotificationPolicy().priorityConversationSenders ==
+                    NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT;
         } catch (RemoteException e) {
             Log.e(TAG, "Could not check conversation senders", e);
         }
@@ -538,6 +541,8 @@
                 .setView(onboardingView)
                 .setIgnoresDnd(ignoreDnd)
                 .setShowsAsBubble(showAsBubble)
+                .setIcon(((ImageView) findViewById(R.id.conversation_icon)).getDrawable())
+                .setOnSettingsClick(mOnConversationSettingsClickListener)
                 .build();
 
         controller.init();
@@ -613,8 +618,7 @@
             try {
                 switch (mAction) {
                     case ACTION_FAVORITE:
-                        mChannelToUpdate.setImportantConversation(
-                                !mChannelToUpdate.isImportantConversation());
+                        mChannelToUpdate.setImportantConversation(true);
                         if (mChannelToUpdate.isImportantConversation()) {
                             mChannelToUpdate.setAllowBubbles(true);
                             if (mAppBubble == BUBBLE_PREFERENCE_NONE) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index a64dcdf..1074adc3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -216,6 +216,11 @@
         }
     }
 
+    private void startConversationSettingsActivity(int uid, ExpandableNotificationRow row) {
+        final Intent intent = new Intent(Settings.ACTION_CONVERSATION_SETTINGS);
+        mNotificationActivityStarter.startNotificationGutsIntent(intent, uid, row);
+    }
+
     private boolean bindGuts(final ExpandableNotificationRow row) {
         row.ensureGutsInflated();
         return bindGuts(row, mGutsMenuItem);
@@ -438,6 +443,12 @@
                     mListContainer.getSwipeActionHelper().snooze(sbn, hours);
                 };
 
+        final NotificationConversationInfo.OnConversationSettingsClickListener
+                onConversationSettingsListener =
+                () -> {
+                    startConversationSettingsActivity(sbn.getUid(), row);
+                };
+
         if (!userHandle.equals(UserHandle.ALL)
                 || mLockscreenUserManager.getCurrentUserId() == UserHandle.USER_SYSTEM) {
             onSettingsClick = (View v, NotificationChannel channel, int appUid) -> {
@@ -468,7 +479,8 @@
                 mBuilderProvider,
                 mDeviceProvisionedController.isDeviceProvisioned(),
                 mMainHandler,
-                mBgHandler);
+                mBgHandler,
+                onConversationSettingsListener);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
index 84bc181..f1fe54a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
@@ -241,7 +241,6 @@
         } catch (PackageManager.NameNotFoundException e) {
             mPkgIcon = mPm.getDefaultActivityIcon();
         }
-        ((TextView) findViewById(R.id.pkg_name)).setText(mAppName);
     }
 
     private void bindDelegate() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
index d1b4052..88c3258 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
@@ -21,19 +21,21 @@
 import android.graphics.Color
 import android.graphics.PixelFormat
 import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
+import android.text.SpannableStringBuilder
+import android.text.style.BulletSpan
 import android.view.Gravity
 import android.view.View
-import android.view.View.GONE
 import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
 import android.view.Window
 import android.view.WindowInsets.Type.statusBars
 import android.view.WindowManager
-import android.widget.LinearLayout
+import android.widget.ImageView
 import android.widget.TextView
 import com.android.systemui.Prefs
 import com.android.systemui.R
-import java.lang.IllegalStateException
+import com.android.systemui.statusbar.notification.row.NotificationConversationInfo.OnConversationSettingsClickListener
 import javax.inject.Inject
 
 /**
@@ -43,7 +45,9 @@
     val view: View,
     val context: Context,
     val ignoresDnd: Boolean,
-    val showsAsBubble: Boolean
+    val showsAsBubble: Boolean,
+    val icon : Drawable,
+    val onConversationSettingsClickListener : OnConversationSettingsClickListener
 ) {
 
     private lateinit var dialog: Dialog
@@ -62,11 +66,21 @@
         dialog.dismiss()
     }
 
+    private fun settings() {
+        // Log that the user has seen the onboarding
+        Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, true)
+        dialog.dismiss()
+        onConversationSettingsClickListener?.onClick()
+    }
+
     class Builder @Inject constructor() {
         private lateinit var view: View
         private lateinit var context: Context
         private var ignoresDnd = false
         private var showAsBubble = false
+        private lateinit var icon: Drawable
+        private lateinit var onConversationSettingsClickListener
+                : OnConversationSettingsClickListener
 
         fun setView(v: View): Builder {
             view = v
@@ -88,9 +102,20 @@
             return this
         }
 
+        fun setIcon(draw : Drawable) : Builder {
+            icon = draw
+            return this
+        }
+
+        fun setOnSettingsClick(onClick : OnConversationSettingsClickListener) : Builder {
+            onConversationSettingsClickListener = onClick
+            return this
+        }
+
         fun build(): PriorityOnboardingDialogController {
             val controller = PriorityOnboardingDialogController(
-                    view, context, ignoresDnd, showAsBubble)
+                    view, context, ignoresDnd, showAsBubble, icon,
+                    onConversationSettingsClickListener)
             return controller
         }
     }
@@ -113,13 +138,32 @@
                 done()
             }
 
-            if (!ignoresDnd) {
-                findViewById<LinearLayout>(R.id.ignore_dnd_tip).visibility = GONE
+            findViewById<TextView>(R.id.settings_button)?.setOnClickListener {
+                settings()
             }
 
-            if (!showsAsBubble) {
-                findViewById<LinearLayout>(R.id.floating_bubble_tip).visibility = GONE
+            findViewById<ImageView>(R.id.conversation_icon)?.setImageDrawable(icon)
+
+            val gapWidth = dialog.context.getResources().getDimensionPixelSize(
+                    R.dimen.conversation_onboarding_bullet_gap_width)
+            val description = SpannableStringBuilder()
+            description.append(context.getText(R.string.priority_onboarding_show_at_top_text),
+                    BulletSpan(gapWidth),  /* flags */0)
+            description.append(System.lineSeparator())
+            description.append(context.getText(R.string.priority_onboarding_show_avatar_text),
+                    BulletSpan(gapWidth),  /* flags */0)
+            if (showsAsBubble) {
+                description.append(System.lineSeparator())
+                description.append(context.getText(
+                        R.string.priority_onboarding_appear_as_bubble_text),
+                        BulletSpan(gapWidth),  /* flags */0)
             }
+            if (ignoresDnd) {
+                description.append(System.lineSeparator())
+                description.append(context.getText(R.string.priority_onboarding_ignores_dnd_text),
+                        BulletSpan(gapWidth),  /* flags */0)
+            }
+            findViewById<TextView>(R.id.behaviors).setText(description)
 
             window?.apply {
                 setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
@@ -129,7 +173,7 @@
 
                 attributes = attributes.apply {
                     format = PixelFormat.TRANSLUCENT
-                    title = ChannelEditorDialogController::class.java.simpleName
+                    title = PriorityOnboardingDialogController::class.java.simpleName
                     gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
                     fitInsetsTypes = attributes.fitInsetsTypes and statusBars().inv()
                     width = MATCH_PARENT
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
index 15499b8..fe70c81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
@@ -50,6 +50,7 @@
     private lateinit var conversationBadgeBg: View
     private lateinit var expandButton: View
     private lateinit var expandButtonContainer: View
+    private lateinit var expandButtonInnerContainer: View
     private lateinit var imageMessageContainer: ViewGroup
     private lateinit var messagingLinearLayout: MessagingLinearLayout
     private lateinit var conversationTitleView: View
@@ -69,6 +70,8 @@
             expandButton = requireViewById(com.android.internal.R.id.expand_button)
             expandButtonContainer =
                     requireViewById(com.android.internal.R.id.expand_button_container)
+            expandButtonInnerContainer =
+                    requireViewById(com.android.internal.R.id.expand_button_inner_container)
             importanceRing = requireViewById(com.android.internal.R.id.conversation_icon_badge_ring)
             appName = requireViewById(com.android.internal.R.id.app_name_text)
             conversationTitleView = requireViewById(com.android.internal.R.id.conversation_text)
@@ -134,6 +137,8 @@
         )
     }
 
+    override fun getExpandButton() = expandButtonInnerContainer
+
     override fun setShelfIconVisible(visible: Boolean) {
         if (conversationLayout.isImportantConversation) {
             if (conversationIconView.visibility != GONE) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index f8b7831..4c9cb20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -317,6 +317,11 @@
     }
 
     @Override
+    public View getExpandButton() {
+        return mExpandButton;
+    }
+
+    @Override
     public int getOriginalIconColor() {
         return mIcon.getOriginalIconColor();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 02e537d..30080e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -240,6 +240,13 @@
         return null;
     }
 
+    /**
+     * @return the expand button if it exists
+     */
+    public @Nullable View getExpandButton() {
+        return null;
+    }
+
     public int getOriginalIconColor() {
         return Notification.COLOR_INVALID;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 46c873d..4337e20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -40,6 +40,7 @@
 import com.android.systemui.statusbar.phone.ReverseLinearLayout.ReverseRelativeLayout;
 import com.android.systemui.statusbar.policy.KeyButtonView;
 
+import java.io.PrintWriter;
 import java.util.Objects;
 
 public class NavigationBarInflaterView extends FrameLayout
@@ -469,4 +470,10 @@
     private static float convertDpToPx(Context context, float dp) {
         return dp * context.getResources().getDisplayMetrics().density;
     }
+
+    public void dump(PrintWriter pw) {
+        pw.println("NavigationBarInflaterView {");
+        pw.println("      mCurrentLayout: " + mCurrentLayout);
+        pw.println("    }");
+    }
 }
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 2978772..6b37ac3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -1198,6 +1198,9 @@
 
         pw.println("    }");
 
+        if (mNavigationInflaterView != null) {
+            mNavigationInflaterView.dump(pw);
+        }
         mContextualButtonGroup.dump(pw);
         mRecentsOnboarding.dump(pw);
         mRegionSamplingHelper.dump(pw);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index f58cce5..76c51d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -572,6 +572,9 @@
                     .setInterpolator(Interpolators.LINEAR)
                     .setDuration(AOD_ICONS_APPEAR_DURATION)
                     .start();
+        } else {
+            mAodIcons.setAlpha(1.0f);
+            mAodIcons.setTranslationY(0);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index b4de3cd..18a7add 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -640,8 +640,7 @@
                         + " dataState=" + state.getDataRegistrationState());
             }
             mServiceState = state;
-            // onDisplayInfoChanged is invoked directly after onServiceStateChanged, so not calling
-            // updateTelephony() to prevent icon flickering in case of overrides.
+            updateTelephony();
         }
 
         @Override
@@ -651,12 +650,6 @@
                         + " type=" + networkType);
             }
             mDataState = state;
-            if (networkType != mTelephonyDisplayInfo.getNetworkType()) {
-                Log.d(mTag, "onDataConnectionStateChanged:"
-                        + " network type change and reset displayInfo. type=" + networkType);
-                mTelephonyDisplayInfo = new TelephonyDisplayInfo(networkType,
-                        TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE);
-            }
             updateTelephony();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java b/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
index 6c3538c..a31ea7c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
+++ b/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
@@ -40,7 +40,7 @@
 
         setBackground(res.getDrawable(R.drawable.dismiss_circle_background));
 
-        mIconView.setImageDrawable(res.getDrawable(R.drawable.dismiss_target_x));
+        mIconView.setImageDrawable(res.getDrawable(R.drawable.ic_close_white));
         addView(mIconView);
 
         setViewSizes();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index b018b59..ed4f8b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.notification.row;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
@@ -30,11 +29,13 @@
 import android.util.ArraySet;
 import android.view.NotificationHeaderView;
 import android.view.View;
+import android.view.ViewPropertyAnimator;
 
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.widget.NotificationExpandButton;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Before;
@@ -98,4 +99,42 @@
         verify(mockExpanded, times(1)).setVisibility(View.VISIBLE);
         verify(mockHeadsUp, times(1)).setVisibility(View.VISIBLE);
     }
+
+    @Test
+    @UiThreadTest
+    public void testExpandButtonFocusIsCalled() {
+        View mockContractedEB = mock(NotificationExpandButton.class);
+        View mockContracted = mock(NotificationHeaderView.class);
+        when(mockContracted.animate()).thenReturn(mock(ViewPropertyAnimator.class));
+        when(mockContracted.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
+                mockContractedEB);
+
+        View mockExpandedEB = mock(NotificationExpandButton.class);
+        View mockExpanded = mock(NotificationHeaderView.class);
+        when(mockExpanded.animate()).thenReturn(mock(ViewPropertyAnimator.class));
+        when(mockExpanded.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
+                mockExpandedEB);
+
+        View mockHeadsUpEB = mock(NotificationExpandButton.class);
+        View mockHeadsUp = mock(NotificationHeaderView.class);
+        when(mockHeadsUp.animate()).thenReturn(mock(ViewPropertyAnimator.class));
+        when(mockHeadsUp.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
+                mockHeadsUpEB);
+
+        // Set up all 3 child forms
+        mView.setContractedChild(mockContracted);
+        mView.setExpandedChild(mockExpanded);
+        mView.setHeadsUpChild(mockHeadsUp);
+
+        // This is required to call requestAccessibilityFocus()
+        mView.setFocusOnVisibilityChange();
+
+        // The following will initialize the view and switch from not visible to expanded.
+        // (heads-up is actually an alternate form of contracted, hence this enters expanded state)
+        mView.setHeadsUp(true);
+
+        verify(mockContractedEB, times(0)).requestAccessibilityFocus();
+        verify(mockExpandedEB, times(1)).requestAccessibilityFocus();
+        verify(mockHeadsUpEB, times(0)).requestAccessibilityFocus();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index b1f67ce..4122cf5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -256,7 +256,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
         final ImageView view = mNotificationInfo.findViewById(R.id.conversation_icon);
         assertEquals(mIconDrawable, view.getDrawable());
     }
@@ -280,7 +280,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
         final TextView textView = mNotificationInfo.findViewById(R.id.pkg_name);
         assertTrue(textView.getText().toString().contains("App Name"));
         assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
@@ -331,7 +331,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
         final TextView textView = mNotificationInfo.findViewById(R.id.group_name);
         assertTrue(textView.getText().toString().contains(group.getName()));
         assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
@@ -356,7 +356,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
         final TextView textView = mNotificationInfo.findViewById(R.id.group_name);
         assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
         assertEquals(GONE, textView.getVisibility());
@@ -380,7 +380,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
         final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
         assertEquals(GONE, nameView.getVisibility());
     }
@@ -415,7 +415,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
         final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
         assertEquals(VISIBLE, nameView.getVisibility());
         assertTrue(nameView.getText().toString().contains("Proxied"));
@@ -443,7 +443,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
 
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         settingsButton.performClick();
@@ -469,7 +469,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertTrue(settingsButton.getVisibility() != View.VISIBLE);
     }
@@ -496,7 +496,7 @@
                 mBuilderProvider,
                 false,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertTrue(settingsButton.getVisibility() != View.VISIBLE);
     }
@@ -521,7 +521,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
         View view = mNotificationInfo.findViewById(R.id.silence);
         assertThat(view.isSelected()).isTrue();
     }
@@ -549,7 +549,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
         View view = mNotificationInfo.findViewById(R.id.default_behavior);
         assertThat(view.isSelected()).isTrue();
         assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
@@ -580,7 +580,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
         View view = mNotificationInfo.findViewById(R.id.default_behavior);
         assertThat(view.isSelected()).isTrue();
         assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
@@ -610,7 +610,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
 
         View fave = mNotificationInfo.findViewById(R.id.priority);
         fave.performClick();
@@ -654,7 +654,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
 
         mNotificationInfo.findViewById(R.id.default_behavior).performClick();
         mTestableLooper.processAllMessages();
@@ -697,7 +697,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
 
         View silence = mNotificationInfo.findViewById(R.id.silence);
 
@@ -741,7 +741,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
 
         View fave = mNotificationInfo.findViewById(R.id.priority);
         fave.performClick();
@@ -778,7 +778,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
 
         View fave = mNotificationInfo.findViewById(R.id.priority);
         fave.performClick();
@@ -793,6 +793,45 @@
     }
 
     @Test
+    public void testFavorite_thenDefaultThenFavorite_andSave_nothingChanged() throws Exception {
+        mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
+        mConversationChannel.setImportance(IMPORTANCE_HIGH);
+        mConversationChannel.setImportantConversation(true);
+
+        mNotificationInfo.bindNotification(
+                mShortcutManager,
+                mMockPackageManager,
+                mMockINotificationManager,
+                mVisualStabilityManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mEntry,
+                mBubbleMetadata,
+                null,
+                null,
+                mIconFactory,
+                mContext,
+                mBuilderProvider,
+                true,
+                mTestHandler,
+                mTestHandler, null);
+
+        View fave = mNotificationInfo.findViewById(R.id.priority);
+        fave.performClick();
+        mNotificationInfo.findViewById(R.id.default_behavior).performClick();
+        fave.performClick();
+        mNotificationInfo.findViewById(R.id.done).performClick();
+        mTestableLooper.processAllMessages();
+
+        ArgumentCaptor<NotificationChannel> captor =
+                ArgumentCaptor.forClass(NotificationChannel.class);
+        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+                anyString(), anyInt(), captor.capture());
+        assertEquals(IMPORTANCE_HIGH, captor.getValue().getImportance());
+        assertTrue(captor.getValue().isImportantConversation());
+    }
+
+    @Test
     public void testDefault_andSave() throws Exception {
         mConversationChannel.setAllowBubbles(true);
         mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
@@ -813,7 +852,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
 
         mNotificationInfo.findViewById(R.id.default_behavior).performClick();
         mNotificationInfo.findViewById(R.id.done).performClick();
@@ -849,7 +888,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
 
         mNotificationInfo.findViewById(R.id.default_behavior).performClick();
         mNotificationInfo.findViewById(R.id.done).performClick();
@@ -885,7 +924,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
 
         mNotificationInfo.findViewById(R.id.default_behavior).performClick();
         mNotificationInfo.findViewById(R.id.done).performClick();
@@ -920,7 +959,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
 
         View silence = mNotificationInfo.findViewById(R.id.silence);
         silence.performClick();
@@ -954,7 +993,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
 
         verify(mMockINotificationManager, times(1)).createConversationNotificationChannelForPackage(
                 anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID));
@@ -979,7 +1018,7 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
 
         verify(mMockINotificationManager, never()).createConversationNotificationChannelForPackage(
                 anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID));
@@ -1014,10 +1053,14 @@
                 () -> b,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
 
         // WHEN user clicks "priority"
         mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
+        verify(controller, never()).show();
+
+        // and then done
+        mNotificationInfo.findViewById(R.id.done).performClick();
 
         // THEN the user is presented with the priority onboarding screen
         verify(controller, atLeastOnce()).show();
@@ -1050,7 +1093,7 @@
                 () -> b,
                 true,
                 mTestHandler,
-                mTestHandler);
+                mTestHandler, null);
 
         // WHEN user clicks "priority"
         mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
index e56ef5b..f327967 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
@@ -161,25 +161,6 @@
     }
 
     @Test
-    public void testBindNotification_SetsTextApplicationName() throws Exception {
-        when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
-        mInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mChannelEditorDialogController,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                true,
-                false);
-        final TextView textView = mInfo.findViewById(R.id.pkg_name);
-        assertTrue(textView.getText().toString().contains("App Name"));
-        assertEquals(VISIBLE, mInfo.findViewById(R.id.header).getVisibility());
-    }
-
-    @Test
     public void testBindNotification_SetsName() {
         mInfo.bindNotification(
                 mMockPackageManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
index be43e19..177e845 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.testing.AndroidTestingRunner;
@@ -56,6 +57,8 @@
     @Mock
     NotificationMediaManager mNotificationMediaManager;
     @Mock
+    NotificationIconContainer mNotificationIconContainer;
+    @Mock
     DozeParameters mDozeParameters;
     @Mock
     NotificationShadeWindowView mNotificationShadeWindowView;
@@ -67,7 +70,7 @@
 
         when(mStatusBar.getNotificationShadeWindowView()).thenReturn(mNotificationShadeWindowView);
         when(mNotificationShadeWindowView.findViewById(anyInt())).thenReturn(
-                        mock(NotificationIconContainer.class));
+                mNotificationIconContainer);
 
         mController = new NotificationIconAreaController(mContext, mStatusBar,
                 mStatusBarStateController, mWakeUpCoordinator, mKeyguardBypassController,
@@ -87,4 +90,12 @@
 
         assertTrue(mController.shouldShouldLowPriorityIcons());
     }
+
+    @Test
+    public void testAppearResetsTranslation() {
+        when(mDozeParameters.shouldControlScreenOff()).thenReturn(false);
+        mController.appearAodIcons();
+        verify(mNotificationIconContainer).setTranslationY(0);
+        verify(mNotificationIconContainer).setAlpha(1.0f);
+    }
 }
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index f08429b..3fd9ee9 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -730,12 +730,7 @@
             final String upstreamIface = v6only.getInterfaceName();
 
             params = new RaParams();
-            // When BPF offload is enabled, we advertise an mtu lower by 16, which is the closest
-            // multiple of 8 >= 14, the ethernet header size. This makes kernel ebpf tethering
-            // offload happy. This hack should be reverted once we have the kernel fixed up.
-            // Note: this will automatically clamp to at least 1280 (ipv6 minimum mtu)
-            // see RouterAdvertisementDaemon.java putMtu()
-            params.mtu = mUsingBpfOffload ? v6only.getMtu() - 16 : v6only.getMtu();
+            params.mtu = v6only.getMtu();
             params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
 
             if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface, ttlAdjustment);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
index e2330ca6..0ec8654 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
@@ -75,9 +75,7 @@
             @NonNull Consumer<InlineSuggestionsRequest> requestConsumer, @NonNull Bundle uiExtras) {
         // TODO(b/151123764): rename the method to better reflect what it does.
         if (mSession != null) {
-            // Send an empty response to IME and destroy the existing session.
-            mSession.onInlineSuggestionsResponseLocked(
-                    InlineFillUi.emptyUi(mSession.getAutofillIdLocked()));
+            // Destroy the existing session.
             mSession.destroySessionLocked();
             mInlineFillUi = null;
         }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1634f6e..0ab5718 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1374,10 +1374,9 @@
         if (nri == null || net == null || !LOGD_BLOCKED_NETWORKINFO) {
             return;
         }
-        String action = blocked ? "BLOCKED" : "UNBLOCKED";
-        log(String.format("Blocked status changed to %s for %d(%d) on netId %d", blocked,
-                nri.mUid, nri.request.requestId, net.netId));
-        mNetworkInfoBlockingLogs.log(action + " " + nri.mUid);
+        final String action = blocked ? "BLOCKED" : "UNBLOCKED";
+        mNetworkInfoBlockingLogs.log(String.format(
+                "%s %d(%d) on netId %d", action, nri.mUid, nri.request.requestId, net.netId));
     }
 
     /**
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index efd3c3e..27d9ba0 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1908,8 +1908,11 @@
     /** @see AudioManager#adjustVolume(int, int) */
     public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
             String callingPackage, String caller) {
+        boolean hasModifyAudioSettings =
+                mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
+                == PackageManager.PERMISSION_GRANTED;
         adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
-                caller, Binder.getCallingUid(), hasModifyAudioSettings(), VOL_ADJUST_NORMAL);
+                caller, Binder.getCallingUid(), hasModifyAudioSettings, VOL_ADJUST_NORMAL);
     }
 
     private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
@@ -2014,10 +2017,13 @@
                     + "CHANGE_ACCESSIBILITY_VOLUME / callingPackage=" + callingPackage);
             return;
         }
+        final boolean hasModifyAudioSettings =
+                mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
+                        == PackageManager.PERMISSION_GRANTED;
         sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_STREAM_VOL, streamType,
                 direction/*val1*/, flags/*val2*/, callingPackage));
         adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
-                Binder.getCallingUid(), hasModifyAudioSettings(), VOL_ADJUST_NORMAL);
+                Binder.getCallingUid(), hasModifyAudioSettings, VOL_ADJUST_NORMAL);
     }
 
     protected void adjustStreamVolume(int streamType, int direction, int flags,
@@ -2528,10 +2534,13 @@
                     + " MODIFY_AUDIO_ROUTING  callingPackage=" + callingPackage);
             return;
         }
+        final boolean hasModifyAudioSettings =
+                mContext.checkCallingOrSelfPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
+                        == PackageManager.PERMISSION_GRANTED;
         sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType,
                 index/*val1*/, flags/*val2*/, callingPackage));
         setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
-                Binder.getCallingUid(), hasModifyAudioSettings());
+                Binder.getCallingUid(), hasModifyAudioSettings);
     }
 
     private boolean canChangeAccessibilityVolume() {
@@ -3197,7 +3206,8 @@
         ensureValidStreamType(streamType);
         final boolean isPrivileged =
                 Binder.getCallingUid() == Process.SYSTEM_UID
-                 || (hasModifyAudioSettings())
+                 || (mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
+                        == PackageManager.PERMISSION_GRANTED)
                  || (mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
                         == PackageManager.PERMISSION_GRANTED);
         return (mStreamStates[streamType].getMinIndex(isPrivileged) + 5) / 10;
@@ -4755,18 +4765,9 @@
         handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
     }
 
-    private boolean hasModifyAudioSettings() {
-        return mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
-                == PackageManager.PERMISSION_GRANTED;
-    }
-
-    private boolean hasModifyAudioSettings(int pid, int uid) {
-        return mContext.checkPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS, pid, uid)
-                == PackageManager.PERMISSION_GRANTED;
-    }
-
     boolean checkAudioSettingsPermission(String method) {
-        if (hasModifyAudioSettings()) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
+                == PackageManager.PERMISSION_GRANTED) {
             return true;
         }
         String msg = "Audio Settings Permission Denial: " + method + " from pid="
@@ -7688,10 +7689,13 @@
         @Override
         public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
                 String callingPackage, int uid, int pid) {
+            final boolean hasModifyAudioSettings =
+                    mContext.checkPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS, pid, uid)
+                    == PackageManager.PERMISSION_GRANTED;
             // direction and stream type swap here because the public
             // adjustSuggested has a different order than the other methods.
             adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
-                    callingPackage, uid, hasModifyAudioSettings(pid, uid), VOL_ADJUST_NORMAL);
+                    callingPackage, uid, hasModifyAudioSettings, VOL_ADJUST_NORMAL);
         }
 
         @Override
@@ -7702,15 +7706,21 @@
                         direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage)
                         .append(" uid:").append(uid).toString()));
             }
+            final boolean hasModifyAudioSettings =
+                    mContext.checkPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS, pid, uid)
+                            == PackageManager.PERMISSION_GRANTED;
             adjustStreamVolume(streamType, direction, flags, callingPackage,
-                    callingPackage, uid, hasModifyAudioSettings(pid, uid), VOL_ADJUST_NORMAL);
+                    callingPackage, uid, hasModifyAudioSettings, VOL_ADJUST_NORMAL);
         }
 
         @Override
         public void setStreamVolumeForUid(int streamType, int direction, int flags,
                 String callingPackage, int uid, int pid) {
+            final boolean hasModifyAudioSettings =
+                    mContext.checkPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS, pid, uid)
+                            == PackageManager.PERMISSION_GRANTED;
             setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid,
-                    hasModifyAudioSettings(pid, uid));
+                    hasModifyAudioSettings);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 9de95ab..b9669c74 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -40,6 +40,7 @@
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiHotplugEvent;
 import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.hdmi.IHdmiControlService;
 import android.hardware.hdmi.IHdmiControlStatusChangeListener;
@@ -63,6 +64,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.PowerManager;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
@@ -268,6 +270,11 @@
     private final ArrayList<HdmiControlStatusChangeListenerRecord>
             mHdmiControlStatusChangeListenerRecords = new ArrayList<>();
 
+    // List of records for HDMI control volume control status change listener for death monitoring.
+    @GuardedBy("mLock")
+    private final RemoteCallbackList<IHdmiCecVolumeControlFeatureListener>
+            mHdmiCecVolumeControlFeatureListenerRecords = new RemoteCallbackList<>();
+
     // List of records for hotplug event listener to handle the the caller killed in action.
     @GuardedBy("mLock")
     private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords =
@@ -1814,6 +1821,21 @@
         }
 
         @Override
+        public void addHdmiCecVolumeControlFeatureListener(
+                final IHdmiCecVolumeControlFeatureListener listener) {
+            enforceAccessPermission();
+            HdmiControlService.this.addHdmiCecVolumeControlFeatureListener(listener);
+        }
+
+        @Override
+        public void removeHdmiCecVolumeControlFeatureListener(
+                final IHdmiCecVolumeControlFeatureListener listener) {
+            enforceAccessPermission();
+            HdmiControlService.this.removeHdmiControlVolumeControlStatusChangeListener(listener);
+        }
+
+
+        @Override
         public void addHotplugEventListener(final IHdmiHotplugEventListener listener) {
             enforceAccessPermission();
             HdmiControlService.this.addHotplugEventListener(listener);
@@ -2409,6 +2431,33 @@
         }
     }
 
+    @VisibleForTesting
+    void addHdmiCecVolumeControlFeatureListener(
+            final IHdmiCecVolumeControlFeatureListener listener) {
+        mHdmiCecVolumeControlFeatureListenerRecords.register(listener);
+
+        runOnServiceThread(new Runnable() {
+            @Override
+            public void run() {
+                // Return the current status of mHdmiCecVolumeControlEnabled;
+                synchronized (mLock) {
+                    try {
+                        listener.onHdmiCecVolumeControlFeature(mHdmiCecVolumeControlEnabled);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Failed to report HdmiControlVolumeControlStatusChange: "
+                                + mHdmiCecVolumeControlEnabled, e);
+                    }
+                }
+            }
+        });
+    }
+
+    @VisibleForTesting
+    void removeHdmiControlVolumeControlStatusChangeListener(
+            final IHdmiCecVolumeControlFeatureListener listener) {
+        mHdmiCecVolumeControlFeatureListenerRecords.unregister(listener);
+    }
+
     private void addHotplugEventListener(final IHdmiHotplugEventListener listener) {
         final HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener);
         try {
@@ -2682,6 +2731,19 @@
         }
     }
 
+    private void announceHdmiCecVolumeControlFeatureChange(boolean isEnabled) {
+        assertRunOnServiceThread();
+        mHdmiCecVolumeControlFeatureListenerRecords.broadcast(listener -> {
+            try {
+                listener.onHdmiCecVolumeControlFeature(isEnabled);
+            } catch (RemoteException e) {
+                Slog.e(TAG,
+                        "Failed to report HdmiControlVolumeControlStatusChange: "
+                                + isEnabled);
+            }
+        });
+    }
+
     public HdmiCecLocalDeviceTv tv() {
         return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV);
     }
@@ -3026,6 +3088,7 @@
                         isHdmiCecVolumeControlEnabled);
             }
         }
+        announceHdmiCecVolumeControlFeatureChange(isHdmiCecVolumeControlEnabled);
     }
 
     boolean isHdmiCecVolumeControlEnabled() {
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index ccbe96f..067bdcb 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -28,6 +28,9 @@
 
 import static com.android.server.location.CallerIdentity.PERMISSION_COARSE;
 import static com.android.server.location.CallerIdentity.PERMISSION_FINE;
+import static com.android.server.location.UserInfoHelper.UserListener.CURRENT_USER_CHANGED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STARTED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STOPPED;
 
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 
@@ -64,6 +67,7 @@
 import android.location.LocationRequest;
 import android.location.LocationTime;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.Handler;
@@ -101,7 +105,7 @@
 import com.android.server.location.CallerIdentity.PermissionLevel;
 import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
 import com.android.server.location.LocationRequestStatistics.PackageStatistics;
-import com.android.server.location.UserInfoHelper.UserListener;
+import com.android.server.location.UserInfoHelper.UserListener.UserChange;
 import com.android.server.location.gnss.GnssManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
@@ -132,11 +136,13 @@
      */
     public static class Lifecycle extends SystemService {
 
+        private final UserInfoHelper mUserInfoHelper;
         private final LocationManagerService mService;
 
         public Lifecycle(Context context) {
             super(context);
-            mService = new LocationManagerService(context);
+            mUserInfoHelper = new SystemUserInfoHelper(context);
+            mService = new LocationManagerService(context, mUserInfoHelper);
         }
 
         @Override
@@ -161,6 +167,29 @@
                 mService.onSystemThirdPartyAppsCanStart();
             }
         }
+
+        @Override
+        public void onUserStarting(TargetUser user) {
+            mUserInfoHelper.dispatchOnUserStarted(user.getUserIdentifier());
+        }
+
+        @Override
+        public void onUserSwitching(TargetUser from, TargetUser to) {
+            mUserInfoHelper.dispatchOnCurrentUserChanged(from.getUserIdentifier(),
+                    to.getUserIdentifier());
+        }
+
+        @Override
+        public void onUserStopped(TargetUser user) {
+            mUserInfoHelper.dispatchOnUserStopped(user.getUserIdentifier());
+        }
+
+        private static class SystemUserInfoHelper extends UserInfoHelper {
+
+            SystemUserInfoHelper(Context context) {
+                super(context);
+            }
+        }
     }
 
     public static final String TAG = "LocationManagerService";
@@ -232,7 +261,7 @@
     @PowerManager.LocationPowerSaveMode
     private int mBatterySaverMode;
 
-    private LocationManagerService(Context context) {
+    private LocationManagerService(Context context, UserInfoHelper userInfoHelper) {
         mContext = context.createAttributionContext(ATTRIBUTION_TAG);
         mHandler = FgThread.getHandler();
         mLocalService = new LocalService();
@@ -240,7 +269,7 @@
         LocalServices.addService(LocationManagerInternal.class, mLocalService);
 
         mAppOpsHelper = new AppOpsHelper(mContext);
-        mUserInfoHelper = new UserInfoHelper(mContext);
+        mUserInfoHelper = userInfoHelper;
         mSettingsHelper = new SettingsHelper(mContext, mHandler);
         mAppForegroundHelper = new AppForegroundHelper(mContext);
         mLocationUsageLogger = new LocationUsageLogger();
@@ -342,7 +371,7 @@
             // initialize the current users. we would get the user started notifications for these
             // users eventually anyways, but this takes care of it as early as possible.
             for (int userId: mUserInfoHelper.getCurrentUserIds()) {
-                onUserChanged(userId, UserListener.USER_STARTED);
+                onUserChanged(userId, USER_STARTED);
             }
         }
     }
@@ -596,32 +625,23 @@
         }
     }
 
-    private void onUserChanged(@UserIdInt int userId, @UserListener.UserChange int change) {
+    private void onUserChanged(@UserIdInt int userId, @UserChange int change) {
         switch (change) {
-            case UserListener.USER_SWITCHED:
-                if (D) {
-                    Log.d(TAG, "user " + userId + " current status changed");
-                }
+            case CURRENT_USER_CHANGED:
                 synchronized (mLock) {
                     for (LocationProviderManager manager : mProviderManagers) {
                         manager.onEnabledChangedLocked(userId);
                     }
                 }
                 break;
-            case UserListener.USER_STARTED:
-                if (D) {
-                    Log.d(TAG, "user " + userId + " started");
-                }
+            case USER_STARTED:
                 synchronized (mLock) {
                     for (LocationProviderManager manager : mProviderManagers) {
                         manager.onUserStarted(userId);
                     }
                 }
                 break;
-            case UserListener.USER_STOPPED:
-                if (D) {
-                    Log.d(TAG, "user " + userId + " stopped");
-                }
+            case USER_STOPPED:
                 synchronized (mLock) {
                     for (LocationProviderManager manager : mProviderManagers) {
                         manager.onUserStopped(userId);
@@ -957,10 +977,22 @@
                 pw.increaseIndent();
 
                 // for now we only dump for the parent user
-                int userId = mUserInfoHelper.getCurrentUserIds()[0];
-                pw.println("last location=" + mLastLocation.get(userId));
-                pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
-                pw.println("enabled=" + isEnabled(userId));
+                int[] userIds = mUserInfoHelper.getCurrentUserIds();
+                if (userIds.length == 1) {
+                    int userId = userIds[0];
+                    pw.println("last location=" + mLastLocation.get(userId));
+                    pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
+                    pw.println("enabled=" + isEnabled(userId));
+                } else {
+                    for (int userId : userIds) {
+                        pw.println("user " + userId + ":");
+                        pw.increaseIndent();
+                        pw.println("last location=" + mLastLocation.get(userId));
+                        pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
+                        pw.println("enabled=" + isEnabled(userId));
+                        pw.decreaseIndent();
+                    }
+                }
             }
 
             mProvider.dump(fd, pw, args);
@@ -1666,6 +1698,9 @@
          * Note: must be constructed with lock held.
          */
         private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
+            if (Build.IS_DEBUGGABLE) {
+                Preconditions.checkState(Thread.holdsLock(mLock));
+            }
             mExpirationRealtimeMs = request.getExpirationRealtimeMs(SystemClock.elapsedRealtime());
             mProvider = provider;
             mRealRequest = request;
@@ -1703,6 +1738,10 @@
          * Method to be called when a record will no longer be used.
          */
         private void disposeLocked(boolean removeReceiver) {
+            if (Build.IS_DEBUGGABLE) {
+                Preconditions.checkState(Thread.holdsLock(mLock));
+            }
+
             CallerIdentity identity = mReceiver.mCallerIdentity;
             mRequestStatistics.stopRequesting(identity.packageName, identity.featureId, mProvider);
 
diff --git a/services/core/java/com/android/server/location/UserInfoHelper.java b/services/core/java/com/android/server/location/UserInfoHelper.java
index a3dcc40..53bff8e 100644
--- a/services/core/java/com/android/server/location/UserInfoHelper.java
+++ b/services/core/java/com/android/server/location/UserInfoHelper.java
@@ -20,48 +20,48 @@
 
 import static com.android.server.location.LocationManagerService.D;
 import static com.android.server.location.LocationManagerService.TAG;
+import static com.android.server.location.UserInfoHelper.UserListener.CURRENT_USER_CHANGED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STARTED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STOPPED;
 
+import android.annotation.CallSuper;
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
-import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
+import android.app.ActivityManagerInternal;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.os.Binder;
-import android.os.Build;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
-import com.android.server.FgThread;
+import com.android.server.LocalServices;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
+import java.util.Objects;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * Provides accessors and listeners for all user info.
  */
-public class UserInfoHelper {
+public abstract class UserInfoHelper {
 
     /**
      * Listener for current user changes.
      */
     public interface UserListener {
 
-        int USER_SWITCHED = 1;
+        int CURRENT_USER_CHANGED = 1;
         int USER_STARTED = 2;
         int USER_STOPPED = 3;
 
-        @IntDef({USER_SWITCHED, USER_STARTED, USER_STOPPED})
+        @IntDef({CURRENT_USER_CHANGED, USER_STARTED, USER_STOPPED})
         @Retention(RetentionPolicy.SOURCE)
         @interface UserChange {}
 
@@ -75,143 +75,101 @@
     private final CopyOnWriteArrayList<UserListener> mListeners;
 
     @GuardedBy("this")
+    @Nullable private ActivityManagerInternal mActivityManagerInternal;
+    @GuardedBy("this")
     @Nullable private UserManager mUserManager;
 
-    @UserIdInt private volatile int mCurrentUserId;
-
-    @GuardedBy("this")
-    @UserIdInt private int mCachedParentUserId;
-    @GuardedBy("this")
-    private int[] mCachedProfileUserIds;
-
     public UserInfoHelper(Context context) {
         mContext = context;
         mListeners = new CopyOnWriteArrayList<>();
-
-        mCurrentUserId = UserHandle.USER_NULL;
-        mCachedParentUserId = UserHandle.USER_NULL;
-        mCachedProfileUserIds = new int[]{UserHandle.USER_NULL};
     }
 
     /** Called when system is ready. */
+    @CallSuper
     public synchronized void onSystemReady() {
-        if (mUserManager != null) {
+        if (mActivityManagerInternal != null) {
             return;
         }
 
+        mActivityManagerInternal = Objects.requireNonNull(
+                LocalServices.getService(ActivityManagerInternal.class));
         mUserManager = mContext.getSystemService(UserManager.class);
-
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
-        intentFilter.addAction(Intent.ACTION_USER_STARTED);
-        intentFilter.addAction(Intent.ACTION_USER_STOPPED);
-        intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
-        intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
-
-        mContext.registerReceiverAsUser(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
-                if (action == null) {
-                    return;
-                }
-                int userId;
-                switch (action) {
-                    case Intent.ACTION_USER_SWITCHED:
-                        userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-                        if (userId != UserHandle.USER_NULL) {
-                            onCurrentUserChanged(userId);
-                        }
-                        break;
-                    case Intent.ACTION_USER_STARTED:
-                        userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-                        if (userId != UserHandle.USER_NULL) {
-                            onUserStarted(userId);
-                        }
-                        break;
-                    case Intent.ACTION_USER_STOPPED:
-                        userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-                        if (userId != UserHandle.USER_NULL) {
-                            onUserStopped(userId);
-                        }
-                        break;
-                    case Intent.ACTION_MANAGED_PROFILE_ADDED:
-                    case Intent.ACTION_MANAGED_PROFILE_REMOVED:
-                        onUserProfilesChanged();
-                        break;
-                }
-            }
-        }, UserHandle.ALL, intentFilter, null, FgThread.getHandler());
-
-        mCurrentUserId = ActivityManager.getCurrentUser();
     }
 
     /**
      * Adds a listener for user changed events. Callbacks occur on an unspecified thread.
      */
-    public void addListener(UserListener listener) {
+    public final void addListener(UserListener listener) {
         mListeners.add(listener);
     }
 
     /**
      * Removes a listener for user changed events.
      */
-    public void removeListener(UserListener listener) {
+    public final void removeListener(UserListener listener) {
         mListeners.remove(listener);
     }
 
-    private void onCurrentUserChanged(@UserIdInt int newUserId) {
-        if (newUserId == mCurrentUserId) {
-            return;
-        }
-
-        if (D) {
-            Log.d(TAG, "current user switched from u" + mCurrentUserId + " to u" + newUserId);
-        }
-
-        int oldUserId = mCurrentUserId;
-        mCurrentUserId = newUserId;
-
-        onUserChanged(oldUserId, UserListener.USER_SWITCHED);
-        onUserChanged(newUserId, UserListener.USER_SWITCHED);
-    }
-
-    private void onUserStarted(@UserIdInt int userId) {
+    protected void dispatchOnUserStarted(@UserIdInt int userId) {
         if (D) {
             Log.d(TAG, "u" + userId + " started");
         }
 
-        onUserChanged(userId, UserListener.USER_STARTED);
+        for (UserListener listener : mListeners) {
+            listener.onUserChanged(userId, USER_STARTED);
+        }
     }
 
-    private void onUserStopped(@UserIdInt int userId) {
+    protected void dispatchOnUserStopped(@UserIdInt int userId) {
         if (D) {
             Log.d(TAG, "u" + userId + " stopped");
         }
 
-        onUserChanged(userId, UserListener.USER_STOPPED);
-    }
-
-    private void onUserChanged(@UserIdInt int userId, @UserListener.UserChange int change) {
         for (UserListener listener : mListeners) {
-            listener.onUserChanged(userId, change);
+            listener.onUserChanged(userId, USER_STOPPED);
         }
     }
 
-    private synchronized void onUserProfilesChanged() {
-        // this intent is only sent to the current user
-        if (mCachedParentUserId == mCurrentUserId) {
-            mCachedParentUserId = UserHandle.USER_NULL;
-            mCachedProfileUserIds = new int[]{UserHandle.USER_NULL};
+    protected void dispatchOnCurrentUserChanged(@UserIdInt int fromUserId,
+            @UserIdInt int toUserId) {
+        int[] fromUserIds = getProfileIds(fromUserId);
+        int[] toUserIds = getProfileIds(toUserId);
+        if (D) {
+            Log.d(TAG, "current user changed from u" + Arrays.toString(fromUserIds) + " to u"
+                    + Arrays.toString(toUserIds));
+        }
+
+        for (UserListener listener : mListeners) {
+            for (int userId : fromUserIds) {
+                listener.onUserChanged(userId, CURRENT_USER_CHANGED);
+            }
+        }
+
+        for (UserListener listener : mListeners) {
+            for (int userId : toUserIds) {
+                listener.onUserChanged(userId, CURRENT_USER_CHANGED);
+            }
         }
     }
 
     /**
      * Returns an array of current user ids. This will always include the current user, and will
-     * also include any profiles of the current user.
+     * also include any profiles of the current user. The caller must never mutate the returned
+     * array.
      */
     public int[] getCurrentUserIds() {
-        return getProfileUserIdsForParentUser(mCurrentUserId);
+        synchronized (this) {
+            if (mActivityManagerInternal == null) {
+                return new int[] {};
+            }
+        }
+
+        long identity = Binder.clearCallingIdentity();
+        try {
+            return mActivityManagerInternal.getCurrentProfileIds();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
     /**
@@ -219,54 +177,47 @@
      * user.
      */
     public boolean isCurrentUserId(@UserIdInt int userId) {
-        int currentUserId = mCurrentUserId;
-        return userId == currentUserId || ArrayUtils.contains(
-                getProfileUserIdsForParentUser(currentUserId), userId);
-    }
-
-    @GuardedBy("this")
-    private synchronized int[] getProfileUserIdsForParentUser(@UserIdInt int parentUserId) {
-        if (parentUserId != mCachedParentUserId) {
-            long identity = Binder.clearCallingIdentity();
-            try {
-                Preconditions.checkState(mUserManager != null);
-
-                // more expensive check - check that argument really is a parent user id
-                if (Build.IS_DEBUGGABLE) {
-                    Preconditions.checkArgument(
-                            mUserManager.getProfileParent(parentUserId) == null);
-                }
-
-                mCachedParentUserId = parentUserId;
-                mCachedProfileUserIds = mUserManager.getProfileIdsWithDisabled(parentUserId);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
+        synchronized (this) {
+            if (mActivityManagerInternal == null) {
+                return false;
             }
         }
 
-        return mCachedProfileUserIds;
+        long identity = Binder.clearCallingIdentity();
+        try {
+            return mActivityManagerInternal.isCurrentProfile(userId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private int[] getProfileIds(@UserIdInt int userId) {
+        synchronized (this) {
+            Preconditions.checkState(mUserManager != null);
+        }
+
+        long identity = Binder.clearCallingIdentity();
+        try {
+            return mUserManager.getEnabledProfileIds(userId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
     /**
      * Dump info for debugging.
      */
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        boolean systemRunning;
-        synchronized (this) {
-            systemRunning = mUserManager != null;
-        }
-
-        if (systemRunning) {
-            int[] currentUserIds = getProfileUserIdsForParentUser(mCurrentUserId);
-            pw.println("current users: " + Arrays.toString(currentUserIds));
-            for (int userId : currentUserIds) {
-                if (mUserManager.hasUserRestrictionForUser(DISALLOW_SHARE_LOCATION,
+        int[] currentUserProfiles = getCurrentUserIds();
+        pw.println("current users: " + Arrays.toString(currentUserProfiles));
+        UserManager userManager = mContext.getSystemService(UserManager.class);
+        if (userManager != null) {
+            for (int userId : currentUserProfiles) {
+                if (userManager.hasUserRestrictionForUser(DISALLOW_SHARE_LOCATION,
                         UserHandle.of(userId))) {
                     pw.println("  u" + userId + " restricted");
                 }
             }
-        } else {
-            pw.println("current user: " + mCurrentUserId);
         }
     }
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 9d3385f..a95dc30 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -246,6 +246,7 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.ConcurrentUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.Preconditions;
@@ -2173,19 +2174,19 @@
         mStatsManager.setPullAtomCallback(
                 PACKAGE_NOTIFICATION_PREFERENCES,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(),
+                ConcurrentUtils.DIRECT_EXECUTOR,
                 mPullAtomCallback
         );
         mStatsManager.setPullAtomCallback(
                 PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(),
+                ConcurrentUtils.DIRECT_EXECUTOR,
                 mPullAtomCallback
         );
         mStatsManager.setPullAtomCallback(
                 PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(),
+                ConcurrentUtils.DIRECT_EXECUTOR,
                 mPullAtomCallback
         );
     }
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index 81ee7d9..52fdc79 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.DataLoaderParamsParcel;
 import android.content.pm.IDataLoader;
 import android.content.pm.IDataLoaderManager;
@@ -122,19 +121,7 @@
                         ri.serviceInfo.packageName, ri.serviceInfo.name);
                 // There should only be one matching provider inside the given package.
                 // If there's more than one, return the first one found.
-                try {
-                    ApplicationInfo ai = pm.getApplicationInfo(resolved.getPackageName(), 0);
-                    if (!ai.isPrivilegedApp()) {
-                        Slog.w(TAG,
-                                "Data loader: " + resolved + " is not a privileged app, skipping.");
-                        continue;
-                    }
-                    return resolved;
-                } catch (PackageManager.NameNotFoundException ex) {
-                    Slog.w(TAG,
-                            "Privileged data loader: " + resolved + " not found, skipping.");
-                }
-
+                return resolved;
             }
             Slog.e(TAG, "Didn't find any matching data loader service provider.");
             return null;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 236a681..f827721 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -40,6 +40,7 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageInstaller.SessionParams;
+import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.VersionedPackage;
@@ -126,8 +127,10 @@
     private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
     /** Automatically destroy staged sessions that have not changed state in this time */
     private static final long MAX_TIME_SINCE_UPDATE_MILLIS = 7 * DateUtils.DAY_IN_MILLIS;
-    /** Upper bound on number of active sessions for a UID */
-    private static final long MAX_ACTIVE_SESSIONS = 1024;
+    /** Upper bound on number of active sessions for a UID that has INSTALL_PACKAGES */
+    private static final long MAX_ACTIVE_SESSIONS_WITH_PERMISSION = 1024;
+    /** Upper bound on number of active sessions for a UID without INSTALL_PACKAGES */
+    private static final long MAX_ACTIVE_SESSIONS_NO_PERMISSION = 50;
     /** Upper bound on number of historical sessions for a UID */
     private static final long MAX_HISTORICAL_SESSIONS = 1048576;
 
@@ -503,7 +506,18 @@
                     + "to use a data loader");
         }
 
-        String requestedInstallerPackageName = params.installerPackageName != null
+        // App package name and label length is restricted so that really long strings aren't
+        // written to disk.
+        if (params.appPackageName != null
+                && params.appPackageName.length() > SessionParams.MAX_PACKAGE_NAME_LENGTH) {
+            params.appPackageName = null;
+        }
+
+        params.appLabel = TextUtils.trimToSize(params.appLabel,
+                PackageItemInfo.MAX_SAFE_LABEL_LENGTH);
+
+        String requestedInstallerPackageName = (params.installerPackageName != null
+                && params.installerPackageName.length() < SessionParams.MAX_PACKAGE_NAME_LENGTH)
                 ? params.installerPackageName : installerPackageName;
 
         if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
@@ -635,12 +649,23 @@
             }
         }
 
+        if (params.whitelistedRestrictedPermissions != null) {
+            mPermissionManager.retainHardAndSoftRestrictedPermissions(
+                    params.whitelistedRestrictedPermissions);
+        }
+
         final int sessionId;
         final PackageInstallerSession session;
         synchronized (mSessions) {
             // Sanity check that installer isn't going crazy
             final int activeCount = getSessionCount(mSessions, callingUid);
-            if (activeCount >= MAX_ACTIVE_SESSIONS) {
+            if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
+                    == PackageManager.PERMISSION_GRANTED) {
+                if (activeCount >= MAX_ACTIVE_SESSIONS_WITH_PERMISSION) {
+                    throw new IllegalStateException(
+                            "Too many active sessions for UID " + callingUid);
+                }
+            } else if (activeCount >= MAX_ACTIVE_SESSIONS_NO_PERMISSION) {
                 throw new IllegalStateException(
                         "Too many active sessions for UID " + callingUid);
             }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6bb10c7..766fae6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -148,6 +148,8 @@
 import android.app.admin.IDevicePolicyManager;
 import android.app.admin.SecurityLog;
 import android.app.backup.IBackupManager;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -639,6 +641,19 @@
      */
     private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW;
 
+    /**
+     * Adding an installer package name to a package that does not have one set requires the
+     * INSTALL_PACKAGES permission.
+     *
+     * If the caller targets R, this will throw a SecurityException. Otherwise the request will
+     * fail silently. In both cases, and regardless of whether this change is enabled, the
+     * installer package will remain unchanged.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+    private static final long THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE =
+            150857253;
+
     public static final String PLATFORM_PACKAGE_NAME = "android";
 
     private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
@@ -5264,15 +5279,17 @@
      * </ul>
      */
     int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
-            boolean matchSystemOnly) {
+            boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
         return updateFlagsForResolve(flags, userId, callingUid,
-                wantInstantApps, matchSystemOnly, false /*onlyExposedExplicitly*/);
+                wantInstantApps, false /*onlyExposedExplicitly*/,
+                isImplicitImageCaptureIntentAndNotSetByDpc);
     }
 
     int updateFlagsForResolve(int flags, int userId, int callingUid,
-            boolean wantInstantApps, boolean onlyExposedExplicitly, boolean matchSystemOnly) {
+            boolean wantInstantApps, boolean onlyExposedExplicitly,
+            boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
         // Safe mode means we shouldn't match any third-party components
-        if (mSafeMode || matchSystemOnly) {
+        if (mSafeMode || isImplicitImageCaptureIntentAndNotSetByDpc) {
             flags |= PackageManager.MATCH_SYSTEM_ONLY;
         }
         if (getInstantAppPackageName(callingUid) != null) {
@@ -6400,7 +6417,8 @@
             if (!mUserManager.exists(userId)) return null;
             final int callingUid = Binder.getCallingUid();
             flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
-                    intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+                    isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+                            flags));
             mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                     false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
 
@@ -6438,7 +6456,7 @@
         final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
         final int flags = updateFlagsForResolve(
                 0, userId, callingUid, false /*includeInstantApps*/,
-                intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+                isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, 0));
         final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
                 userId);
         synchronized (mLock) {
@@ -6684,6 +6702,40 @@
         return true;
     }
 
+    /**
+     * From Android R, camera intents have to match system apps. The only exception to this is if
+     * the DPC has set the camera persistent preferred activity. This case was introduced
+     * because it is important that the DPC has the ability to set both system and non-system
+     * camera persistent preferred activities.
+     *
+     * @return {@code true} if the intent is a camera intent and the persistent preferred
+     * activity was not set by the DPC.
+     */
+    @GuardedBy("mLock")
+    private boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
+            String resolvedType, int flags) {
+        return intent.isImplicitImageCaptureIntent() && !isPersistentPreferredActivitySetByDpm(
+                intent, userId, resolvedType, flags);
+    }
+
+    private boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
+            String resolvedType, int flags) {
+        PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
+                .get(userId);
+        //TODO(b/158003772): Remove double query
+        List<PersistentPreferredActivity> pprefs = ppir != null
+                ? ppir.queryIntent(intent, resolvedType,
+                (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
+                userId)
+                : new ArrayList<>();
+        for (PersistentPreferredActivity ppa : pprefs) {
+            if (ppa.mIsSetByDpm) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @GuardedBy("mLock")
     private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
             int flags, List<ResolveInfo> query, boolean debug, int userId) {
@@ -6767,7 +6819,8 @@
                         android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
         flags = updateFlagsForResolve(
                 flags, userId, callingUid, false /*includeInstantApps*/,
-                intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+                isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+                        flags));
         intent = updateIntentForResolve(intent);
         // writer
         synchronized (mLock) {
@@ -6980,7 +7033,8 @@
             synchronized (mLock) {
                 int flags = updateFlagsForResolve(0, parent.id, callingUid,
                         false /*includeInstantApps*/,
-                        intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+                        isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, parent.id,
+                                resolvedType, 0));
                 CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
                         intent, resolvedType, flags, sourceUserId, parent.id);
                 return xpDomainInfo != null;
@@ -7067,7 +7121,8 @@
 
         flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
                 comp != null || pkgName != null /*onlyExposedExplicitly*/,
-                intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+                isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+                        flags));
         if (comp != null) {
             final List<ResolveInfo> list = new ArrayList<>(1);
             final ActivityInfo ai = getActivityInfo(comp, flags, userId);
@@ -7856,7 +7911,8 @@
         if (!mUserManager.exists(userId)) return Collections.emptyList();
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
-                intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+                isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+                        flags));
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/,
                 "query intent activity options");
@@ -8043,7 +8099,8 @@
                 "query intent receivers");
         final String instantAppPkgName = getInstantAppPackageName(callingUid);
         flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
-                intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+                isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+                        flags));
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -8134,7 +8191,7 @@
             int userId, int callingUid) {
         if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
-                false /* matchSystemOnly */);
+                false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
         List<ResolveInfo> query = queryIntentServicesInternal(
                 intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/);
         if (query != null) {
@@ -8166,7 +8223,7 @@
                 "query intent receivers");
         final String instantAppPkgName = getInstantAppPackageName(callingUid);
         flags = updateFlagsForResolve(flags, userId, callingUid, includeInstantApps,
-                false /* matchSystemOnly */);
+                false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -8304,7 +8361,7 @@
         final int callingUid = Binder.getCallingUid();
         final String instantAppPkgName = getInstantAppPackageName(callingUid);
         flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
-                false /* matchSystemOnly */);
+                false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -14130,19 +14187,38 @@
             // be signed with the same cert as the caller.
             String targetInstallerPackageName =
                     targetPackageSetting.installSource.installerPackageName;
-            if (targetInstallerPackageName != null) {
-                PackageSetting setting = mSettings.mPackages.get(
-                        targetInstallerPackageName);
-                // If the currently set package isn't valid, then it's always
-                // okay to change it.
-                if (setting != null) {
-                    if (compareSignatures(callerSignature,
-                            setting.signatures.mSigningDetails.signatures)
-                            != PackageManager.SIGNATURE_MATCH) {
-                        throw new SecurityException(
-                                "Caller does not have same cert as old installer package "
-                                + targetInstallerPackageName);
+            PackageSetting targetInstallerPkgSetting = targetInstallerPackageName == null ? null :
+                    mSettings.mPackages.get(targetInstallerPackageName);
+
+            if (targetInstallerPkgSetting != null) {
+                if (compareSignatures(callerSignature,
+                        targetInstallerPkgSetting.signatures.mSigningDetails.signatures)
+                        != PackageManager.SIGNATURE_MATCH) {
+                    throw new SecurityException(
+                            "Caller does not have same cert as old installer package "
+                            + targetInstallerPackageName);
+                }
+            } else if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
+                    != PackageManager.PERMISSION_GRANTED) {
+                // This is probably an attempt to exploit vulnerability b/150857253 of taking
+                // privileged installer permissions when the installer has been uninstalled or
+                // was never set.
+                EventLog.writeEvent(0x534e4554, "150857253", callingUid, "");
+
+                long binderToken = Binder.clearCallingIdentity();
+                try {
+                    if (mInjector.getCompatibility().isChangeEnabledByUid(
+                            THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE,
+                            callingUid)) {
+                        throw new SecurityException("Neither user " + callingUid
+                                + " nor current process has "
+                                + Manifest.permission.INSTALL_PACKAGES);
+                    } else {
+                        // If change disabled, fail silently for backwards compatibility
+                        return;
                     }
+                } finally {
+                    Binder.restoreCallingIdentity(binderToken);
                 }
             }
 
@@ -19840,7 +19916,7 @@
         }
         synchronized (mLock) {
             mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
-                    new PersistentPreferredActivity(filter, activity));
+                    new PersistentPreferredActivity(filter, activity, true));
             scheduleWritePackageRestrictionsLocked(userId);
         }
         updateDefaultHomeNotLocked(userId);
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredActivity.java b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
index 0d4cdf9..5a6fd09 100644
--- a/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
+++ b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
@@ -16,31 +16,34 @@
 
 package com.android.server.pm;
 
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.util.Log;
+
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
-import android.content.ComponentName;
-import android.content.IntentFilter;
-import android.util.Log;
-
 import java.io.IOException;
 
 class PersistentPreferredActivity extends IntentFilter {
     private static final String ATTR_NAME = "name"; // component name
     private static final String ATTR_FILTER = "filter"; // filter
+    private static final String ATTR_SET_BY_DPM = "set-by-dpm"; // set by DPM
 
     private static final String TAG = "PersistentPreferredActivity";
 
     private static final boolean DEBUG_FILTERS = false;
 
     final ComponentName mComponent;
+    final boolean mIsSetByDpm;
 
-    PersistentPreferredActivity(IntentFilter filter, ComponentName activity) {
+    PersistentPreferredActivity(IntentFilter filter, ComponentName activity, boolean isSetByDpm) {
         super(filter);
         mComponent = activity;
+        mIsSetByDpm = isSetByDpm;
     }
 
     PersistentPreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException {
@@ -52,6 +55,8 @@
                             "Bad activity name " + shortComponent +
                             " at " + parser.getPositionDescription());
         }
+        mIsSetByDpm = Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_SET_BY_DPM));
+
         int outerDepth = parser.getDepth();
         String tagName = parser.getName();
         int type;
@@ -83,6 +88,7 @@
 
     public void writeToXml(XmlSerializer serializer) throws IOException {
         serializer.attribute(null, ATTR_NAME, mComponent.flattenToShortString());
+        serializer.attribute(null, ATTR_SET_BY_DPM, Boolean.toString(mIsSetByDpm));
         serializer.startTag(null, ATTR_FILTER);
             super.writeToXml(serializer);
         serializer.endTag(null, ATTR_FILTER);
@@ -91,6 +97,7 @@
     @Override
     public String toString() {
         return "PersistentPreferredActivity{0x" + Integer.toHexString(System.identityHashCode(this))
-                + " " + mComponent.flattenToShortString() + "}";
+                + " " + mComponent.flattenToShortString()
+                + ", mIsSetByDpm=" + mIsSetByDpm + "}";
     }
 }
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 79805e3..8ccf837 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -77,7 +77,11 @@
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.rollback.WatchdogRollbackLogger;
 
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
 import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
@@ -102,6 +106,9 @@
     private final PreRebootVerificationHandler mPreRebootVerificationHandler;
     private final Supplier<PackageParser2> mPackageParserSupplier;
 
+    private final File mFailureReasonFile = new File("/metadata/staged-install/failure_reason.txt");
+    private String mFailureReason;
+
     @GuardedBy("mStagedSessions")
     private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
 
@@ -125,6 +132,12 @@
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mPreRebootVerificationHandler = new PreRebootVerificationHandler(
                 BackgroundThread.get().getLooper());
+
+        if (mFailureReasonFile.exists()) {
+            try (BufferedReader reader = new BufferedReader(new FileReader(mFailureReasonFile))) {
+                mFailureReason = reader.readLine();
+            } catch (Exception ignore) { }
+        }
     }
 
     /**
@@ -383,10 +396,19 @@
     }
 
     // Reverts apex sessions and user data (if checkpoint is supported). Also reboots the device.
-    private void abortCheckpoint(String errorMsg) {
-        Slog.e(TAG, "Aborting checkpoint: " + errorMsg);
+    private void abortCheckpoint(int sessionId, String errorMsg) {
+        String failureReason = "Failed to install sessionId: " + sessionId + " Error: " + errorMsg;
+        Slog.e(TAG, failureReason);
         try {
             if (supportsCheckpoint() && needsCheckpoint()) {
+                // Store failure reason for next reboot
+                try (BufferedWriter writer =
+                             new BufferedWriter(new FileWriter(mFailureReasonFile))) {
+                    writer.write(failureReason);
+                } catch (Exception e) {
+                    Slog.w(TAG, "Failed to save failure reason: ", e);
+                }
+
                 // Only revert apex sessions if device supports updating apex
                 if (mApexManager.isApexSupported()) {
                     mApexManager.revertActiveSessions();
@@ -592,14 +614,12 @@
             // If checkpoint is supported, then we only resume sessions if we are in checkpointing
             // mode. If not, we fail all sessions.
             if (supportsCheckpoint() && !needsCheckpoint()) {
-                // TODO(b/146343545): Persist failure reason across checkpoint reboot
-                Slog.d(TAG, "Reverting back to safe state. Marking " + session.sessionId
-                        + " as failed.");
-                String errorMsg = "Reverting back to safe state";
-                if (!TextUtils.isEmpty(mNativeFailureReason)) {
-                    errorMsg = "Entered fs-rollback mode and reverted session due to crashing "
-                            + "native process: " + mNativeFailureReason;
+                String errorMsg = "Reverting back to safe state. Marking " + session.sessionId
+                        + " as failed";
+                if (!TextUtils.isEmpty(mFailureReason)) {
+                    errorMsg = errorMsg + ": " + mFailureReason;
                 }
+                Slog.d(TAG, errorMsg);
                 session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN, errorMsg);
                 return;
             }
@@ -624,7 +644,7 @@
                         + "supposed to be activated";
                 session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
                         errorMsg);
-                abortCheckpoint(errorMsg);
+                abortCheckpoint(session.sessionId, errorMsg);
                 return;
             }
             if (isApexSessionFailed(apexSessionInfo)) {
@@ -636,7 +656,7 @@
                 }
                 session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
                         errorMsg);
-                abortCheckpoint(errorMsg);
+                abortCheckpoint(session.sessionId, errorMsg);
                 return;
             }
             if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
@@ -647,7 +667,7 @@
                         + "didn't activate nor fail. Marking it as failed anyway.";
                 session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
                         errorMsg);
-                abortCheckpoint(errorMsg);
+                abortCheckpoint(session.sessionId, errorMsg);
                 return;
             }
         }
@@ -664,7 +684,7 @@
             installApksInSession(session);
         } catch (PackageManagerException e) {
             session.setStagedSessionFailed(e.error, e.getMessage());
-            abortCheckpoint(e.getMessage());
+            abortCheckpoint(session.sessionId, e.getMessage());
 
             // If checkpoint is not supported, we have to handle failure for one staged session.
             if (!hasApex) {
@@ -1189,6 +1209,8 @@
                 ctx.unregisterReceiver(this);
             }
         }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+
+        mFailureReasonFile.delete();
     }
 
     private static class LocalIntentReceiverAsync {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d5c9424..40fa798 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2250,9 +2250,6 @@
         // Managed profiles have their own specific rules.
         final boolean isManagedProfile = type.isManagedProfile();
         if (isManagedProfile) {
-            if (ActivityManager.isLowRamDeviceStatic()) {
-                return false;
-            }
             if (!mContext.getPackageManager().hasSystemFeature(
                     PackageManager.FEATURE_MANAGED_USERS)) {
                 return false;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index b0d4d95..d3f3ba1 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -26,6 +26,7 @@
 import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
@@ -1804,8 +1805,9 @@
                 continue;
             }
 
-            // If this permission was granted by default, make sure it is.
-            if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
+            // If this permission was granted by default or role, make sure it is.
+            if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0
+                    || (oldFlags & FLAG_PERMISSION_GRANTED_BY_ROLE) != 0) {
                 // PermissionPolicyService will handle the app op for runtime permissions later.
                 grantRuntimePermissionInternal(permName, packageName, false,
                         Process.SYSTEM_UID, userId, delayingPermCallback);
@@ -4948,6 +4950,20 @@
                         StorageManager.UUID_PRIVATE_INTERNAL, true, mDefaultPermissionCallback);
             }
         }
+
+        @Override
+        public void retainHardAndSoftRestrictedPermissions(@NonNull List<String> permissions) {
+            synchronized (mLock) {
+                Iterator<String> iterator = permissions.iterator();
+                while (iterator.hasNext()) {
+                    String permission = iterator.next();
+                    BasePermission basePermission = mSettings.mPermissions.get(permission);
+                    if (basePermission == null || !basePermission.isHardOrSoftRestricted()) {
+                        iterator.remove();
+                    }
+                }
+            }
+        }
     }
 
     private static final class OnPermissionChangeListeners extends Handler {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 57a25ed..4412162 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -36,6 +36,7 @@
  * TODO: Should be merged into PermissionManagerInternal, but currently uses internal classes.
  */
 public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal {
+
     /**
      * Provider for package names.
      */
@@ -455,4 +456,10 @@
 
     /** Called when a new user has been created. */
     public abstract void onNewUserCreated(@UserIdInt int userId);
+
+    /**
+     * Removes invalid permissions which are not {@link PermissionInfo#FLAG_HARD_RESTRICTED} or
+     * {@link PermissionInfo#FLAG_SOFT_RESTRICTED} from the input.
+     */
+    public abstract void retainHardAndSoftRestrictedPermissions(@NonNull List<String> permissions);
 }
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 6c1ff72..ab459fd 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -3319,8 +3319,8 @@
                         public void run() {
                             try {
                                 estimateAppOpsSamplingRate();
-                            } catch (Exception e) {
-                                Slog.e(TAG, "AppOps sampling ratio estimation failed");
+                            } catch (Throwable e) {
+                                Slog.e(TAG, "AppOps sampling ratio estimation failed: ", e);
                                 synchronized (mAppOpsSamplingRateLock) {
                                     mAppOpsSamplingRate = min(mAppOpsSamplingRate, 10);
                                 }
@@ -3361,7 +3361,7 @@
                         Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(),
                         Long.MAX_VALUE).setFlags(
                         OP_FLAGS_PULLED).build();
-        appOps.getHistoricalOps(histOpsRequest, mContext.getMainExecutor(), ops::complete);
+        appOps.getHistoricalOps(histOpsRequest, AsyncTask.THREAD_POOL_EXECUTOR, ops::complete);
         HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
                 TimeUnit.MILLISECONDS);
         List<AppOpEntry> opsList =
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 5f63233..c38d649 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -115,7 +115,7 @@
     private static final String TAG = "UriGrantsManagerService";
     // Maximum number of persisted Uri grants a package is allowed
     private static final int MAX_PERSISTED_URI_GRANTS = 128;
-    private static final boolean ENABLE_DYNAMIC_PERMISSIONS = true;
+    private static final boolean ENABLE_DYNAMIC_PERMISSIONS = false;
 
     private final Object mLock = new Object();
     private final H mH;
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index df0fa9c..6e9428e 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -61,6 +61,7 @@
     private static final int NOTIFY_TASK_LIST_FROZEN_UNFROZEN_MSG = 26;
     private static final int NOTIFY_TASK_FOCUS_CHANGED_MSG = 27;
     private static final int NOTIFY_TASK_REQUESTED_ORIENTATION_CHANGED_MSG = 28;
+    private static final int NOTIFY_ACTIVITY_ROTATED_MSG = 29;
 
     // Delay in notifying task stack change listeners (in millis)
     private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -183,6 +184,10 @@
         l.onTaskRequestedOrientationChanged(m.arg1, m.arg2);
     };
 
+    private final TaskStackConsumer mNotifyOnActivityRotation = (l, m) -> {
+        l.onActivityRotation();
+    };
+
     @FunctionalInterface
     public interface TaskStackConsumer {
         void accept(ITaskStackListener t, Message m) throws RemoteException;
@@ -277,6 +282,9 @@
                 case NOTIFY_TASK_REQUESTED_ORIENTATION_CHANGED_MSG:
                     forAllRemoteListeners(mNotifyTaskRequestedOrientationChanged, msg);
                     break;
+                case NOTIFY_ACTIVITY_ROTATED_MSG:
+                    forAllRemoteListeners(mNotifyOnActivityRotation, msg);
+                    break;
             }
             if (msg.obj instanceof SomeArgs) {
                 ((SomeArgs) msg.obj).recycle();
@@ -574,4 +582,11 @@
         forAllLocalListeners(mNotifyTaskRequestedOrientationChanged, msg);
         msg.sendToTarget();
     }
+
+    /** @see android.app.ITaskStackListener#onActivityRotation() */
+    void notifyOnActivityRotation() {
+        final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_ROTATED_MSG);
+        forAllLocalListeners(mNotifyOnActivityRotation, msg);
+        msg.sendToTarget();
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f34510e..8934e8f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3848,6 +3848,11 @@
                     final boolean rotationChanged = displayContent.updateRotationUnchecked();
                     Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
 
+                    if (rotationChanged) {
+                        mAtmService.getTaskChangeNotificationController()
+                                .notifyOnActivityRotation();
+                    }
+
                     if (!rotationChanged || forceRelayout) {
                         displayContent.setLayoutNeeded();
                         layoutNeeded = true;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0450890..36232e1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5790,10 +5790,10 @@
         // be invoked and we need to invoke it ourself.
         if (mLocalSyncId >= 0) {
             mBLASTSyncEngine.setReady(mLocalSyncId);
-        } else {
-            mWaitingListener.onTransactionReady(mWaitingSyncId, mBLASTSyncTransaction);
+            return mWinAnimator.finishDrawingLocked(null);
         }
 
+        mWaitingListener.onTransactionReady(mWaitingSyncId, mBLASTSyncTransaction);
         mUsingBLASTSyncTransaction = false;
 
         mWaitingSyncId = 0;
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java
index 71e79b3..56727e8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java
@@ -16,34 +16,23 @@
 package com.android.server.location;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
 
-import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
+import android.app.ActivityManagerInternal;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.UserInfo;
-import android.os.Handler;
-import android.os.UserHandle;
 import android.os.UserManager;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.server.LocalServices;
 import com.android.server.location.UserInfoHelper.UserListener;
 
 import org.junit.After;
@@ -51,16 +40,18 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.quality.Strictness;
-
-import java.util.ArrayList;
-import java.util.List;
 
 @Presubmit
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class UserInfoHelperTest {
 
+    private static class TestUserInfoHelper extends UserInfoHelper {
+        TestUserInfoHelper(Context context) {
+            super(context);
+        }
+    }
+
     private static final int USER1_ID = 1;
     private static final int USER1_MANAGED_ID = 11;
     private static final int[] USER1_PROFILES = new int[]{USER1_ID, USER1_MANAGED_ID};
@@ -70,69 +61,30 @@
 
     @Mock private Context mContext;
     @Mock private UserManager mUserManager;
+    @Mock private ActivityManagerInternal mActivityManagerInternal;
 
-    private StaticMockitoSession mMockingSession;
-    private List<BroadcastReceiver> mBroadcastReceivers = new ArrayList<>();
-
-    private UserInfoHelper mHelper;
+    private TestUserInfoHelper mHelper;
 
     @Before
     public void setUp() {
-        mMockingSession = mockitoSession()
-                .initMocks(this)
-                .spyStatic(ActivityManager.class)
-                .strictness(Strictness.WARN)
-                .startMocking();
+        initMocks(this);
 
+        LocalServices.addService(ActivityManagerInternal.class, mActivityManagerInternal);
         doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
-        doAnswer(invocation -> {
-            mBroadcastReceivers.add(invocation.getArgument(0));
-            return null;
-        }).when(mContext).registerReceiverAsUser(any(BroadcastReceiver.class), any(
-                UserHandle.class), any(IntentFilter.class), isNull(), any(Handler.class));
-        doReturn(USER1_PROFILES).when(mUserManager).getProfileIdsWithDisabled(USER1_ID);
-        doReturn(USER2_PROFILES).when(mUserManager).getProfileIdsWithDisabled(USER2_ID);
-        doReturn(new UserInfo(USER1_ID, "", 0)).when(mUserManager).getProfileParent(
-                USER1_MANAGED_ID);
-        doReturn(new UserInfo(USER2_ID, "", 0)).when(mUserManager).getProfileParent(
-                USER2_MANAGED_ID);
 
-        doReturn(USER1_ID).when(ActivityManager::getCurrentUser);
+        doReturn(USER1_PROFILES).when(mUserManager).getEnabledProfileIds(USER1_ID);
+        doReturn(USER2_PROFILES).when(mUserManager).getEnabledProfileIds(USER2_ID);
+        doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER1_ID);
+        doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER1_MANAGED_ID);
+        doReturn(USER1_PROFILES).when(mActivityManagerInternal).getCurrentProfileIds();
 
-        mHelper = new UserInfoHelper(mContext);
+        mHelper = new TestUserInfoHelper(mContext);
         mHelper.onSystemReady();
     }
 
     @After
     public void tearDown() {
-        if (mMockingSession != null) {
-            mMockingSession.finishMocking();
-        }
-    }
-
-    private void switchUser(int userId) {
-        doReturn(userId).when(ActivityManager::getCurrentUser);
-        Intent intent = new Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE,
-                userId);
-        for (BroadcastReceiver broadcastReceiver : mBroadcastReceivers) {
-            broadcastReceiver.onReceive(mContext, intent);
-        }
-    }
-
-    private void startUser(int userId) {
-        Intent intent = new Intent(Intent.ACTION_USER_STARTED).putExtra(Intent.EXTRA_USER_HANDLE,
-                userId);
-        for (BroadcastReceiver broadcastReceiver : mBroadcastReceivers) {
-            broadcastReceiver.onReceive(mContext, intent);
-        }
-    }
-
-    private void stopUser(int userId) {
-        Intent intent = new Intent(Intent.ACTION_USER_STOPPED).putExtra(Intent.EXTRA_USER_HANDLE,
-                userId);
-        for (BroadcastReceiver broadcastReceiver : mBroadcastReceivers) {
-            broadcastReceiver.onReceive(mContext, intent);
-        }
+        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
     }
 
     @Test
@@ -140,16 +92,21 @@
         UserListener listener = mock(UserListener.class);
         mHelper.addListener(listener);
 
-        switchUser(USER1_ID);
-        verify(listener, never()).onUserChanged(anyInt(), anyInt());
+        mHelper.dispatchOnCurrentUserChanged(USER1_ID, USER2_ID);
+        verify(listener, times(1)).onUserChanged(USER1_ID, UserListener.CURRENT_USER_CHANGED);
+        verify(listener, times(1)).onUserChanged(USER1_MANAGED_ID,
+                UserListener.CURRENT_USER_CHANGED);
+        verify(listener, times(1)).onUserChanged(USER2_ID, UserListener.CURRENT_USER_CHANGED);
+        verify(listener, times(1)).onUserChanged(USER2_MANAGED_ID,
+                UserListener.CURRENT_USER_CHANGED);
 
-        switchUser(USER2_ID);
-        verify(listener, times(1)).onUserChanged(USER1_ID, UserListener.USER_SWITCHED);
-        verify(listener, times(1)).onUserChanged(USER2_ID, UserListener.USER_SWITCHED);
-
-        switchUser(USER1_ID);
-        verify(listener, times(2)).onUserChanged(USER1_ID, UserListener.USER_SWITCHED);
-        verify(listener, times(2)).onUserChanged(USER2_ID, UserListener.USER_SWITCHED);
+        mHelper.dispatchOnCurrentUserChanged(USER2_ID, USER1_ID);
+        verify(listener, times(2)).onUserChanged(USER2_ID, UserListener.CURRENT_USER_CHANGED);
+        verify(listener, times(2)).onUserChanged(USER2_MANAGED_ID,
+                UserListener.CURRENT_USER_CHANGED);
+        verify(listener, times(2)).onUserChanged(USER1_ID, UserListener.CURRENT_USER_CHANGED);
+        verify(listener, times(2)).onUserChanged(USER1_MANAGED_ID,
+                UserListener.CURRENT_USER_CHANGED);
     }
 
     @Test
@@ -157,11 +114,11 @@
         UserListener listener = mock(UserListener.class);
         mHelper.addListener(listener);
 
-        startUser(USER1_ID);
+        mHelper.dispatchOnUserStarted(USER1_ID);
         verify(listener).onUserChanged(USER1_ID, UserListener.USER_STARTED);
 
-        startUser(USER2_ID);
-        verify(listener).onUserChanged(USER2_ID, UserListener.USER_STARTED);
+        mHelper.dispatchOnUserStarted(USER1_MANAGED_ID);
+        verify(listener).onUserChanged(USER1_MANAGED_ID, UserListener.USER_STARTED);
     }
 
     @Test
@@ -169,24 +126,22 @@
         UserListener listener = mock(UserListener.class);
         mHelper.addListener(listener);
 
-        stopUser(USER1_ID);
-        verify(listener).onUserChanged(USER1_ID, UserListener.USER_STOPPED);
-
-        stopUser(USER2_ID);
+        mHelper.dispatchOnUserStopped(USER2_ID);
         verify(listener).onUserChanged(USER2_ID, UserListener.USER_STOPPED);
+
+        mHelper.dispatchOnUserStopped(USER2_MANAGED_ID);
+        verify(listener).onUserChanged(USER2_MANAGED_ID, UserListener.USER_STOPPED);
     }
 
     @Test
     public void testCurrentUserIds() {
         assertThat(mHelper.getCurrentUserIds()).isEqualTo(USER1_PROFILES);
 
-        switchUser(USER2_ID);
+        doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_ID);
+        doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_MANAGED_ID);
+        doReturn(USER2_PROFILES).when(mActivityManagerInternal).getCurrentProfileIds();
 
         assertThat(mHelper.getCurrentUserIds()).isEqualTo(USER2_PROFILES);
-
-        switchUser(USER1_ID);
-
-        assertThat(mHelper.getCurrentUserIds()).isEqualTo(USER1_PROFILES);
     }
 
     @Test
@@ -196,7 +151,11 @@
         assertThat(mHelper.isCurrentUserId(USER2_ID)).isFalse();
         assertThat(mHelper.isCurrentUserId(USER2_MANAGED_ID)).isFalse();
 
-        switchUser(USER2_ID);
+        doReturn(false).when(mActivityManagerInternal).isCurrentProfile(USER1_ID);
+        doReturn(false).when(mActivityManagerInternal).isCurrentProfile(USER1_MANAGED_ID);
+        doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_ID);
+        doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_MANAGED_ID);
+        doReturn(USER2_PROFILES).when(mActivityManagerInternal).getCurrentProfileIds();
 
         assertThat(mHelper.isCurrentUserId(USER1_ID)).isFalse();
         assertThat(mHelper.isCurrentUserId(USER2_ID)).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 7af7a23..c34b8e1 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -33,6 +33,7 @@
 import android.content.ContextWrapper;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
 import android.os.IPowerManager;
 import android.os.IThermalService;
 import android.os.Looper;
@@ -261,4 +262,89 @@
         mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
         assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isTrue();
     }
+
+    @Test
+    public void addHdmiCecVolumeControlFeatureListener_emitsCurrentState_enabled() {
+        mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+        VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
+
+        mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback);
+        mTestLooper.dispatchAll();
+
+        assertThat(callback.mCallbackReceived).isTrue();
+        assertThat(callback.mVolumeControlEnabled).isTrue();
+    }
+
+    @Test
+    public void addHdmiCecVolumeControlFeatureListener_emitsCurrentState_disabled() {
+        mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+        VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
+
+        mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback);
+        mTestLooper.dispatchAll();
+
+        assertThat(callback.mCallbackReceived).isTrue();
+        assertThat(callback.mVolumeControlEnabled).isFalse();
+    }
+
+    @Test
+    public void addHdmiCecVolumeControlFeatureListener_notifiesStateUpdate() {
+        mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+        VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
+
+        mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback);
+
+        mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+        mTestLooper.dispatchAll();
+
+        assertThat(callback.mCallbackReceived).isTrue();
+        assertThat(callback.mVolumeControlEnabled).isTrue();
+    }
+
+    @Test
+    public void addHdmiCecVolumeControlFeatureListener_honorsUnregistration() {
+        mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+        VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
+
+        mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback);
+        mTestLooper.dispatchAll();
+
+        mHdmiControlService.removeHdmiControlVolumeControlStatusChangeListener(callback);
+        mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+        mTestLooper.dispatchAll();
+
+        assertThat(callback.mCallbackReceived).isTrue();
+        assertThat(callback.mVolumeControlEnabled).isFalse();
+    }
+
+    @Test
+    public void addHdmiCecVolumeControlFeatureListener_notifiesStateUpdate_multiple() {
+        mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+        VolumeControlFeatureCallback callback1 = new VolumeControlFeatureCallback();
+        VolumeControlFeatureCallback callback2 = new VolumeControlFeatureCallback();
+
+        mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback1);
+        mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback2);
+
+
+        mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+        mTestLooper.dispatchAll();
+
+        assertThat(callback1.mCallbackReceived).isTrue();
+        assertThat(callback2.mCallbackReceived).isTrue();
+        assertThat(callback1.mVolumeControlEnabled).isTrue();
+        assertThat(callback2.mVolumeControlEnabled).isTrue();
+    }
+
+    private static class VolumeControlFeatureCallback extends
+            IHdmiCecVolumeControlFeatureListener.Stub {
+        boolean mCallbackReceived = false;
+        boolean mVolumeControlEnabled = false;
+
+        @Override
+        public void onHdmiCecVolumeControlFeature(boolean enabled) throws RemoteException {
+            this.mCallbackReceived = true;
+            this.mVolumeControlEnabled = enabled;
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
index 5412bb5..74b4d12 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
@@ -18,8 +18,8 @@
 
 import android.content.pm.PackageManager
 import android.platform.test.annotations.Presubmit
+import androidx.test.filters.LargeTest
 import com.google.common.truth.Expect
-import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Rule
 import org.junit.Test
 
@@ -52,6 +52,7 @@
         }
     }
 
+    @LargeTest
     @Test
     fun packageInfoEquality() {
         val flags = PackageManager.GET_ACTIVITIES or
@@ -65,7 +66,9 @@
                 PackageManager.GET_SERVICES or
                 PackageManager.GET_SHARED_LIBRARY_FILES or
                 PackageManager.GET_SIGNATURES or
-                PackageManager.GET_SIGNING_CERTIFICATES
+                PackageManager.GET_SIGNING_CERTIFICATES or
+                PackageManager.MATCH_DIRECT_BOOT_UNAWARE or
+                PackageManager.MATCH_DIRECT_BOOT_AWARE
         val oldPackageInfo = oldPackages.asSequence().map { oldPackageInfo(it, flags) }
         val newPackageInfo = newPackages.asSequence().map { newPackageInfo(it, flags) }
 
@@ -77,11 +80,79 @@
             } else {
                 "$firstName | $secondName"
             }
-            expect.withMessage("${it.first?.applicationInfo?.sourceDir} $packageName")
-                    .that(it.first?.dumpToString())
-                    .isEqualTo(it.second?.dumpToString())
+
+            // Main components are asserted independently to separate the failures. Otherwise the
+            // comparison would include every component in one massive string.
+
+            val prefix = "${it.first?.applicationInfo?.sourceDir} $packageName"
+
+            expect.withMessage("$prefix PackageInfo")
+                    .that(it.second?.dumpToString())
+                    .isEqualTo(it.first?.dumpToString())
+
+            expect.withMessage("$prefix ApplicationInfo")
+                    .that(it.second?.applicationInfo?.dumpToString())
+                    .isEqualTo(it.first?.applicationInfo?.dumpToString())
+
+            val firstActivityNames = it.first?.activities?.map { it.name } ?: emptyList()
+            val secondActivityNames = it.second?.activities?.map { it.name } ?: emptyList()
+            expect.withMessage("$prefix activities")
+                    .that(secondActivityNames)
+                    .containsExactlyElementsIn(firstActivityNames)
+                    .inOrder()
+
+            if (!it.first?.activities.isNullOrEmpty() && !it.second?.activities.isNullOrEmpty()) {
+                it.first?.activities?.zip(it.second?.activities!!)?.forEach {
+                    expect.withMessage("$prefix ${it.first.name}")
+                            .that(it.second.dumpToString())
+                            .isEqualTo(it.first.dumpToString())
+                }
+            }
+
+            val firstReceiverNames = it.first?.receivers?.map { it.name } ?: emptyList()
+            val secondReceiverNames = it.second?.receivers?.map { it.name } ?: emptyList()
+            expect.withMessage("$prefix receivers")
+                    .that(secondReceiverNames)
+                    .containsExactlyElementsIn(firstReceiverNames)
+                    .inOrder()
+
+            if (!it.first?.receivers.isNullOrEmpty() && !it.second?.receivers.isNullOrEmpty()) {
+                it.first?.receivers?.zip(it.second?.receivers!!)?.forEach {
+                    expect.withMessage("$prefix ${it.first.name}")
+                            .that(it.second.dumpToString())
+                            .isEqualTo(it.first.dumpToString())
+                }
+            }
+
+            val firstProviderNames = it.first?.providers?.map { it.name } ?: emptyList()
+            val secondProviderNames = it.second?.providers?.map { it.name } ?: emptyList()
+            expect.withMessage("$prefix providers")
+                    .that(secondProviderNames)
+                    .containsExactlyElementsIn(firstProviderNames)
+                    .inOrder()
+
+            if (!it.first?.providers.isNullOrEmpty() && !it.second?.providers.isNullOrEmpty()) {
+                it.first?.providers?.zip(it.second?.providers!!)?.forEach {
+                    expect.withMessage("$prefix ${it.first.name}")
+                            .that(it.second.dumpToString())
+                            .isEqualTo(it.first.dumpToString())
+                }
+            }
+
+            val firstServiceNames = it.first?.services?.map { it.name } ?: emptyList()
+            val secondServiceNames = it.second?.services?.map { it.name } ?: emptyList()
+            expect.withMessage("$prefix services")
+                    .that(secondServiceNames)
+                    .containsExactlyElementsIn(firstServiceNames)
+                    .inOrder()
+
+            if (!it.first?.services.isNullOrEmpty() && !it.second?.services.isNullOrEmpty()) {
+                it.first?.services?.zip(it.second?.services!!)?.forEach {
+                    expect.withMessage("$prefix ${it.first.name}")
+                            .that(it.second.dumpToString())
+                            .isEqualTo(it.first.dumpToString())
+                }
+            }
         }
     }
 }
-
-
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
index 0f028f0..420ff19 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.content.pm.ActivityInfo
 import android.content.pm.ApplicationInfo
+import android.content.pm.ComponentInfo
 import android.content.pm.ConfigurationInfo
 import android.content.pm.FeatureInfo
 import android.content.pm.InstrumentationInfo
@@ -27,6 +28,8 @@
 import android.content.pm.PackageUserState
 import android.content.pm.PermissionInfo
 import android.content.pm.ProviderInfo
+import android.content.pm.ServiceInfo
+import android.os.Bundle
 import android.os.Debug
 import android.os.Environment
 import android.util.SparseArray
@@ -38,8 +41,10 @@
 import com.android.server.testutils.mockThrowOnUnmocked
 import com.android.server.testutils.whenever
 import org.junit.BeforeClass
-import org.mockito.Mockito
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyBoolean
 import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.anyString
 import org.mockito.Mockito.mock
 import java.io.File
 
@@ -47,7 +52,7 @@
 
     companion object {
 
-        private const val VERIFY_ALL_APKS = false
+        private const val VERIFY_ALL_APKS = true
 
         /** For auditing memory usage differences */
         private const val DUMP_HPROF_TO_EXTERNAL = false
@@ -81,10 +86,14 @@
                             .filter { file -> file.name.endsWith(".apk") }
                             .toList()
                 }
+                .distinct()
 
         private val dummyUserState = mock(PackageUserState::class.java).apply {
             installed = true
-            Mockito.`when`(isAvailable(anyInt())).thenReturn(true)
+            whenever(isAvailable(anyInt())) { true }
+            whenever(isMatch(any<ComponentInfo>(), anyInt())) { true }
+            whenever(isMatch(anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(),
+                    anyString(), anyInt())) { true }
         }
 
         lateinit var oldPackages: List<PackageParser.Package>
@@ -145,6 +154,7 @@
         private fun mockPkgSetting(aPkg: AndroidPackage) = mockThrowOnUnmocked<PackageSetting> {
             this.pkg = aPkg
             whenever(pkgState) { PackageStateUnserialized() }
+            whenever(readUserState(anyInt())) { dummyUserState }
         }
     }
 
@@ -156,19 +166,10 @@
     // The following methods prepend "this." because @hide APIs can cause an IDE to auto-import
     // the R.attr constant instead of referencing the field in an attempt to fix the error.
 
-    /**
-     * Known exclusions:
-     *   - [ApplicationInfo.credentialProtectedDataDir]
-     *   - [ApplicationInfo.dataDir]
-     *   - [ApplicationInfo.deviceProtectedDataDir]
-     *   - [ApplicationInfo.processName]
-     *   - [ApplicationInfo.publicSourceDir]
-     *   - [ApplicationInfo.scanPublicSourceDir]
-     *   - [ApplicationInfo.scanSourceDir]
-     *   - [ApplicationInfo.sourceDir]
-     * These attributes used to be assigned post-package-parsing as part of another component,
-     * but are now adjusted directly inside [PackageImpl].
-     */
+    // It's difficult to comment out a line in a triple quoted string, so this is used instead
+    // to ignore specific fields. A comment is required to explain why a field was ignored.
+    private fun Any?.ignored(comment: String): String = "IGNORED"
+
     protected fun ApplicationInfo.dumpToString() = """
             appComponentFactory=${this.appComponentFactory}
             backupAgentName=${this.backupAgentName}
@@ -179,22 +180,31 @@
             compatibleWidthLimitDp=${this.compatibleWidthLimitDp}
             compileSdkVersion=${this.compileSdkVersion}
             compileSdkVersionCodename=${this.compileSdkVersionCodename}
+            credentialProtectedDataDir=${this.credentialProtectedDataDir
+            .ignored("Deferred pre-R, but assigned immediately in R")}
+            crossProfile=${this.crossProfile.ignored("Added in R")}
+            dataDir=${this.dataDir.ignored("Deferred pre-R, but assigned immediately in R")}
             descriptionRes=${this.descriptionRes}
+            deviceProtectedDataDir=${this.deviceProtectedDataDir
+            .ignored("Deferred pre-R, but assigned immediately in R")}
             enabled=${this.enabled}
             enabledSetting=${this.enabledSetting}
             flags=${Integer.toBinaryString(this.flags)}
             fullBackupContent=${this.fullBackupContent}
+            gwpAsanMode=${this.gwpAsanMode.ignored("Added in R")}
             hiddenUntilInstalled=${this.hiddenUntilInstalled}
             icon=${this.icon}
             iconRes=${this.iconRes}
             installLocation=${this.installLocation}
+            labelRes=${this.labelRes}
             largestWidthLimitDp=${this.largestWidthLimitDp}
             logo=${this.logo}
             longVersionCode=${this.longVersionCode}
+            ${"".ignored("mHiddenApiPolicy is a private field")}
             manageSpaceActivityName=${this.manageSpaceActivityName}
-            maxAspectRatio.compareTo(that.maxAspectRatio)=${this.maxAspectRatio}
-            metaData=${this.metaData}
-            minAspectRatio.compareTo(that.minAspectRatio)=${this.minAspectRatio}
+            maxAspectRatio=${this.maxAspectRatio}
+            metaData=${this.metaData.dumpToString()}
+            minAspectRatio=${this.minAspectRatio}
             minSdkVersion=${this.minSdkVersion}
             name=${this.name}
             nativeLibraryDir=${this.nativeLibraryDir}
@@ -206,18 +216,27 @@
             permission=${this.permission}
             primaryCpuAbi=${this.primaryCpuAbi}
             privateFlags=${Integer.toBinaryString(this.privateFlags)}
+            processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
+            publicSourceDir=${this.publicSourceDir
+            .ignored("Deferred pre-R, but assigned immediately in R")}
             requiresSmallestWidthDp=${this.requiresSmallestWidthDp}
             resourceDirs=${this.resourceDirs?.contentToString()}
             roundIconRes=${this.roundIconRes}
-            secondaryCpuAbi=${this.secondaryCpuAbi}
-            secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
+            scanPublicSourceDir=${this.scanPublicSourceDir
+            .ignored("Deferred pre-R, but assigned immediately in R")}
+            scanSourceDir=${this.scanSourceDir
+            .ignored("Deferred pre-R, but assigned immediately in R")}
             seInfo=${this.seInfo}
             seInfoUser=${this.seInfoUser}
+            secondaryCpuAbi=${this.secondaryCpuAbi}
+            secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
             sharedLibraryFiles=${this.sharedLibraryFiles?.contentToString()}
             sharedLibraryInfos=${this.sharedLibraryInfos}
             showUserIcon=${this.showUserIcon}
+            sourceDir=${this.sourceDir
+            .ignored("Deferred pre-R, but assigned immediately in R")}
             splitClassLoaderNames=${this.splitClassLoaderNames?.contentToString()}
-            splitDependencies=${this.splitDependencies}
+            splitDependencies=${this.splitDependencies.dumpToString()}
             splitNames=${this.splitNames?.contentToString()}
             splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
             splitSourceDirs=${this.splitSourceDirs?.contentToString()}
@@ -226,8 +245,8 @@
             targetSdkVersion=${this.targetSdkVersion}
             taskAffinity=${this.taskAffinity}
             theme=${this.theme}
-            uid=${this.uid}
             uiOptions=${this.uiOptions}
+            uid=${this.uid}
             versionCode=${this.versionCode}
             volumeUuid=${this.volumeUuid}
             zygotePreloadName=${this.zygotePreloadName}
@@ -241,19 +260,27 @@
             """.trimIndent()
 
     protected fun InstrumentationInfo.dumpToString() = """
+            banner=${this.banner}
             credentialProtectedDataDir=${this.credentialProtectedDataDir}
             dataDir=${this.dataDir}
             deviceProtectedDataDir=${this.deviceProtectedDataDir}
             functionalTest=${this.functionalTest}
             handleProfiling=${this.handleProfiling}
+            icon=${this.icon}
+            labelRes=${this.labelRes}
+            logo=${this.logo}
+            metaData=${this.metaData}
+            name=${this.name}
             nativeLibraryDir=${this.nativeLibraryDir}
+            nonLocalizedLabel=${this.nonLocalizedLabel}
+            packageName=${this.packageName}
             primaryCpuAbi=${this.primaryCpuAbi}
             publicSourceDir=${this.publicSourceDir}
             secondaryCpuAbi=${this.secondaryCpuAbi}
             secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
+            showUserIcon=${this.showUserIcon}
             sourceDir=${this.sourceDir}
-            splitDependencies=${this.splitDependencies.sequence()
-            .map { it.first to it.second?.contentToString() }.joinToString()}
+            splitDependencies=${this.splitDependencies.dumpToString()}
             splitNames=${this.splitNames?.contentToString()}
             splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
             splitSourceDirs=${this.splitSourceDirs?.contentToString()}
@@ -262,25 +289,40 @@
             """.trimIndent()
 
     protected fun ActivityInfo.dumpToString() = """
+            banner=${this.banner}
             colorMode=${this.colorMode}
             configChanges=${this.configChanges}
+            descriptionRes=${this.descriptionRes}
+            directBootAware=${this.directBootAware}
             documentLaunchMode=${this.documentLaunchMode}
+            enabled=${this.enabled}
+            exported=${this.exported}
             flags=${Integer.toBinaryString(this.flags)}
+            icon=${this.icon}
+            labelRes=${this.labelRes}
             launchMode=${this.launchMode}
             launchToken=${this.launchToken}
             lockTaskLaunchMode=${this.lockTaskLaunchMode}
+            logo=${this.logo}
             maxAspectRatio=${this.maxAspectRatio}
             maxRecents=${this.maxRecents}
+            metaData=${this.metaData.dumpToString()}
             minAspectRatio=${this.minAspectRatio}
+            name=${this.name}
+            nonLocalizedLabel=${this.nonLocalizedLabel}
+            packageName=${this.packageName}
             parentActivityName=${this.parentActivityName}
             permission=${this.permission}
-            persistableMode=${this.persistableMode}
-            privateFlags=${Integer.toBinaryString(this.privateFlags)}
+            persistableMode=${this.persistableMode.ignored("Could be dropped pre-R, fixed in R")}
+            privateFlags=${this.privateFlags}
+            processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
             requestedVrComponent=${this.requestedVrComponent}
             resizeMode=${this.resizeMode}
             rotationAnimation=${this.rotationAnimation}
             screenOrientation=${this.screenOrientation}
+            showUserIcon=${this.showUserIcon}
             softInputMode=${this.softInputMode}
+            splitName=${this.splitName}
             targetActivity=${this.targetActivity}
             taskAffinity=${this.taskAffinity}
             theme=${this.theme}
@@ -300,30 +342,77 @@
 
     protected fun PermissionInfo.dumpToString() = """
             backgroundPermission=${this.backgroundPermission}
+            banner=${this.banner}
             descriptionRes=${this.descriptionRes}
             flags=${Integer.toBinaryString(this.flags)}
             group=${this.group}
+            icon=${this.icon}
+            labelRes=${this.labelRes}
+            logo=${this.logo}
+            metaData=${this.metaData.dumpToString()}
+            name=${this.name}
             nonLocalizedDescription=${this.nonLocalizedDescription}
+            nonLocalizedLabel=${this.nonLocalizedLabel}
+            packageName=${this.packageName}
             protectionLevel=${this.protectionLevel}
             requestRes=${this.requestRes}
+            showUserIcon=${this.showUserIcon}
             """.trimIndent()
 
     protected fun ProviderInfo.dumpToString() = """
+            applicationInfo=${this.applicationInfo.ignored("Already checked")}
             authority=${this.authority}
+            banner=${this.banner}
+            descriptionRes=${this.descriptionRes}
+            directBootAware=${this.directBootAware}
+            enabled=${this.enabled}
+            exported=${this.exported}
             flags=${Integer.toBinaryString(this.flags)}
             forceUriPermissions=${this.forceUriPermissions}
             grantUriPermissions=${this.grantUriPermissions}
+            icon=${this.icon}
             initOrder=${this.initOrder}
             isSyncable=${this.isSyncable}
+            labelRes=${this.labelRes}
+            logo=${this.logo}
+            metaData=${this.metaData.dumpToString()}
             multiprocess=${this.multiprocess}
+            name=${this.name}
+            nonLocalizedLabel=${this.nonLocalizedLabel}
+            packageName=${this.packageName}
             pathPermissions=${this.pathPermissions?.joinToString {
         "readPermission=${it.readPermission}\nwritePermission=${it.writePermission}"
     }}
+            processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
             readPermission=${this.readPermission}
+            showUserIcon=${this.showUserIcon}
+            splitName=${this.splitName}
             uriPermissionPatterns=${this.uriPermissionPatterns?.contentToString()}
             writePermission=${this.writePermission}
             """.trimIndent()
 
+    protected fun ServiceInfo.dumpToString() = """
+            applicationInfo=${this.applicationInfo.ignored("Already checked")}
+            banner=${this.banner}
+            descriptionRes=${this.descriptionRes}
+            directBootAware=${this.directBootAware}
+            enabled=${this.enabled}
+            exported=${this.exported}
+            flags=${Integer.toBinaryString(this.flags)}
+            icon=${this.icon}
+            labelRes=${this.labelRes}
+            logo=${this.logo}
+            mForegroundServiceType"${this.mForegroundServiceType}
+            metaData=${this.metaData.dumpToString()}
+            name=${this.name}
+            nonLocalizedLabel=${this.nonLocalizedLabel}
+            packageName=${this.packageName}
+            permission=${this.permission}
+            processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
+            showUserIcon=${this.showUserIcon}
+            splitName=${this.splitName}
+            """.trimIndent()
+
     protected fun ConfigurationInfo.dumpToString() = """
             reqGlEsVersion=${this.reqGlEsVersion}
             reqInputFeatures=${this.reqInputFeatures}
@@ -333,8 +422,10 @@
             """.trimIndent()
 
     protected fun PackageInfo.dumpToString() = """
-            activities=${this.activities?.joinToString { it.dumpToString() }}
-            applicationInfo=${this.applicationInfo.dumpToString()}
+            activities=${this.activities?.joinToString { it.dumpToString() }
+            .ignored("Checked separately in test")}
+            applicationInfo=${this.applicationInfo.dumpToString()
+            .ignored("Checked separately in test")}
             baseRevisionCode=${this.baseRevisionCode}
             compileSdkVersion=${this.compileSdkVersion}
             compileSdkVersionCodename=${this.compileSdkVersionCodename}
@@ -356,15 +447,18 @@
             overlayTarget=${this.overlayTarget}
             packageName=${this.packageName}
             permissions=${this.permissions?.joinToString { it.dumpToString() }}
-            providers=${this.providers?.joinToString { it.dumpToString() }}
-            receivers=${this.receivers?.joinToString { it.dumpToString() }}
+            providers=${this.providers?.joinToString { it.dumpToString() }
+            .ignored("Checked separately in test")}
+            receivers=${this.receivers?.joinToString { it.dumpToString() }
+            .ignored("Checked separately in test")}
             reqFeatures=${this.reqFeatures?.joinToString { it.dumpToString() }}
             requestedPermissions=${this.requestedPermissions?.contentToString()}
             requestedPermissionsFlags=${this.requestedPermissionsFlags?.contentToString()}
             requiredAccountType=${this.requiredAccountType}
             requiredForAllUsers=${this.requiredForAllUsers}
             restrictedAccountType=${this.restrictedAccountType}
-            services=${this.services?.contentToString()}
+            services=${this.services?.joinToString { it.dumpToString() }
+            .ignored("Checked separately in test")}
             sharedUserId=${this.sharedUserId}
             sharedUserLabel=${this.sharedUserLabel}
             signatures=${this.signatures?.joinToString { it.toCharsString() }}
@@ -378,11 +472,17 @@
             versionName=${this.versionName}
             """.trimIndent()
 
-    @Suppress("unused")
-    private fun <T> SparseArray<T>.sequence(): Sequence<Pair<Int, T>> {
-        var index = 0
-        return generateSequence {
-            index++.takeIf { it < size() }?.let { keyAt(it) to valueAt(index) }
+    private fun Bundle?.dumpToString() = this?.keySet()?.associateWith { get(it) }?.toString()
+
+    private fun <T> SparseArray<T>?.dumpToString(): String {
+        if (this == null) {
+            return "EMPTY"
         }
+
+        val list = mutableListOf<Pair<Int, T>>()
+        for (index in (0 until size())) {
+            list += keyAt(index) to valueAt(index)
+        }
+        return list.toString()
     }
 }
diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java
index 752707e..d366efe 100644
--- a/telephony/java/android/telephony/SmsCbMessage.java
+++ b/telephony/java/android/telephony/SmsCbMessage.java
@@ -594,6 +594,7 @@
         SmsCbEtwsInfo etwsInfo = getEtwsWarningInfo();
         if (etwsInfo != null) {
             cv.put(CellBroadcasts.ETWS_WARNING_TYPE, etwsInfo.getWarningType());
+            cv.put(CellBroadcasts.ETWS_IS_PRIMARY, etwsInfo.isPrimary());
         }
 
         SmsCbCmasInfo cmasInfo = getCmasWarningInfo();
@@ -667,9 +668,12 @@
 
         SmsCbEtwsInfo etwsInfo;
         int etwsWarningTypeColumn = cursor.getColumnIndex(CellBroadcasts.ETWS_WARNING_TYPE);
-        if (etwsWarningTypeColumn != -1 && !cursor.isNull(etwsWarningTypeColumn)) {
+        int etwsIsPrimaryColumn = cursor.getColumnIndex(CellBroadcasts.ETWS_IS_PRIMARY);
+        if (etwsWarningTypeColumn != -1 && !cursor.isNull(etwsWarningTypeColumn)
+                && etwsIsPrimaryColumn != -1 && !cursor.isNull(etwsIsPrimaryColumn)) {
             int warningType = cursor.getInt(etwsWarningTypeColumn);
-            etwsInfo = new SmsCbEtwsInfo(warningType, false, false, false, null);
+            boolean isPrimary = cursor.getInt(etwsIsPrimaryColumn) != 0;
+            etwsInfo = new SmsCbEtwsInfo(warningType, false, false, isPrimary, null);
         } else {
             etwsInfo = null;
         }
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 70c5e72..b841921 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -632,7 +632,6 @@
 
     /**
      * @hide
-     * TODO: makes real freq boundaries
      */
     public boolean is24GHz() {
         return ScanResult.is24GHz(mFrequency);
@@ -640,7 +639,6 @@
 
     /**
      * @hide
-     * TODO: makes real freq boundaries
      */
     @UnsupportedAppUsage
     public boolean is5GHz() {
@@ -648,6 +646,13 @@
     }
 
     /**
+     * @hide
+     */
+    public boolean is6GHz() {
+        return ScanResult.is6GHz(mFrequency);
+    }
+
+    /**
      * Record the MAC address of the WLAN interface
      * @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
      * @hide