Merge "Use InteractionJankMonitor to instrument CUJs of NotificationShade"
diff --git a/ApiDocs.bp b/ApiDocs.bp
index c82fee0f..faa0e5d 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -65,7 +65,7 @@
         "test-base/src/**/*.java",
         ":opt-telephony-srcs",
         ":opt-net-voip-srcs",
-        ":art-module-public-api-stubs-source",
+        ":art.module.public.api{.public.stubs.source}",
         ":conscrypt.module.public.api{.public.stubs.source}",
         ":android_icu4j_public_api_files",
         "test-mock/src/**/*.java",
@@ -135,7 +135,7 @@
     ],
     knowntags: [
         "docs/knowntags.txt",
-        ":known-oj-tags",
+        ":art.module.public.api{.doctags}",
     ],
     custom_template: "droiddoc-templates-sdk",
     resourcesdir: "docs/html/reference/images/",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 852fcc6..a3a2094 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -47,7 +47,7 @@
         "core/java/**/*.logtags",
         ":opt-telephony-srcs",
         ":opt-net-voip-srcs",
-        ":art-module-public-api-stubs-source",
+        ":art.module.public.api{.public.stubs.source}",
         ":android_icu4j_public_api_files",
         "**/package.html",
     ],
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
index a701f86..ecd1499 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
@@ -139,7 +139,6 @@
 
         final IntSupplier mViewVisibility;
 
-        int mSeq;
         int mFrameNumber;
         int mFlags;
 
@@ -156,7 +155,7 @@
         void runBenchmark(BenchmarkState state) throws RemoteException {
             final IWindowSession session = WindowManagerGlobal.getWindowSession();
             while (state.keepRunning()) {
-                session.relayout(mWindow, mSeq, mParams, mWidth, mHeight,
+                session.relayout(mWindow, mParams, mWidth, mHeight,
                         mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrames,
                         mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls,
                         mOutSurfaceSize, mOutBlastSurfaceControl);
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
index c52b130..b11d7464 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
@@ -107,7 +107,7 @@
                 final InputChannel inputChannel = new InputChannel();
 
                 long startTime = SystemClock.elapsedRealtimeNanos();
-                session.addToDisplay(this, mSeq, mLayoutParams, View.VISIBLE,
+                session.addToDisplay(this, mLayoutParams, View.VISIBLE,
                         Display.DEFAULT_DISPLAY, mOutFrame, mOutContentInsets, mOutStableInsets,
                         mOutDisplayCutout, inputChannel, mOutInsetsState, mOutControls);
                 final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime;
diff --git a/apex/media/OWNERS b/apex/media/OWNERS
index e83ea3a..ced2fb5 100644
--- a/apex/media/OWNERS
+++ b/apex/media/OWNERS
@@ -1,7 +1,10 @@
 andrewlewis@google.com
 aquilescanta@google.com
 chz@google.com
+hdmoon@google.com
 hkuang@google.com
+jinpark@google.com
+klhyun@google.com
 lnilsson@google.com
 marcone@google.com
 sungsoo@google.com
diff --git a/api/current.txt b/api/current.txt
index b93ffe3..2c2a5a8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6138,6 +6138,7 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.app.PendingIntent> CREATOR;
     field public static final int FLAG_CANCEL_CURRENT = 268435456; // 0x10000000
     field public static final int FLAG_IMMUTABLE = 67108864; // 0x4000000
+    field public static final int FLAG_MUTABLE = 33554432; // 0x2000000
     field public static final int FLAG_NO_CREATE = 536870912; // 0x20000000
     field public static final int FLAG_ONE_SHOT = 1073741824; // 0x40000000
     field public static final int FLAG_UPDATE_CURRENT = 134217728; // 0x8000000
@@ -26359,6 +26360,7 @@
     method public boolean containsKey(String);
     method public int describeContents();
     method public android.graphics.Bitmap getBitmap(String);
+    method @IntRange(from=0) public int getBitmapDimensionLimit();
     method @NonNull public android.media.MediaDescription getDescription();
     method public long getLong(String);
     method public android.media.Rating getRating(String);
@@ -26408,6 +26410,7 @@
     method public android.media.MediaMetadata.Builder putRating(String, android.media.Rating);
     method public android.media.MediaMetadata.Builder putString(String, String);
     method public android.media.MediaMetadata.Builder putText(String, CharSequence);
+    method @NonNull public android.media.MediaMetadata.Builder setBitmapDimensionLimit(int);
   }
 
   @Deprecated public abstract class MediaMetadataEditor {
@@ -46797,6 +46800,7 @@
     field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
     field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool";
     field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
+    field public static final String KEY_CARRIER_USSD_METHOD_INT = "carrier_ussd_method_int";
     field public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL = "carrier_ut_provisioning_required_bool";
     field public static final String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
     field public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL = "carrier_volte_override_wfc_provisioning_bool";
@@ -46991,6 +46995,10 @@
     field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
     field public static final int SERVICE_CLASS_NONE = 0; // 0x0
     field public static final int SERVICE_CLASS_VOICE = 1; // 0x1
+    field public static final int USSD_OVER_CS_ONLY = 2; // 0x2
+    field public static final int USSD_OVER_CS_PREFERRED = 0; // 0x0
+    field public static final int USSD_OVER_IMS_ONLY = 3; // 0x3
+    field public static final int USSD_OVER_IMS_PREFERRED = 1; // 0x1
   }
 
   public static final class CarrierConfigManager.Apn {
@@ -53644,6 +53652,33 @@
     field public int toolType;
   }
 
+  public interface OnReceiveContentCallback<T extends android.view.View> {
+    method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull T);
+    method public boolean onReceiveContent(@NonNull T, @NonNull android.view.OnReceiveContentCallback.Payload);
+  }
+
+  public static final class OnReceiveContentCallback.Payload {
+    method @NonNull public android.content.ClipData getClip();
+    method @Nullable public android.os.Bundle getExtras();
+    method public int getFlags();
+    method @Nullable public android.net.Uri getLinkUri();
+    method public int getSource();
+    field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
+    field public static final int SOURCE_AUTOFILL = 3; // 0x3
+    field public static final int SOURCE_CLIPBOARD = 0; // 0x0
+    field public static final int SOURCE_DRAG_AND_DROP = 2; // 0x2
+    field public static final int SOURCE_INPUT_METHOD = 1; // 0x1
+    field public static final int SOURCE_PROCESS_TEXT = 4; // 0x4
+  }
+
+  public static final class OnReceiveContentCallback.Payload.Builder {
+    ctor public OnReceiveContentCallback.Payload.Builder(@NonNull android.content.ClipData, int);
+    method @NonNull public android.view.OnReceiveContentCallback.Payload build();
+    method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setExtras(@Nullable android.os.Bundle);
+    method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setFlags(int);
+    method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setLinkUri(@Nullable android.net.Uri);
+  }
+
   public abstract class OrientationEventListener {
     ctor public OrientationEventListener(android.content.Context);
     ctor public OrientationEventListener(android.content.Context, int);
@@ -54195,6 +54230,7 @@
     method @IdRes public int getNextFocusRightId();
     method @IdRes public int getNextFocusUpId();
     method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
+    method @Nullable public android.view.OnReceiveContentCallback<? extends android.view.View> getOnReceiveContentCallback();
     method @ColorInt public int getOutlineAmbientShadowColor();
     method public android.view.ViewOutlineProvider getOutlineProvider();
     method @ColorInt public int getOutlineSpotShadowColor();
@@ -54546,6 +54582,7 @@
     method public void setOnHoverListener(android.view.View.OnHoverListener);
     method public void setOnKeyListener(android.view.View.OnKeyListener);
     method public void setOnLongClickListener(@Nullable android.view.View.OnLongClickListener);
+    method public void setOnReceiveContentCallback(@Nullable android.view.OnReceiveContentCallback<? extends android.view.View>);
     method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener);
     method @Deprecated public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
     method public void setOnTouchListener(android.view.View.OnTouchListener);
@@ -60808,17 +60845,6 @@
     method public android.view.View newGroupView(android.content.Context, android.database.Cursor, boolean, android.view.ViewGroup);
   }
 
-  public interface RichContentReceiver<T extends android.view.View> {
-    method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes();
-    method public boolean onReceive(@NonNull T, @NonNull android.content.ClipData, int, int);
-    field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
-    field public static final int SOURCE_AUTOFILL = 3; // 0x3
-    field public static final int SOURCE_CLIPBOARD = 0; // 0x0
-    field public static final int SOURCE_DRAG_AND_DROP = 2; // 0x2
-    field public static final int SOURCE_INPUT_METHOD = 1; // 0x1
-    field public static final int SOURCE_PROCESS_TEXT = 4; // 0x4
-  }
-
   public class ScrollView extends android.widget.FrameLayout {
     ctor public ScrollView(android.content.Context);
     ctor public ScrollView(android.content.Context, android.util.AttributeSet);
@@ -61373,10 +61399,10 @@
     method public int getMinWidth();
     method public final android.text.method.MovementMethod getMovementMethod();
     method public int getOffsetForPosition(float, float);
+    method @Nullable public android.view.OnReceiveContentCallback<android.widget.TextView> getOnReceiveContentCallback();
     method public android.text.TextPaint getPaint();
     method public int getPaintFlags();
     method public String getPrivateImeOptions();
-    method @NonNull public android.widget.RichContentReceiver<android.widget.TextView> getRichContentReceiver();
     method public int getSelectionEnd();
     method public int getSelectionStart();
     method @ColorInt public int getShadowColor();
@@ -61504,7 +61530,6 @@
     method public void setPaintFlags(int);
     method public void setPrivateImeOptions(String);
     method public void setRawInputType(int);
-    method public void setRichContentReceiver(@NonNull android.widget.RichContentReceiver<android.widget.TextView>);
     method public void setScroller(android.widget.Scroller);
     method public void setSelectAllOnFocus(boolean);
     method public void setShadowLayer(float, float, float, int);
@@ -61545,7 +61570,6 @@
     method public void setWidth(int);
     field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
     field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
-    field @NonNull public static final android.widget.RichContentReceiver<android.widget.TextView> DEFAULT_RICH_CONTENT_RECEIVER;
   }
 
   public enum TextView.BufferType {
@@ -61562,6 +61586,12 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.widget.TextView.SavedState> CREATOR;
   }
 
+  public class TextViewOnReceiveContentCallback implements android.view.OnReceiveContentCallback<android.widget.TextView> {
+    ctor public TextViewOnReceiveContentCallback();
+    method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull android.widget.TextView);
+    method public boolean onReceiveContent(@NonNull android.widget.TextView, @NonNull android.view.OnReceiveContentCallback.Payload);
+  }
+
   public interface ThemedSpinnerAdapter extends android.widget.SpinnerAdapter {
     method @Nullable public android.content.res.Resources.Theme getDropDownViewTheme();
     method public void setDropDownViewTheme(@Nullable android.content.res.Resources.Theme);
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index eb2f264..4a7c121 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -53,10 +53,6 @@
     field public static final int FLAG_FROM_KEY = 4096; // 0x1000
   }
 
-  public static final class MediaMetadata.Builder {
-    ctor public MediaMetadata.Builder(@NonNull android.media.MediaMetadata, @IntRange(from=1) int);
-  }
-
   public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
     ctor public MediaParceledListSlice(@NonNull java.util.List<T>);
     method public int describeContents();
diff --git a/api/test-current.txt b/api/test-current.txt
index 3a4d101..8e437f1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -83,6 +83,7 @@
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
     method public long getTotalRam();
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
+    method @RequiresPermission("android.permission.INJECT_EVENTS") public void holdLock(int);
     method public static boolean isHighEndGfx();
     method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void killProcessesWhenImperceptible(@NonNull int[], @NonNull String);
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
@@ -1023,6 +1024,7 @@
     method @Nullable public String getSystemTextClassifierPackageName();
     method @Nullable public String getWellbeingPackageName();
     method @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS") public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
+    method @RequiresPermission("android.permission.INJECT_EVENTS") public void holdLock(int);
     method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
     method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull String);
@@ -5289,6 +5291,7 @@
   }
 
   public interface WindowManager extends android.view.ViewManager {
+    method @RequiresPermission("android.permission.INJECT_EVENTS") public default void holdLock(int);
     method public default void setShouldShowIme(int, boolean);
     method public default void setShouldShowSystemDecors(int, boolean);
     method public default void setShouldShowWithInsecureKeyguard(int, boolean);
@@ -5581,6 +5584,11 @@
     method public void disableClockTick();
   }
 
+  @android.widget.RemoteViews.RemoteView public class TextView extends android.view.View implements android.view.ViewTreeObserver.OnPreDrawListener {
+    method public void onActivityResult(int, int, @Nullable android.content.Intent);
+    field public static final int PROCESS_TEXT_REQUEST_CODE = 100; // 0x64
+  }
+
   public class TimePicker extends android.widget.FrameLayout {
     method public android.view.View getAmView();
     method public android.view.View getHourView();
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 4ccc7e6..c327d1a 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -499,7 +499,7 @@
     }
 
     // Pulled events will start at field 10000.
-    // Next: 10084
+    // Next: 10087
     oneof pulled {
         WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
         WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
@@ -598,6 +598,7 @@
         DNDModeProto dnd_mode_rule = 10084 [(module) = "framework"];
         GeneralExternalStorageAccessStats general_external_storage_access_stats =
             10085 [(module) = "mediaprovider"];
+        IncomingSms incoming_sms = 10086 [(module) = "telephony"];
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP.
@@ -10461,6 +10462,59 @@
 }
 
 /**
+ * Pulls information for a single incoming SMS.
+ *
+ * Each pull creates multiple atoms, one for each SMS. The sequence is randomized when pulled.
+ *
+ * Pulled from:
+ *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+ */
+message IncomingSms {
+    // Format of the SMS (3GPP or 3GPP2).
+    optional android.telephony.SmsFormatEnum sms_format = 1;
+
+    // Technology of the SMS (CS or IMS).
+    optional android.telephony.SmsTechEnum sms_tech = 2;
+
+    // Radio access technology (RAT) used for the SMS. It can be IWLAN in case of IMS.
+    optional android.telephony.NetworkTypeEnum rat = 3;
+
+    // Type the SMS.
+    optional android.telephony.SmsTypeEnum sms_type = 4;
+
+    // Number of total parts.
+    optional int32 total_parts = 5;
+
+    // Number of received parts (if smaller than total parts, the SMS was dropped).
+    optional int32 received_parts = 6;
+
+    // Indicates if the incoming SMS was blocked.
+    optional bool blocked = 7;
+
+    // Indicate a specific error handling the SMS
+    optional android.telephony.SmsIncomingErrorEnum error = 8;
+
+    // Whether the SMS was received while roaming.
+    optional bool is_roaming = 9;
+
+    // Index of the SIM is used, 0 for single-SIM devices.
+    optional int32 sim_slot_index = 10;
+
+    // Whether the device was in multi-SIM mode (with multiple active SIM profiles).
+    optional bool is_multi_sim = 11;
+
+    // Whether the message was received with an eSIM profile.
+    optional bool is_esim = 12;
+
+    // Carrier ID of the SIM card used for the SMS.
+    // See https://source.android.com/devices/tech/config/carrierid.
+    optional int32 carrier_id = 13;
+
+    // Random message ID.
+    optional int64 message_id = 14;
+}
+
+/**
  * Logs gnss stats from location service provider
  *
  * Pulled from:
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 70ca49d..e75d2f6 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4796,4 +4796,19 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Holds the AM lock for the specified amount of milliseconds.
+     * This is intended for use by the tests that need to imitate lock contention.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.INJECT_EVENTS)
+    public void holdLock(int durationMs) {
+        try {
+            getService().holdLock(durationMs);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 95bbebe..1a4db4e 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -696,4 +696,10 @@
      * @param enable set it to true to enable the app freezer, false to disable it.
      */
     boolean enableAppFreezer(in boolean enable);
+
+    /**
+     * Holds the AM lock for the specified amount of milliseconds.
+     * This is intended for use by the tests that need to imitate lock contention.
+     */
+    void holdLock(in int durationMs);
 }
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index cd352e1..8e3ee0c 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -19,12 +19,16 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentSender;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -35,6 +39,7 @@
 import android.os.UserHandle;
 import android.util.AndroidException;
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.os.IResultReceiver;
@@ -102,11 +107,20 @@
  * FLAG_ONE_SHOT, <b>both</b> FLAG_ONE_SHOT and FLAG_NO_CREATE need to be supplied.
  */
 public final class PendingIntent implements Parcelable {
+    private static final String TAG = "PendingIntent";
     private final IIntentSender mTarget;
     private IResultReceiver mCancelReceiver;
     private IBinder mWhitelistToken;
     private ArraySet<CancelListener> mCancelListeners;
 
+    /**
+     * It is now required to specify either {@link #FLAG_IMMUTABLE}
+     * or {@link #FLAG_MUTABLE} when creating a PendingIntent.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.R)
+    static final long PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED = 160794467L;
+
     /** @hide */
     @IntDef(flag = true,
             value = {
@@ -115,6 +129,7 @@
                     FLAG_CANCEL_CURRENT,
                     FLAG_UPDATE_CURRENT,
                     FLAG_IMMUTABLE,
+                    FLAG_MUTABLE,
 
                     Intent.FILL_IN_ACTION,
                     Intent.FILL_IN_DATA,
@@ -175,6 +190,20 @@
     public static final int FLAG_IMMUTABLE = 1<<26;
 
     /**
+     * Flag indicating that the created PendingIntent should be mutable.
+     * This flag cannot be combined with {@link #FLAG_IMMUTABLE}. <p>Up until
+     * {@link android.os.Build.VERSION_CODES#R}, PendingIntents are assumed to
+     * be mutable by default, unless {@link #FLAG_IMMUTABLE} is set. Starting
+     * with {@link android.os.Build.VERSION_CODES#S}, it will be required to
+     * explicitly specify the mutability of PendingIntents on creation with
+     * either (@link #FLAG_IMMUTABLE} or {@link #FLAG_MUTABLE}. It is strongly
+     * recommended to use {@link #FLAG_IMMUTABLE} when creating a
+     * PendingIntent. {@link #FLAG_MUTABLE} should only be used when some
+     * functionality relies on modifying the underlying intent.
+     */
+    public static final int FLAG_MUTABLE = 1<<25;
+
+    /**
      * Exception thrown when trying to send through a PendingIntent that
      * has been canceled or is otherwise no longer able to execute the request.
      */
@@ -286,6 +315,24 @@
         sOnMarshaledListener.set(listener);
     }
 
+    private static void checkFlags(int flags, String packageName) {
+        final boolean flagImmutableSet = (flags & PendingIntent.FLAG_IMMUTABLE) != 0;
+        final boolean flagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0;
+        String msg = packageName + ": Targeting S+ (version " + Build.VERSION_CODES.S
+                    + " and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE"
+                    + " be specified when creating a PendingIntent";
+
+        if (flagImmutableSet && flagMutableSet) {
+            throw new IllegalArgumentException(
+                "Cannot set both FLAG_IMMUTABLE and FLAG_MUTABLE for PendingIntent");
+        }
+
+        if (Compatibility.isChangeEnabled(PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED)
+                && !flagImmutableSet && !flagMutableSet) {
+            Log.e(TAG, msg);
+        }
+    }
+
     /**
      * Retrieve a PendingIntent that will start a new activity, like calling
      * {@link Context#startActivity(Intent) Context.startActivity(Intent)}.
@@ -350,6 +397,7 @@
         String packageName = context.getPackageName();
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
+        checkFlags(flags, packageName);
         try {
             intent.migrateExtraStreamToClipData(context);
             intent.prepareToLeaveProcess(context);
@@ -376,6 +424,7 @@
         String packageName = context.getPackageName();
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
+        checkFlags(flags, packageName);
         try {
             intent.migrateExtraStreamToClipData(context);
             intent.prepareToLeaveProcess(context);
@@ -495,6 +544,7 @@
             intents[i].prepareToLeaveProcess(context);
             resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
         }
+        checkFlags(flags, packageName);
         try {
             IIntentSender target =
                 ActivityManager.getService().getIntentSenderWithFeature(
@@ -521,6 +571,7 @@
             intents[i].prepareToLeaveProcess(context);
             resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
         }
+        checkFlags(flags, packageName);
         try {
             IIntentSender target =
                 ActivityManager.getService().getIntentSenderWithFeature(
@@ -572,6 +623,7 @@
         String packageName = context.getPackageName();
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
+        checkFlags(flags, packageName);
         try {
             intent.prepareToLeaveProcess(context);
             IIntentSender target =
@@ -651,6 +703,7 @@
         String packageName = context.getPackageName();
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
+        checkFlags(flags, packageName);
         try {
             intent.prepareToLeaveProcess(context);
             IIntentSender target =
diff --git a/core/java/android/app/people/IPeopleManager.aidl b/core/java/android/app/people/IPeopleManager.aidl
index 61dac0d..c547ef1 100644
--- a/core/java/android/app/people/IPeopleManager.aidl
+++ b/core/java/android/app/people/IPeopleManager.aidl
@@ -39,4 +39,10 @@
 
     /** Removes all the recent conversations and uncaches their cached shortcuts. */
     void removeAllRecentConversations();
+
+    /**
+     * Returns the last interaction with the specified conversation. If the
+     * conversation can't be found or no interactions have been recorded, returns 0L.
+     */
+    long getLastInteraction(in String packageName, int userId, in String shortcutId);
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 24282365..ba894ae 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -795,4 +795,6 @@
     boolean isAutoRevokeWhitelisted(String packageName);
 
     void grantImplicitAccess(int queryingUid, String visibleAuthority);
+
+    void holdLock(in int durationMs);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 4eec56c..79e23b3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -8305,4 +8305,19 @@
     public static void uncorkPackageInfoCache() {
         PropertyInvalidatedCache.uncorkInvalidations(PermissionManager.CACHE_KEY_PACKAGE_INFO);
     }
+
+    /**
+     * Holds the PM lock for the specified amount of milliseconds.
+     * Intended for use by the tests that need to imitate lock contention.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.INJECT_EVENTS)
+    public void holdLock(int durationMs) {
+        try {
+            ActivityThread.getPackageManager().holdLock(durationMs);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 1061121..0d0bfb3 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2175,10 +2175,8 @@
 
     /**
      * <p>The desired zoom ratio</p>
-     * <p>Instead of using {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} with dual purposes of crop and zoom, the
-     * application can now choose to use this tag to specify the desired zoom level. The
-     * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} can still be used to specify the horizontal or vertical
-     * crop to achieve aspect ratios different than the native camera sensor.</p>
+     * <p>Instead of using {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} for zoom, the application can now choose to
+     * use this tag to specify the desired zoom level.</p>
      * <p>By using this control, the application gains a simpler way to control zoom, which can
      * be a combination of optical and digital zoom. For example, a multi-camera system may
      * contain more than one lens with different focal lengths, and the user can use optical
@@ -2860,11 +2858,18 @@
      * respectively.</p>
      * <p>The camera device may adjust the crop region to account for rounding and other hardware
      * requirements; the final crop region used will be included in the output capture result.</p>
+     * <p>The camera sensor output aspect ratio depends on factors such as output stream
+     * combination and {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange}, and shouldn't be adjusted by using
+     * this control. And the camera device will treat different camera sensor output sizes
+     * (potentially with in-sensor crop) as the same crop of
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}. As a result, the application shouldn't assume the
+     * maximum crop region always maps to the same aspect ratio or field of view for the
+     * sensor output.</p>
      * <p>Starting from API level 30, it's strongly recommended to use {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}
      * to take advantage of better support for zoom with logical multi-camera. The benefits
      * include better precision with optical-digital zoom combination, and ability to do
      * zoom-out from 1.0x. When using {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for zoom, the crop region in
-     * the capture request must be either letterboxing or pillarboxing (but not both). The
+     * the capture request should be left as the default activeArray size. The
      * coordinate system is post-zoom, meaning that the activeArraySize or
      * preCorrectionActiveArraySize covers the camera device's field of view "after" zoom.  See
      * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details.</p>
@@ -2874,6 +2879,7 @@
      * capability and mode</p>
      * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE
      * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 29a53fb..8cfa086 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2405,10 +2405,8 @@
 
     /**
      * <p>The desired zoom ratio</p>
-     * <p>Instead of using {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} with dual purposes of crop and zoom, the
-     * application can now choose to use this tag to specify the desired zoom level. The
-     * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} can still be used to specify the horizontal or vertical
-     * crop to achieve aspect ratios different than the native camera sensor.</p>
+     * <p>Instead of using {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} for zoom, the application can now choose to
+     * use this tag to specify the desired zoom level.</p>
      * <p>By using this control, the application gains a simpler way to control zoom, which can
      * be a combination of optical and digital zoom. For example, a multi-camera system may
      * contain more than one lens with different focal lengths, and the user can use optical
@@ -3506,11 +3504,18 @@
      * respectively.</p>
      * <p>The camera device may adjust the crop region to account for rounding and other hardware
      * requirements; the final crop region used will be included in the output capture result.</p>
+     * <p>The camera sensor output aspect ratio depends on factors such as output stream
+     * combination and {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange}, and shouldn't be adjusted by using
+     * this control. And the camera device will treat different camera sensor output sizes
+     * (potentially with in-sensor crop) as the same crop of
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}. As a result, the application shouldn't assume the
+     * maximum crop region always maps to the same aspect ratio or field of view for the
+     * sensor output.</p>
      * <p>Starting from API level 30, it's strongly recommended to use {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}
      * to take advantage of better support for zoom with logical multi-camera. The benefits
      * include better precision with optical-digital zoom combination, and ability to do
      * zoom-out from 1.0x. When using {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for zoom, the crop region in
-     * the capture request must be either letterboxing or pillarboxing (but not both). The
+     * the capture request should be left as the default activeArray size. The
      * coordinate system is post-zoom, meaning that the activeArraySize or
      * preCorrectionActiveArraySize covers the camera device's field of view "after" zoom.  See
      * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details.</p>
@@ -3520,6 +3525,7 @@
      * capability and mode</p>
      * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE
      * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index c12bb39..997efbe 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -746,7 +746,7 @@
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
-    public void setUdfpsOverlayController(IUdfpsOverlayController controller) {
+    public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) {
         if (mService == null) {
             Slog.w(TAG, "setUdfpsOverlayController: no fingerprint service");
             return;
@@ -763,14 +763,14 @@
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
-    public void onFingerDown(int x, int y, float minor, float major) {
+    public void onFingerDown(int sensorId, int x, int y, float minor, float major) {
         if (mService == null) {
             Slog.w(TAG, "onFingerDown: no fingerprint service");
             return;
         }
 
         try {
-            mService.onFingerDown(x, y, minor, major);
+            mService.onFingerDown(sensorId, x, y, minor, major);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -780,14 +780,14 @@
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
-    public void onFingerUp() {
+    public void onFingerUp(int sensorId) {
         if (mService == null) {
             Slog.w(TAG, "onFingerDown: no fingerprint service");
             return;
         }
 
         try {
-            mService.onFingerUp();
+            mService.onFingerUp(sensorId);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java b/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
index 718141a..d26346c 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
@@ -18,9 +18,7 @@
 
 import android.annotation.IntDef;
 import android.hardware.biometrics.SensorProperties;
-import android.hardware.face.FaceSensorProperties;
 import android.os.Parcel;
-import android.os.Parcelable;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index cc2b520..68013ea 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -121,10 +121,10 @@
     void initializeConfiguration(int sensorId, int strength);
 
     // Notifies about a finger touching the sensor area.
-    void onFingerDown(int x, int y, float minor, float major);
+    void onFingerDown(int sensorId, int x, int y, float minor, float major);
 
     // Notifies about a finger leaving the sensor area.
-    void onFingerUp();
+    void onFingerUp(int sensorId);
 
     // Sets the controller for managing the UDFPS overlay.
     void setUdfpsOverlayController(in IUdfpsOverlayController controller);
diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
index a57726c..58b7046 100644
--- a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
+++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
@@ -21,11 +21,11 @@
  */
 oneway interface IUdfpsOverlayController {
     // Shows the overlay.
-    void showUdfpsOverlay();
+    void showUdfpsOverlay(int sensorId);
 
     // Hides the overlay.
-    void hideUdfpsOverlay();
+    void hideUdfpsOverlay(int sensorId);
 
     // Shows debug messages on the UDFPS overlay.
-    void setDebugMessage(String message);
+    void setDebugMessage(int sensorId, String message);
 }
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 651494d..cad103e9 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -21,13 +21,14 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.LinkPropertiesUtils;
-import android.net.util.LinkPropertiesUtils.CompareResult;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import com.android.net.module.util.LinkPropertiesUtils;
+import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
+
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 0eb3c1e..51c5a50 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -20,12 +20,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.MacAddressUtils;
 import android.net.wifi.WifiInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import com.android.internal.util.Preconditions;
+import com.android.net.module.util.MacAddressUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 9876076..a8b45e9 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -22,11 +22,12 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.NetUtils;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.net.module.util.NetUtils;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.net.Inet4Address;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index fdbf79a..d889b155 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -21,6 +21,7 @@
 import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.job.JobParameters;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -2889,14 +2890,17 @@
 
     /**
      * Returns the approximate CPU time (in microseconds) spent by the system server handling
-     * incoming service calls from apps.
+     * incoming service calls from apps.  The result is returned as an array of longs,
+     * organized as a sequence like this:
+     * <pre>
+     *     cluster1-speeed1, cluster1-speed2, ..., cluster2-speed1, cluster2-speed2, ...
+     * </pre>
      *
-     * @param cluster the index of the CPU cluster.
-     * @param step the index of the CPU speed. This is not the actual speed of the CPU.
      * @see com.android.internal.os.PowerProfile#getNumCpuClusters()
      * @see com.android.internal.os.PowerProfile#getNumSpeedStepsInCpuCluster(int)
      */
-    public abstract long getSystemServiceTimeAtCpuSpeed(int cluster, int step);
+    @Nullable
+    public abstract long[] getSystemServiceTimeAtCpuSpeeds();
 
     /**
      * Returns the total, last, or current battery uptime in microseconds.
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 52ee04c..54f80c6 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -267,6 +267,7 @@
         }
         if (appInfo == null) {
             Log.w(TAG, "Debug layer app '" + packageName + "' not installed");
+            return "";
         }
 
         final String abi = chooseAbi(appInfo);
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index a92d91b..e996809 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -98,6 +98,8 @@
     boolean isAmbientDisplaySuppressedForToken(String token);
     // returns whether ambient display is suppressed by any app with any token.
     boolean isAmbientDisplaySuppressed();
+    // returns whether ambient display is suppressed by the given app with the given token.
+    boolean isAmbientDisplaySuppressedForTokenByApp(String token, int appUid);
 
     // Forces the system to suspend even if there are held wakelocks.
     boolean forceSuspend();
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 3265829..50f0c28 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -2191,6 +2191,27 @@
     }
 
     /**
+     * Returns true if ambient display is suppressed by the given {@code appUid} with the given
+     * {@code token}.
+     *
+     * <p>This method will return false if {@link #isAmbientDisplayAvailable()} is false.
+     *
+     * @param token The identifier of the ambient display suppression.
+     * @param appUid The uid of the app that suppressed ambient display.
+     * @hide
+     */
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.READ_DREAM_STATE,
+            android.Manifest.permission.READ_DREAM_SUPPRESSION })
+    public boolean isAmbientDisplaySuppressedForTokenByApp(@NonNull String token, int appUid) {
+        try {
+            return mService.isAmbientDisplaySuppressedForTokenByApp(token, appUid);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns the reason the phone was last shutdown. Calling app must have the
      * {@link android.Manifest.permission#DEVICE_POWER} permission to request this information.
      * @return Reason for shutdown as an int, {@link #SHUTDOWN_REASON_UNKNOWN} if the file could
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 07867e2..e4d1fab 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14464,6 +14464,15 @@
          */
         public static final String NR_NSA_TRACKING_SCREEN_OFF_MODE =
                 "nr_nsa_tracking_screen_off_mode";
+
+        /**
+         * Whether to show People Space.
+         * Values are:
+         * 0: Disabled (default)
+         * 1: Enabled
+         * @hide
+         */
+        public static final String SHOW_PEOPLE_SPACE = "show_people_space";
     }
 
     /**
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 19860eb..0f46ffc 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -879,7 +879,7 @@
                                 com.android.internal.R.style.Animation_Wallpaper;
                         InputChannel inputChannel = new InputChannel();
 
-                        if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,
+                        if (mSession.addToDisplay(mWindow, mLayout, View.VISIBLE,
                                 mDisplay.getDisplayId(), mWinFrames.frame, mWinFrames.contentInsets,
                                 mWinFrames.stableInsets, mWinFrames.displayCutout, inputChannel,
                                 mInsetsState, mTempControls) < 0) {
@@ -903,7 +903,7 @@
                     }
 
                     final int relayoutResult = mSession.relayout(
-                        mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
+                            mWindow, mLayout, mWidth, mHeight,
                             View.VISIBLE, 0, -1, mWinFrames, mMergedConfiguration, mSurfaceControl,
                             mInsetsState, mTempControls, mSurfaceSize, mTmpSurfaceControl);
                     if (mSurfaceControl.isValid()) {
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 2ded473..7a117f1 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -227,7 +227,7 @@
      * @param level The level to check.
      * @return Whether or not that this is allowed to be logged.
      * @throws IllegalArgumentException is thrown if the tag.length() > 23
-     *         for Nougat (7.0) releases (API <= 23) and prior, there is no
+     *         for Nougat (7.0) and prior releases (API <= 25), there is no
      *         tag limit of concern after this API level.
      */
     @FastNative
diff --git a/core/java/android/util/imetracing/ImeTracing.java b/core/java/android/util/imetracing/ImeTracing.java
new file mode 100644
index 0000000..865d560
--- /dev/null
+++ b/core/java/android/util/imetracing/ImeTracing.java
@@ -0,0 +1,114 @@
+/*
+ * 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.util.imetracing;
+
+import android.app.ActivityThread;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.ShellCommand;
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.view.IInputMethodManager;
+
+/**
+ *
+ * An abstract class that declares the methods for ime trace related operations - enable trace,
+ * schedule trace and add new trace to buffer. Both the client and server side classes can use
+ * it by getting an implementation through {@link ImeTracing#getInstance()}.
+ *
+ * @hide
+ */
+public abstract class ImeTracing {
+
+    static final String TAG = "imeTracing";
+    public static final String PROTO_ARG = "--proto-com-android-imetracing";
+
+    private static ImeTracing sInstance;
+    static boolean sEnabled = false;
+    IInputMethodManager mService;
+
+    ImeTracing() throws ServiceNotFoundException {
+        mService = IInputMethodManager.Stub.asInterface(
+                ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE));
+    }
+
+    /**
+     * Returns an instance of {@link ImeTracingServerImpl} when called from a server side class
+     * and an instance of {@link ImeTracingClientImpl} when called from a client side class.
+     * Useful to schedule a dump for next frame or save a dump when certain methods are called.
+     *
+     * @return Instance of one of the children classes of {@link ImeTracing}
+     */
+    public static ImeTracing getInstance() {
+        if (sInstance == null) {
+            try {
+                sInstance = isSystemProcess()
+                        ? new ImeTracingServerImpl() : new ImeTracingClientImpl();
+            } catch (RemoteException | ServiceNotFoundException e) {
+                Log.e(TAG, "Exception while creating ImeTracing instance", e);
+            }
+        }
+        return sInstance;
+    }
+
+    /**
+     * Sends request to start proto dump to {@link ImeTracingServerImpl} when called from a
+     * server process and to {@link ImeTracingClientImpl} when called from a client process.
+     */
+    public abstract void triggerDump();
+
+    /**
+     * @param proto dump to be added to the buffer
+     */
+    public abstract void addToBuffer(ProtoOutputStream proto);
+
+    /**
+     * @param shell The shell command to process
+     * @return {@code 0} if the command was successfully processed, {@code -1} otherwise
+     */
+    public abstract int onShellCommand(ShellCommand shell);
+
+    /**
+     * Sets whether ime tracing is enabled.
+     *
+     * @param enabled Tells whether ime tracing should be enabled or disabled.
+     */
+    public void setEnabled(boolean enabled) {
+        sEnabled = enabled;
+    }
+
+    /**
+     * @return {@code true} if dumping is enabled, {@code false} otherwise.
+     */
+    public boolean isEnabled() {
+        return sEnabled;
+    }
+
+    /**
+     * @return {@code true} if tracing is available, {@code false} otherwise.
+     */
+    public boolean isAvailable() {
+        return mService != null;
+    }
+
+    private static boolean isSystemProcess() {
+        return ActivityThread.isSystem();
+    }
+}
diff --git a/core/java/android/util/imetracing/ImeTracingClientImpl.java b/core/java/android/util/imetracing/ImeTracingClientImpl.java
new file mode 100644
index 0000000..e5d7d338
--- /dev/null
+++ b/core/java/android/util/imetracing/ImeTracingClientImpl.java
@@ -0,0 +1,71 @@
+/*
+ * 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.util.imetracing;
+
+import android.os.RemoteException;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.ShellCommand;
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+import android.view.inputmethod.InputMethodManager;
+
+/**
+ * @hide
+ */
+class ImeTracingClientImpl extends ImeTracing {
+
+    private boolean mDumpInProgress;
+    private final Object mDumpInProgressLock = new Object();
+
+    ImeTracingClientImpl() throws ServiceNotFoundException, RemoteException {
+        sEnabled = mService.isImeTraceEnabled();
+    }
+
+    @Override
+    public void addToBuffer(ProtoOutputStream proto) {
+    }
+
+    @Override
+    public int onShellCommand(ShellCommand shell) {
+        return -1;
+    }
+
+    @Override
+    public void triggerDump() {
+        if (isAvailable() && isEnabled()) {
+            boolean doDump = false;
+            synchronized (mDumpInProgressLock) {
+                if (!mDumpInProgress) {
+                    mDumpInProgress = true;
+                    doDump = true;
+                }
+            }
+
+            if (doDump) {
+                try {
+                    ProtoOutputStream proto = new ProtoOutputStream();
+                    InputMethodManager.dumpProto(proto);
+                    mService.startProtoDump(proto.getBytes());
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Exception while sending ime-related client dump to server", e);
+                } finally {
+                    mDumpInProgress = false;
+                }
+            }
+        }
+    }
+}
diff --git a/core/java/android/util/imetracing/ImeTracingServerImpl.java b/core/java/android/util/imetracing/ImeTracingServerImpl.java
new file mode 100644
index 0000000..350cf57
--- /dev/null
+++ b/core/java/android/util/imetracing/ImeTracingServerImpl.java
@@ -0,0 +1,154 @@
+/*
+ * 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.util.imetracing;
+
+import static android.os.Build.IS_USER;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorTraceFileProto.MAGIC_NUMBER;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorTraceFileProto.MAGIC_NUMBER_H;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorTraceFileProto.MAGIC_NUMBER_L;
+
+import android.os.RemoteException;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.ShellCommand;
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.TraceBuffer;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @hide
+ */
+class ImeTracingServerImpl extends ImeTracing {
+    private static final String TRACE_FILENAME = "/data/misc/wmtrace/ime_trace.pb";
+    private static final int BUFFER_CAPACITY = 4096 * 1024;
+
+    // Needed for winscope to auto-detect the dump type. Explained further in
+    // core.proto.android.view.inputmethod.inputmethodeditortrace.proto
+    private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+    private final TraceBuffer mBuffer;
+    private final File mTraceFile;
+    private final Object mEnabledLock = new Object();
+
+    ImeTracingServerImpl() throws ServiceNotFoundException {
+        mBuffer = new TraceBuffer<>(BUFFER_CAPACITY);
+        mTraceFile = new File(TRACE_FILENAME);
+    }
+
+    /**
+     * The provided dump is added to the current dump buffer {@link ImeTracingServerImpl#mBuffer}.
+     *
+     * @param proto dump to be added to the buffer
+     */
+    @Override
+    public void addToBuffer(ProtoOutputStream proto) {
+        if (isAvailable() && isEnabled()) {
+            mBuffer.add(proto);
+        }
+    }
+
+    /**
+     * Responds to a shell command of the format "adb shell cmd input_method ime tracing <command>"
+     *
+     * @param shell The shell command to process
+     * @return {@code 0} if the command was valid and successfully processed, {@code -1} otherwise
+     */
+    @Override
+    public int onShellCommand(ShellCommand shell) {
+        PrintWriter pw = shell.getOutPrintWriter();
+        String cmd = shell.getNextArgRequired();
+        switch (cmd) {
+            case "start":
+                startTrace(pw);
+                return 0;
+            case "stop":
+                stopTrace(pw);
+                return 0;
+            default:
+                pw.println("Unknown command: " + cmd);
+                pw.println("Input method trace options:");
+                pw.println("  start: Start tracing");
+                pw.println("  stop: Stop tracing");
+                return -1;
+        }
+    }
+
+    @Override
+    public void triggerDump() {
+        if (isAvailable() && isEnabled()) {
+            try {
+                mService.startProtoDump(null);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Exception while triggering proto dump", e);
+            }
+        }
+    }
+
+    private void writeTraceToFileLocked() {
+        try {
+            ProtoOutputStream proto = new ProtoOutputStream();
+            proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+            mBuffer.writeTraceToFile(mTraceFile, proto);
+        } catch (IOException e) {
+            Log.e(TAG, "Unable to write buffer to file", e);
+        }
+    }
+
+    @GuardedBy("mEnabledLock")
+    private void startTrace(PrintWriter pw) {
+        if (IS_USER) {
+            Log.w(TAG, "Warn: Tracing is not supported on user builds.");
+            return;
+        }
+
+        synchronized (mEnabledLock) {
+            if (isAvailable() && isEnabled()) {
+                Log.w(TAG, "Warn: Tracing is already started.");
+                return;
+            }
+
+            pw.println("Starting tracing to " + mTraceFile + ".");
+            sEnabled = true;
+            mBuffer.resetBuffer();
+        }
+    }
+
+    @GuardedBy("mEnabledLock")
+    private void stopTrace(PrintWriter pw) {
+        if (IS_USER) {
+            Log.w(TAG, "Warn: Tracing is not supported on user builds.");
+            return;
+        }
+
+        synchronized (mEnabledLock) {
+            if (!isAvailable() || !isEnabled()) {
+                Log.w(TAG, "Warn: Tracing is not available or not started.");
+                return;
+            }
+
+            pw.println("Stopping tracing and writing traces to " + mTraceFile + ".");
+            sEnabled = false;
+            writeTraceToFileLocked();
+            mBuffer.resetBuffer();
+        }
+    }
+}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 94e641c..193e674 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -120,12 +120,6 @@
     void updatePointerIcon(float x, float y);
 
     /**
-     * System chrome visibility changes
-     */
-    void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
-            int localValue, int localChanges);
-
-    /**
      * Called for non-application windows when the enter animation has completed.
      */
     void dispatchWindowShown();
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 8e875d7..daab70a 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -378,11 +378,6 @@
     boolean requestAssistScreenshot(IAssistDataReceiver receiver);
 
     /**
-     * Called by the status bar to notify Views of changes to System UI visiblity.
-     */
-    oneway void statusBarVisibilityChanged(int displayId, int visibility);
-
-    /**
      * Called by System UI to notify Window Manager to hide transient bars.
      */
     oneway void hideTransientBars(int displayId);
@@ -757,4 +752,10 @@
      */
     void requestScrollCapture(int displayId, IBinder behindClient, int taskId,
             IScrollCaptureController controller);
+
+    /**
+     * Holds the WM lock for the specified amount of milliseconds.
+     * Intended for use by the tests that need to imitate lock contention.
+     */
+    void holdLock(in int durationMs);
 }
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 18c87c0..69a5faf 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -44,17 +44,17 @@
  * {@hide}
  */
 interface IWindowSession {
-    int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs,
+    int addToDisplay(IWindow window, in WindowManager.LayoutParams attrs,
             in int viewVisibility, in int layerStackId, out Rect outFrame,
             out Rect outContentInsets, out Rect outStableInsets,
             out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel,
             out InsetsState insetsState, out InsetsSourceControl[] activeControls);
-    int addToDisplayAsUser(IWindow window, int seq, in WindowManager.LayoutParams attrs,
+    int addToDisplayAsUser(IWindow window, in WindowManager.LayoutParams attrs,
                 in int viewVisibility, in int layerStackId, in int userId,
                 out Rect outFrame, out Rect outContentInsets, out Rect outStableInsets,
                 out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel,
                 out InsetsState insetsState, out InsetsSourceControl[] activeControls);
-    int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
+    int addToDisplayWithoutInputChannel(IWindow window, in WindowManager.LayoutParams attrs,
             in int viewVisibility, in int layerStackId, out Rect outContentInsets,
             out Rect outStableInsets, out InsetsState insetsState);
     @UnsupportedAppUsage
@@ -68,7 +68,6 @@
      * to draw the window's contents.
      *
      * @param window The window being modified.
-     * @param seq Ordering sequence number.
      * @param attrs If non-null, new attributes to apply to the window.
      * @param requestedWidth The width the window wants to be.
      * @param requestedHeight The height the window wants to be.
@@ -106,7 +105,7 @@
      * @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_SHOW_FOCUS},
      * {@link WindowManagerGlobal#RELAYOUT_FIRST_TIME}.
      */
-    int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs,
+    int relayout(IWindow window, in WindowManager.LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewVisibility,
             int flags, long frameNumber, out ClientWindowFrames outFrames,
             out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index 92772c1..efc0bd2 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -16,16 +16,23 @@
 
 package android.view;
 
+import static android.view.ImeFocusControllerProto.HAS_IME_FOCUS;
+import static android.view.ImeFocusControllerProto.NEXT_SERVED_VIEW;
+import static android.view.ImeFocusControllerProto.SERVED_VIEW;
+
 import android.annotation.AnyThread;
 import android.annotation.NonNull;
 import android.annotation.UiThread;
 import android.util.Log;
+import android.util.proto.ProtoOutputStream;
 import android.view.inputmethod.InputMethodManager;
 
 import com.android.internal.inputmethod.InputMethodDebug;
 import com.android.internal.inputmethod.StartInputFlags;
 import com.android.internal.inputmethod.StartInputReason;
 
+import java.util.Objects;
+
 /**
  * Responsible for IME focus handling inside {@link ViewRootImpl}.
  * @hide
@@ -280,4 +287,12 @@
     boolean hasImeFocus() {
         return mHasImeFocus;
     }
+
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(HAS_IME_FOCUS, mHasImeFocus);
+        proto.write(SERVED_VIEW, Objects.toString(mServedView));
+        proto.write(NEXT_SERVED_VIEW, Objects.toString(mNextServedView));
+        proto.end(token);
+    }
 }
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 82f6036..dd1a194 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -16,6 +16,9 @@
 
 package android.view;
 
+import static android.view.ImeInsetsSourceConsumerProto.FOCUSED_EDITOR;
+import static android.view.ImeInsetsSourceConsumerProto.INSETS_SOURCE_CONSUMER;
+import static android.view.ImeInsetsSourceConsumerProto.IS_REQUESTED_VISIBLE_AWAITING_CONTROL;
 import static android.view.InsetsController.AnimationType;
 import static android.view.InsetsState.ITYPE_IME;
 
@@ -24,6 +27,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.text.TextUtils;
+import android.util.proto.ProtoOutputStream;
 import android.view.SurfaceControl.Transaction;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
@@ -111,7 +115,6 @@
     public @ShowResult int requestShow(boolean fromIme) {
         // TODO: ResultReceiver for IME.
         // TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag.
-
         if (getControl() == null) {
             // If control is null, schedule to show IME when control is available.
             mIsRequestedVisibleAwaitingControl = true;
@@ -227,6 +230,17 @@
         return Arrays.equals(parcel1.createByteArray(), parcel2.createByteArray());
     }
 
+    @Override
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        super.dumpDebug(proto, INSETS_SOURCE_CONSUMER);
+        if (mFocusedEditor != null) {
+            mFocusedEditor.dumpDebug(proto, FOCUSED_EDITOR);
+        }
+        proto.write(IS_REQUESTED_VISIBLE_AWAITING_CONTROL, mIsRequestedVisibleAwaitingControl);
+        proto.end(token);
+    }
+
     private InputMethodManager getImm() {
         return mController.getHost().getInputMethodManager();
     }
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 6ffd892..71899fa 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -17,6 +17,14 @@
 package android.view;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.InsetsAnimationControlImplProto.CURRENT_ALPHA;
+import static android.view.InsetsAnimationControlImplProto.IS_CANCELLED;
+import static android.view.InsetsAnimationControlImplProto.IS_FINISHED;
+import static android.view.InsetsAnimationControlImplProto.PENDING_ALPHA;
+import static android.view.InsetsAnimationControlImplProto.PENDING_FRACTION;
+import static android.view.InsetsAnimationControlImplProto.PENDING_INSETS;
+import static android.view.InsetsAnimationControlImplProto.SHOWN_ON_FINISH;
+import static android.view.InsetsAnimationControlImplProto.TMP_MATRIX;
 import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
 import static android.view.InsetsController.AnimationType;
 import static android.view.InsetsController.DEBUG;
@@ -38,6 +46,8 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.SparseSetArray;
+import android.util.imetracing.ImeTracing;
+import android.util.proto.ProtoOutputStream;
 import android.view.InsetsState.InternalInsetsSide;
 import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
 import android.view.WindowInsets.Type.InsetsType;
@@ -48,6 +58,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
+import java.util.Objects;
 
 /**
  * Implements {@link WindowInsetsAnimationController}
@@ -122,6 +133,10 @@
         mAnimationType = animationType;
         mController.startAnimation(this, listener, types, mAnimation,
                 new Bounds(mHiddenInsets, mShownInsets));
+
+        if ((mTypes & WindowInsets.Type.ime()) != 0) {
+            ImeTracing.getInstance().triggerDump();
+        }
     }
 
     private boolean calculatePerceptible(Insets currentInsets, float currentAlpha) {
@@ -285,6 +300,20 @@
         return mAnimation;
     }
 
+    @Override
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(IS_CANCELLED, mCancelled);
+        proto.write(IS_FINISHED, mFinished);
+        proto.write(TMP_MATRIX, Objects.toString(mTmpMatrix));
+        proto.write(PENDING_INSETS, Objects.toString(mPendingInsets));
+        proto.write(PENDING_FRACTION, mPendingFraction);
+        proto.write(SHOWN_ON_FINISH, mShownOnFinish);
+        proto.write(CURRENT_ALPHA, mCurrentAlpha);
+        proto.write(PENDING_ALPHA, mPendingAlpha);
+        proto.end(token);
+    }
+
     WindowInsetsAnimationControlListener getListener() {
         return mListener;
     }
diff --git a/core/java/android/view/InsetsAnimationControlRunner.java b/core/java/android/view/InsetsAnimationControlRunner.java
index 0711c3e..0275b52 100644
--- a/core/java/android/view/InsetsAnimationControlRunner.java
+++ b/core/java/android/view/InsetsAnimationControlRunner.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.util.proto.ProtoOutputStream;
 import android.view.InsetsController.AnimationType;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.WindowInsets.Type.InsetsType;
@@ -53,4 +54,14 @@
      * @return The animation type this runner is running.
      */
     @AnimationType int getAnimationType();
+
+    /**
+     *
+     * Export the state of classes that implement this interface into a protocol buffer
+     * output stream.
+     *
+     * @param proto Stream to write the state to
+     * @param fieldId FieldId of the implementation class
+     */
+    void dumpDebug(ProtoOutputStream proto, long fieldId);
 }
diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java
index 1236044..cc3cd27 100644
--- a/core/java/android/view/InsetsAnimationThreadControlRunner.java
+++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java
@@ -25,6 +25,7 @@
 import android.os.Trace;
 import android.util.Log;
 import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
 import android.view.InsetsController.AnimationType;
 import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
 import android.view.WindowInsets.Type.InsetsType;
@@ -122,6 +123,12 @@
 
     @Override
     @UiThread
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        mControl.dumpDebug(proto, fieldId);
+    }
+
+    @Override
+    @UiThread
     public int getTypes() {
         return mControl.getTypes();
     }
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 92eade3..652781a 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static android.view.InsetsControllerProto.CONTROL;
+import static android.view.InsetsControllerProto.STATE;
 import static android.view.InsetsState.ITYPE_CAPTION_BAR;
 import static android.view.InsetsState.ITYPE_IME;
 import static android.view.InsetsState.toInternalType;
@@ -41,6 +43,8 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
+import android.util.imetracing.ImeTracing;
+import android.util.proto.ProtoOutputStream;
 import android.view.InsetsSourceConsumer.ShowResult;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.SurfaceControl.Transaction;
@@ -298,6 +302,10 @@
 
         @Override
         public void onReady(WindowInsetsAnimationController controller, int types) {
+            if ((types & ime()) != 0) {
+                ImeTracing.getInstance().triggerDump();
+            }
+
             mController = controller;
             if (DEBUG) Log.d(TAG, "default animation onReady types: " + types);
 
@@ -812,6 +820,9 @@
 
     @VisibleForTesting
     public void show(@InsetsType int types, boolean fromIme) {
+        if (fromIme) {
+            ImeTracing.getInstance().triggerDump();
+        }
         // Handle pending request ready in case there was one set.
         if (fromIme && mPendingImeControlRequest != null) {
             PendingControlRequest pendingRequest = mPendingImeControlRequest;
@@ -860,6 +871,9 @@
     }
 
     void hide(@InsetsType int types, boolean fromIme) {
+        if (fromIme) {
+            ImeTracing.getInstance().triggerDump();
+        }
         int typesReady = 0;
         final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
         for (int i = internalTypes.size() - 1; i >= 0; i--) {
@@ -894,6 +908,9 @@
             listener.onCancelled(null);
             return;
         }
+        if (fromIme) {
+            ImeTracing.getInstance().triggerDump();
+        }
 
         controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, durationMs,
                 interpolator, animationType, getLayoutInsetsDuringAnimationMode(types),
@@ -1292,6 +1309,9 @@
 
     private void hideDirectly(
             @InsetsType int types, boolean animationFinished, @AnimationType int animationType) {
+        if ((types & ime()) != 0) {
+            ImeTracing.getInstance().triggerDump();
+        }
         final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
         for (int i = internalTypes.size() - 1; i >= 0; i--) {
             getSourceConsumer(internalTypes.valueAt(i)).hide(animationFinished, animationType);
@@ -1299,6 +1319,9 @@
     }
 
     private void showDirectly(@InsetsType int types) {
+        if ((types & ime()) != 0) {
+            ImeTracing.getInstance().triggerDump();
+        }
         final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
         for (int i = internalTypes.size() - 1; i >= 0; i--) {
             getSourceConsumer(internalTypes.valueAt(i)).show(false /* fromIme */);
@@ -1318,6 +1341,16 @@
         mState.dump(prefix + "  ", pw);
     }
 
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        mState.dumpDebug(proto, STATE);
+        for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
+            InsetsAnimationControlRunner runner = mRunningAnimations.get(i).runner;
+            runner.dumpDebug(proto, CONTROL);
+        }
+        proto.end(token);
+    }
+
     @VisibleForTesting
     @Override
     public void startAnimation(InsetsAnimationControlImpl controller,
@@ -1388,7 +1421,7 @@
     }
 
     @Override
-    public @Appearance int getSystemBarsBehavior() {
+    public @Behavior int getSystemBarsBehavior() {
         return mHost.getSystemBarsBehavior();
     }
 
diff --git a/core/java/android/view/InsetsFlags.java b/core/java/android/view/InsetsFlags.java
index 385b0bf..5a64a5d 100644
--- a/core/java/android/view/InsetsFlags.java
+++ b/core/java/android/view/InsetsFlags.java
@@ -16,13 +16,6 @@
 
 package android.view;
 
-import static android.view.View.NAVIGATION_BAR_TRANSLUCENT;
-import static android.view.View.NAVIGATION_BAR_TRANSPARENT;
-import static android.view.View.STATUS_BAR_TRANSLUCENT;
-import static android.view.View.STATUS_BAR_TRANSPARENT;
-import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
-import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
-import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
@@ -76,44 +69,4 @@
                     name = "SHOW_TRANSIENT_BARS_BY_SWIPE")
     })
     public @Behavior int behavior;
-
-    /**
-     * Converts system UI visibility to appearance.
-     *
-     * @param systemUiVisibility the system UI visibility to be converted.
-     * @return the outcome {@link Appearance}
-     */
-    public static @Appearance int getAppearance(int systemUiVisibility) {
-        int appearance = 0;
-        appearance |= convertFlag(systemUiVisibility, SYSTEM_UI_FLAG_LOW_PROFILE,
-                APPEARANCE_LOW_PROFILE_BARS);
-        appearance |= convertFlag(systemUiVisibility, SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
-                APPEARANCE_LIGHT_STATUS_BARS);
-        appearance |= convertFlag(systemUiVisibility, SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
-                APPEARANCE_LIGHT_NAVIGATION_BARS);
-        appearance |= convertNoFlag(systemUiVisibility,
-                STATUS_BAR_TRANSLUCENT | STATUS_BAR_TRANSPARENT, APPEARANCE_OPAQUE_STATUS_BARS);
-        appearance |= convertNoFlag(systemUiVisibility,
-                NAVIGATION_BAR_TRANSLUCENT | NAVIGATION_BAR_TRANSPARENT,
-                APPEARANCE_OPAQUE_NAVIGATION_BARS);
-        return appearance;
-    }
-
-    /**
-     * Converts the system UI visibility into an appearance flag if the given visibility contains
-     * the given system UI flag.
-     */
-    private static @Appearance int convertFlag(int systemUiVisibility, int systemUiFlag,
-            @Appearance int appearance) {
-        return (systemUiVisibility & systemUiFlag) != 0 ? appearance : 0;
-    }
-
-    /**
-     * Converts the system UI visibility into an appearance flag if the given visibility doesn't
-     * contains the given system UI flag.
-     */
-    private static @Appearance int convertNoFlag(int systemUiVisibility, int systemUiFlag,
-            @Appearance int appearance) {
-        return (systemUiVisibility & systemUiFlag) == 0 ? appearance : 0;
-    }
 }
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index dbf7570..41cc8459 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -16,6 +16,10 @@
 
 package android.view;
 
+import static android.view.InsetsSourceProto.FRAME;
+import static android.view.InsetsSourceProto.TYPE;
+import static android.view.InsetsSourceProto.VISIBLE;
+import static android.view.InsetsSourceProto.VISIBLE_FRAME;
 import static android.view.InsetsState.ITYPE_CAPTION_BAR;
 import static android.view.InsetsState.ITYPE_IME;
 
@@ -25,6 +29,7 @@
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.proto.ProtoOutputStream;
 import android.view.InsetsState.InternalInsetsType;
 
 import java.io.PrintWriter;
@@ -183,6 +188,17 @@
         return false;
     }
 
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(TYPE, InsetsState.typeToString(mType));
+        mFrame.dumpDebug(proto, FRAME);
+        if (mVisibleFrame != null) {
+            mVisibleFrame.dumpDebug(proto, VISIBLE_FRAME);
+        }
+        proto.write(VISIBLE, mVisible);
+        proto.end(token);
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix);
         pw.print("InsetsSource type="); pw.print(InsetsState.typeToString(mType));
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index ba40459..d7ceaf7 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -19,6 +19,13 @@
 import static android.view.InsetsController.ANIMATION_TYPE_NONE;
 import static android.view.InsetsController.AnimationType;
 import static android.view.InsetsController.DEBUG;
+import static android.view.InsetsSourceConsumerProto.HAS_WINDOW_FOCUS;
+import static android.view.InsetsSourceConsumerProto.INTERNAL_INSETS_TYPE;
+import static android.view.InsetsSourceConsumerProto.IS_REQUESTED_VISIBLE;
+import static android.view.InsetsSourceConsumerProto.PENDING_FRAME;
+import static android.view.InsetsSourceConsumerProto.PENDING_VISIBLE_FRAME;
+import static android.view.InsetsSourceConsumerProto.SOURCE_CONTROL;
+import static android.view.InsetsState.ITYPE_IME;
 import static android.view.InsetsState.getDefaultVisibility;
 import static android.view.InsetsState.toPublicType;
 
@@ -28,6 +35,8 @@
 import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.util.Log;
+import android.util.imetracing.ImeTracing;
+import android.util.proto.ProtoOutputStream;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowInsets.Type.InsetsType;
@@ -319,6 +328,9 @@
 
     @VisibleForTesting(visibility = PACKAGE)
     public boolean notifyAnimationFinished() {
+        if (mType == ITYPE_IME) {
+            ImeTracing.getInstance().triggerDump();
+        }
         if (mPendingFrame != null) {
             InsetsSource source = mState.getSource(mType);
             source.setFrame(mPendingFrame);
@@ -360,4 +372,21 @@
         t.apply();
         onPerceptible(mRequestedVisible);
     }
+
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(INTERNAL_INSETS_TYPE, InsetsState.typeToString(mType));
+        proto.write(HAS_WINDOW_FOCUS, mHasWindowFocus);
+        proto.write(IS_REQUESTED_VISIBLE, mRequestedVisible);
+        if (mSourceControl != null) {
+            mSourceControl.dumpDebug(proto, SOURCE_CONTROL);
+        }
+        if (mPendingFrame != null) {
+            mPendingFrame.dumpDebug(proto, PENDING_FRAME);
+        }
+        if (mPendingVisibleFrame != null) {
+            mPendingVisibleFrame.dumpDebug(proto, PENDING_VISIBLE_FRAME);
+        }
+        proto.end(token);
+    }
 }
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 51b4921..b45bd38 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -16,10 +16,17 @@
 
 package android.view;
 
+import static android.graphics.PointProto.X;
+import static android.graphics.PointProto.Y;
+import static android.view.InsetsSourceControlProto.LEASH;
+import static android.view.InsetsSourceControlProto.POSITION;
+import static android.view.InsetsSourceControlProto.TYPE;
+
 import android.annotation.Nullable;
 import android.graphics.Point;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.proto.ProtoOutputStream;
 import android.view.InsetsState.InternalInsetsType;
 
 import java.io.PrintWriter;
@@ -120,4 +127,19 @@
             return new InsetsSourceControl[size];
         }
     };
+
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(TYPE, InsetsState.typeToString(mType));
+
+        final long surfaceToken = proto.start(POSITION);
+        proto.write(X, mSurfacePosition.x);
+        proto.write(Y, mSurfacePosition.y);
+        proto.end(surfaceToken);
+
+        if (mLeash != null) {
+            mLeash.dumpDebug(proto, LEASH);
+        }
+        proto.end(token);
+    }
 }
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index c5d0a10..eabb718 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static android.view.InsetsStateProto.DISPLAY_FRAME;
+import static android.view.InsetsStateProto.SOURCES;
 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
 import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
 import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
@@ -41,6 +43,7 @@
 import android.os.Parcelable;
 import android.util.ArraySet;
 import android.util.SparseIntArray;
+import android.util.proto.ProtoOutputStream;
 import android.view.WindowInsets.Type;
 import android.view.WindowInsets.Type.InsetsType;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
@@ -545,6 +548,16 @@
         }
     }
 
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        InsetsSource source = mSources[ITYPE_IME];
+        if (source != null) {
+            source.dumpDebug(proto, SOURCES);
+        }
+        mDisplayFrame.dumpDebug(proto, DISPLAY_FRAME);
+        proto.end(token);
+    }
+
     public static String typeToString(@InternalInsetsType int type) {
         switch (type) {
             case ITYPE_STATUS_BAR:
diff --git a/core/java/android/view/OnReceiveContentCallback.java b/core/java/android/view/OnReceiveContentCallback.java
new file mode 100644
index 0000000..73bcb93
--- /dev/null
+++ b/core/java/android/view/OnReceiveContentCallback.java
@@ -0,0 +1,377 @@
+/*
+ * 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.view;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.net.Uri;
+import android.os.Bundle;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Callback for apps to implement handling for insertion of content. "Content" here refers to both
+ * text and non-text (plain/styled text, HTML, images, videos, audio files, etc).
+ *
+ * <p>This callback can be attached to different types of UI components using
+ * {@link View#setOnReceiveContentCallback}.
+ *
+ * <p>For editable {@link android.widget.TextView} components, implementations can extend from
+ * {@link android.widget.TextViewOnReceiveContentCallback} to reuse default platform behavior for
+ * handling text.
+ *
+ * <p>Example implementation:<br>
+ * <pre class="prettyprint">
+ * public class MyOnReceiveContentCallback implements OnReceiveContentCallback&lt;TextView&gt; {
+ *
+ *     private static final Set&lt;String&gt; SUPPORTED_MIME_TYPES = Collections.unmodifiableSet(
+ *         Set.of("image/*", "video/*"));
+ *
+ *     &#64;NonNull
+ *     &#64;Override
+ *     public Set&lt;String&gt; getSupportedMimeTypes() {
+ *         return SUPPORTED_MIME_TYPES;
+ *     }
+ *
+ *     &#64;Override
+ *     public boolean onReceiveContent(@NonNull TextView view, @NonNull Payload payload) {
+ *         // ... app-specific logic to handle the content in the payload ...
+ *     }
+ * }
+ * </pre>
+ *
+ * @param <T> The type of {@link View} with which this receiver can be associated.
+ */
+public interface OnReceiveContentCallback<T extends View> {
+    /**
+     * Receive the given content.
+     *
+     * <p>This function will only be invoked if the MIME type of the content is in the set of
+     * types returned by {@link #getSupportedMimeTypes}.
+     *
+     * <p>For text, if the view has a selection, the selection should be overwritten by the clip; if
+     * there's no selection, this method should insert the content at the current cursor position.
+     *
+     * <p>For non-text content (e.g. an image), the content may be inserted inline, or it may be
+     * added as an attachment (could potentially be shown in a completely separate view).
+     *
+     * @param view The view where the content insertion was requested.
+     * @param payload The content to insert and related metadata.
+     *
+     * @return Returns true if some or all of the content is accepted for insertion. If accepted,
+     * actual insertion may be handled asynchronously in the background and may or may not result in
+     * successful insertion. For example, the app may not end up inserting an accepted item if it
+     * exceeds the app's size limit for that type of content.
+     */
+    boolean onReceiveContent(@NonNull T view, @NonNull Payload payload);
+
+    /**
+     * Returns the MIME types that can be handled by this callback.
+     *
+     * <p>The {@link #onReceiveContent} callback method will only be invoked if the MIME type of the
+     * content is in the set of supported types returned here.
+     *
+     * <p>Different platform features (e.g. pasting from the clipboard, inserting stickers from the
+     * keyboard, etc) may use this function to conditionally alter their behavior. For example, the
+     * keyboard may choose to hide its UI for inserting GIFs if the input field that has focus has
+     * a {@link OnReceiveContentCallback} set and the MIME types returned from this function don't
+     * include "image/gif".
+     *
+     * <p><em>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC
+     * MIME types. As a result, you should always write your MIME types with lower case letters, or
+     * use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to lower
+     * case.</em>
+     *
+     * @param view The target view.
+     * @return An immutable set with the MIME types supported by this callback. The returned MIME
+     * types may contain wildcards such as "text/*", "image/*", etc.
+     */
+    @SuppressLint("CallbackMethodName")
+    @NonNull
+    Set<String> getSupportedMimeTypes(@NonNull T view);
+
+    /**
+     * Returns true if at least one of the MIME types of the given clip is
+     * {@link #getSupportedMimeTypes supported} by this receiver.
+     *
+     * @hide
+     */
+    default boolean supports(@NonNull T view, @NonNull ClipDescription description) {
+        for (String supportedMimeType : getSupportedMimeTypes(view)) {
+            if (description.hasMimeType(supportedMimeType)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Holds all the relevant data for a request to {@link OnReceiveContentCallback}.
+     */
+    final class Payload {
+
+        /**
+         * Specifies the UI through which content is being inserted.
+         *
+         * @hide
+         */
+        @IntDef(prefix = {"SOURCE_"}, value = {SOURCE_CLIPBOARD, SOURCE_INPUT_METHOD,
+                SOURCE_DRAG_AND_DROP, SOURCE_AUTOFILL, SOURCE_PROCESS_TEXT})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Source {}
+
+        /**
+         * Specifies that the operation was triggered by a paste from the clipboard (e.g. "Paste" or
+         * "Paste as plain text" action in the insertion/selection menu).
+         */
+        public static final int SOURCE_CLIPBOARD = 0;
+
+        /**
+         * Specifies that the operation was triggered from the soft keyboard (also known as input
+         * method editor or IME). See https://developer.android.com/guide/topics/text/image-keyboard
+         * for more info.
+         */
+        public static final int SOURCE_INPUT_METHOD = 1;
+
+        /**
+         * Specifies that the operation was triggered by the drag/drop framework. See
+         * https://developer.android.com/guide/topics/ui/drag-drop for more info.
+         */
+        public static final int SOURCE_DRAG_AND_DROP = 2;
+
+        /**
+         * Specifies that the operation was triggered by the autofill framework. See
+         * https://developer.android.com/guide/topics/text/autofill for more info.
+         */
+        public static final int SOURCE_AUTOFILL = 3;
+
+        /**
+         * Specifies that the operation was triggered by a result from a
+         * {@link android.content.Intent#ACTION_PROCESS_TEXT PROCESS_TEXT} action in the selection
+         * menu.
+         */
+        public static final int SOURCE_PROCESS_TEXT = 4;
+
+        /**
+         * Returns the symbolic name of the given source.
+         *
+         * @hide
+         */
+        static String sourceToString(@Source int source) {
+            switch (source) {
+                case SOURCE_CLIPBOARD: return "SOURCE_CLIPBOARD";
+                case SOURCE_INPUT_METHOD: return "SOURCE_INPUT_METHOD";
+                case SOURCE_DRAG_AND_DROP: return "SOURCE_DRAG_AND_DROP";
+                case SOURCE_AUTOFILL: return "SOURCE_AUTOFILL";
+                case SOURCE_PROCESS_TEXT: return "SOURCE_PROCESS_TEXT";
+            }
+            return String.valueOf(source);
+        }
+
+        /**
+         * Flags to configure the insertion behavior.
+         *
+         * @hide
+         */
+        @IntDef(flag = true, prefix = {"FLAG_"}, value = {FLAG_CONVERT_TO_PLAIN_TEXT})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Flags {}
+
+        /**
+         * Flag requesting that the content should be converted to plain text prior to inserting.
+         */
+        public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1 << 0;
+
+        /**
+         * Returns the symbolic names of the set flags or {@code "0"} if no flags are set.
+         *
+         * @hide
+         */
+        static String flagsToString(@Flags int flags) {
+            if ((flags & FLAG_CONVERT_TO_PLAIN_TEXT) != 0) {
+                return "FLAG_CONVERT_TO_PLAIN_TEXT";
+            }
+            return String.valueOf(flags);
+        }
+
+        /**
+         * The data to be inserted.
+         */
+        @NonNull private final ClipData mClip;
+
+        /**
+         * The source of the operation. See {@code SOURCE_} constants.
+         */
+        private final @Source int mSource;
+
+        /**
+         * Optional flags that control the insertion behavior. See {@code FLAG_} constants.
+         */
+        private final @Flags int mFlags;
+
+        /**
+         * Optional http/https URI for the content that may be provided by the IME. This is only
+         * populated if the source is {@link #SOURCE_INPUT_METHOD} and if a non-empty
+         * {@link android.view.inputmethod.InputContentInfo#getLinkUri linkUri} was passed by the
+         * IME.
+         */
+        @Nullable
+        private final Uri mLinkUri;
+
+        /**
+         * Optional additional metadata. If the source is {@link #SOURCE_INPUT_METHOD}, this will
+         * include the {@link android.view.inputmethod.InputConnection#commitContent opts} passed by
+         * the IME.
+         */
+        @Nullable
+        private final Bundle mExtras;
+
+        private Payload(Builder b) {
+            this.mClip = Objects.requireNonNull(b.mClip);
+            this.mSource = Preconditions.checkArgumentInRange(b.mSource, 0, SOURCE_PROCESS_TEXT,
+                    "source");
+            this.mFlags = Preconditions.checkFlagsArgument(b.mFlags, FLAG_CONVERT_TO_PLAIN_TEXT);
+            this.mLinkUri = b.mLinkUri;
+            this.mExtras = b.mExtras;
+        }
+
+        @NonNull
+        @Override
+        public String toString() {
+            return "Payload{"
+                    + "clip=" + mClip.getDescription()
+                    + ", source=" + sourceToString(mSource)
+                    + ", flags=" + flagsToString(mFlags)
+                    + ", linkUri=" + mLinkUri
+                    + ", extras=" + mExtras
+                    + "}";
+        }
+
+        /**
+         * The data to be inserted.
+         */
+        public @NonNull ClipData getClip() {
+            return mClip;
+        }
+
+        /**
+         * The source of the operation. See {@code SOURCE_} constants.
+         */
+        public @Source int getSource() {
+            return mSource;
+        }
+
+        /**
+         * Optional flags that control the insertion behavior. See {@code FLAG_} constants.
+         */
+        public @Flags int getFlags() {
+            return mFlags;
+        }
+
+        /**
+         * Optional http/https URI for the content that may be provided by the IME. This is only
+         * populated if the source is {@link #SOURCE_INPUT_METHOD} and if a non-empty
+         * {@link android.view.inputmethod.InputContentInfo#getLinkUri linkUri} was passed by the
+         * IME.
+         */
+        public @Nullable Uri getLinkUri() {
+            return mLinkUri;
+        }
+
+        /**
+         * Optional additional metadata. If the source is {@link #SOURCE_INPUT_METHOD}, this will
+         * include the {@link android.view.inputmethod.InputConnection#commitContent opts} passed by
+         * the IME.
+         */
+        public @Nullable Bundle getExtras() {
+            return mExtras;
+        }
+
+        /**
+         * Builder for {@link Payload}.
+         */
+        public static final class Builder {
+            @NonNull private final ClipData mClip;
+            private final @Source int mSource;
+            private @Flags int mFlags;
+            @Nullable private Uri mLinkUri;
+            @Nullable private Bundle mExtras;
+
+            /**
+             * Creates a new builder.
+             * @param clip   The data to insert.
+             * @param source The source of the operation. See {@code SOURCE_} constants.
+             */
+            public Builder(@NonNull ClipData clip, @Source int source) {
+                mClip = clip;
+                mSource = source;
+            }
+
+            /**
+             * Sets flags that control content insertion behavior.
+             * @param flags Optional flags to configure the insertion behavior. Use 0 for default
+             *              behavior. See {@code FLAG_} constants.
+             * @return this builder
+             */
+            @NonNull
+            public Builder setFlags(@Flags int flags) {
+                mFlags = flags;
+                return this;
+            }
+
+            /**
+             * Sets the http/https URI for the content. See
+             * {@link android.view.inputmethod.InputContentInfo#getLinkUri} for more info.
+             * @param linkUri Optional http/https URI for the content.
+             * @return this builder
+             */
+            @NonNull
+            public Builder setLinkUri(@Nullable Uri linkUri) {
+                mLinkUri = linkUri;
+                return this;
+            }
+
+            /**
+             * Sets additional metadata.
+             * @param extras Optional bundle with additional metadata.
+             * @return this builder
+             */
+            @NonNull
+            public Builder setExtras(@Nullable Bundle extras) {
+                mExtras = extras;
+                return this;
+            }
+
+            /**
+             * @return A new {@link Payload} instance with the data from this builder.
+             */
+            @NonNull
+            public Payload build() {
+                return new Payload(this);
+            }
+        }
+    }
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e7e28ac..c430a4d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3995,89 +3995,6 @@
 
     /**
      * @hide
-     *
-     * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
-     * out of the public fields to keep the undefined bits out of the developer's way.
-     *
-     * Flag to specify that the status bar is displayed in transient mode.
-     */
-    public static final int STATUS_BAR_TRANSIENT = 0x04000000;
-
-    /**
-     * @hide
-     *
-     * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
-     * out of the public fields to keep the undefined bits out of the developer's way.
-     *
-     * Flag to specify that the navigation bar is displayed in transient mode.
-     */
-    @UnsupportedAppUsage
-    public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000;
-
-    /**
-     * @hide
-     *
-     * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
-     * out of the public fields to keep the undefined bits out of the developer's way.
-     *
-     * Flag to specify that the hidden status bar would like to be shown.
-     */
-    public static final int STATUS_BAR_UNHIDE = 0x10000000;
-
-    /**
-     * @hide
-     *
-     * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
-     * out of the public fields to keep the undefined bits out of the developer's way.
-     *
-     * Flag to specify that the hidden navigation bar would like to be shown.
-     */
-    public static final int NAVIGATION_BAR_UNHIDE = 0x20000000;
-
-    /**
-     * @hide
-     *
-     * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
-     * out of the public fields to keep the undefined bits out of the developer's way.
-     *
-     * Flag to specify that the status bar is displayed in translucent mode.
-     */
-    public static final int STATUS_BAR_TRANSLUCENT = 0x40000000;
-
-    /**
-     * @hide
-     *
-     * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
-     * out of the public fields to keep the undefined bits out of the developer's way.
-     *
-     * Flag to specify that the navigation bar is displayed in translucent mode.
-     */
-    public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000;
-
-    /**
-     * @hide
-     *
-     * Makes navigation bar transparent (but not the status bar).
-     */
-    public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000;
-
-    /**
-     * @hide
-     *
-     * Makes status bar transparent (but not the navigation bar).
-     */
-    public static final int STATUS_BAR_TRANSPARENT = 0x00000008;
-
-    /**
-     * @hide
-     *
-     * Makes both status bar and navigation bar transparent.
-     */
-    public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT
-            | STATUS_BAR_TRANSPARENT;
-
-    /**
-     * @hide
      */
     public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7;
 
@@ -4302,31 +4219,7 @@
                     name = "STATUS_BAR_DISABLE_RECENT"),
             @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH,
                     equals = STATUS_BAR_DISABLE_SEARCH,
-                    name = "STATUS_BAR_DISABLE_SEARCH"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSIENT,
-                    equals = STATUS_BAR_TRANSIENT,
-                    name = "STATUS_BAR_TRANSIENT"),
-            @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSIENT,
-                    equals = NAVIGATION_BAR_TRANSIENT,
-                    name = "NAVIGATION_BAR_TRANSIENT"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_UNHIDE,
-                    equals = STATUS_BAR_UNHIDE,
-                    name = "STATUS_BAR_UNHIDE"),
-            @ViewDebug.FlagToString(mask = NAVIGATION_BAR_UNHIDE,
-                    equals = NAVIGATION_BAR_UNHIDE,
-                    name = "NAVIGATION_BAR_UNHIDE"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSLUCENT,
-                    equals = STATUS_BAR_TRANSLUCENT,
-                    name = "STATUS_BAR_TRANSLUCENT"),
-            @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSLUCENT,
-                    equals = NAVIGATION_BAR_TRANSLUCENT,
-                    name = "NAVIGATION_BAR_TRANSLUCENT"),
-            @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSPARENT,
-                    equals = NAVIGATION_BAR_TRANSPARENT,
-                    name = "NAVIGATION_BAR_TRANSPARENT"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSPARENT,
-                    equals = STATUS_BAR_TRANSPARENT,
-                    name = "STATUS_BAR_TRANSPARENT")
+                    name = "STATUS_BAR_DISABLE_SEARCH")
     }, formatToHexString = true)
     @SystemUiVisibility
     int mSystemUiVisibility;
@@ -4355,14 +4248,6 @@
             STATUS_BAR_DISABLE_CLOCK,
             STATUS_BAR_DISABLE_RECENT,
             STATUS_BAR_DISABLE_SEARCH,
-            STATUS_BAR_TRANSIENT,
-            NAVIGATION_BAR_TRANSIENT,
-            STATUS_BAR_UNHIDE,
-            NAVIGATION_BAR_UNHIDE,
-            STATUS_BAR_TRANSLUCENT,
-            NAVIGATION_BAR_TRANSLUCENT,
-            NAVIGATION_BAR_TRANSPARENT,
-            STATUS_BAR_TRANSPARENT,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SystemUiVisibility {}
@@ -5358,6 +5243,9 @@
     @InputSourceClass
     int mUnbufferedInputSource = InputDevice.SOURCE_CLASS_NONE;
 
+    @Nullable
+    private OnReceiveContentCallback<? extends View> mOnReceiveContentCallback;
+
     /**
      * Simple constructor to use when creating a view from code.
      *
@@ -9113,6 +9001,36 @@
     }
 
     /**
+     * Returns the callback used for handling insertion of content into this view. See
+     * {@link #setOnReceiveContentCallback} for more info.
+     *
+     * @return The callback for handling insertion of content. Returns null if no callback has been
+     * {@link #setOnReceiveContentCallback set}.
+     */
+    @Nullable
+    public OnReceiveContentCallback<? extends View> getOnReceiveContentCallback() {
+        return mOnReceiveContentCallback;
+    }
+
+    /**
+     * Sets the callback to handle insertion of content into this view.
+     *
+     * <p>Depending on the view, this callback may be invoked for scenarios such as content
+     * insertion from the IME, Autofill, etc.
+     *
+     * <p>The callback will only be invoked if the MIME type of the content is
+     * {@link OnReceiveContentCallback#getSupportedMimeTypes declared as supported} by the callback.
+     * If the content type is not supported by the callback, the default platform handling will be
+     * executed instead.
+     *
+     * @param callback The callback to use. This can be null to reset to the default behavior.
+     */
+    public void setOnReceiveContentCallback(
+            @Nullable OnReceiveContentCallback<? extends View> callback) {
+        mOnReceiveContentCallback = callback;
+    }
+
+    /**
      * Automatically fills the content of this view with the {@code value}.
      *
      * <p>Views support the Autofill Framework mainly by:
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4176e88..88bd1c1 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -33,6 +33,23 @@
 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
 import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewRootImplProto.ADDED;
+import static android.view.ViewRootImplProto.APP_VISIBLE;
+import static android.view.ViewRootImplProto.CUR_SCROLL_Y;
+import static android.view.ViewRootImplProto.DISPLAY_ID;
+import static android.view.ViewRootImplProto.HEIGHT;
+import static android.view.ViewRootImplProto.IS_ANIMATING;
+import static android.view.ViewRootImplProto.IS_DRAWING;
+import static android.view.ViewRootImplProto.LAST_WINDOW_INSETS;
+import static android.view.ViewRootImplProto.PENDING_DISPLAY_CUTOUT;
+import static android.view.ViewRootImplProto.REMOVED;
+import static android.view.ViewRootImplProto.SCROLL_Y;
+import static android.view.ViewRootImplProto.SOFT_INPUT_MODE;
+import static android.view.ViewRootImplProto.VIEW;
+import static android.view.ViewRootImplProto.VISIBLE_RECT;
+import static android.view.ViewRootImplProto.WIDTH;
+import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES;
+import static android.view.ViewRootImplProto.WIN_FRAME;
 import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
 import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
@@ -61,6 +78,8 @@
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.IME_FOCUS_CONTROLLER;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.INSETS_CONTROLLER;
 
 import android.Manifest;
 import android.animation.LayoutTransition;
@@ -127,6 +146,8 @@
 import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.util.TypedValue;
+import android.util.imetracing.ImeTracing;
+import android.util.proto.ProtoOutputStream;
 import android.view.InputDevice.InputSourceClass;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.Surface.OutOfResourcesException;
@@ -164,6 +185,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.inputmethod.InputMethodDebug;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.policy.DecorView;
@@ -182,6 +204,7 @@
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Objects;
 import java.util.Queue;
 import java.util.concurrent.CountDownLatch;
 
@@ -339,8 +362,6 @@
 
     final int mTargetSdkVersion;
 
-    int mSeq;
-
     @UnsupportedAppUsage
     View mView;
 
@@ -648,7 +669,6 @@
     private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
 
     static final class SystemUiVisibilityInfo {
-        int seq;
         int globalVisibility;
         int localValue;
         int localChanges;
@@ -995,7 +1015,7 @@
                     mAttachInfo.mRecomputeGlobalAttributes = true;
                     collectViewAttributes();
                     adjustLayoutParamsForCompatibility(mWindowAttributes);
-                    res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
+                    res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                             getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrames.frame,
                             mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                             mAttachInfo.mDisplayCutout, inputChannel,
@@ -7390,7 +7410,7 @@
             frameNumber = mSurface.getNextFrameNumber();
         }
 
-        int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
+        int relayoutResult = mWindowSession.relayout(mWindow, params,
                 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
                 (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
                 insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
@@ -7520,6 +7540,38 @@
         mView.debug();
     }
 
+    /**
+     * Export the state of {@link ViewRootImpl} and other relevant classes into a protocol buffer
+     * output stream.
+     *
+     * @param proto Stream to write the state to
+     * @param fieldId FieldId of ViewRootImpl as defined in the parent message
+     */
+    @GuardedBy("this")
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(VIEW, Objects.toString(mView));
+        proto.write(DISPLAY_ID, mDisplay.getDisplayId());
+        proto.write(APP_VISIBLE, mAppVisible);
+        proto.write(HEIGHT, mHeight);
+        proto.write(WIDTH, mWidth);
+        proto.write(IS_ANIMATING, mIsAnimating);
+        mVisRect.dumpDebug(proto, VISIBLE_RECT);
+        proto.write(IS_DRAWING, mIsDrawing);
+        proto.write(ADDED, mAdded);
+        mWinFrame.dumpDebug(proto, WIN_FRAME);
+        mPendingDisplayCutout.get().dumpDebug(proto, PENDING_DISPLAY_CUTOUT);
+        proto.write(LAST_WINDOW_INSETS, Objects.toString(mLastWindowInsets));
+        proto.write(SOFT_INPUT_MODE, InputMethodDebug.softInputModeToString(mSoftInputMode));
+        proto.write(SCROLL_Y, mScrollY);
+        proto.write(CUR_SCROLL_Y, mCurScrollY);
+        proto.write(REMOVED, mRemoved);
+        mWindowAttributes.dumpDebug(proto, WINDOW_ATTRIBUTES);
+        proto.end(token);
+        mInsetsController.dumpDebug(proto, INSETS_CONTROLLER);
+        mImeFocusController.dumpDebug(proto, IME_FOCUS_CONTROLLER);
+    }
+
     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
         String innerPrefix = prefix + "  ";
         writer.println(prefix + "ViewRoot:");
@@ -8460,17 +8512,6 @@
         mHandler.sendMessage(msg);
     }
 
-    // TODO(118118435): Remove this after migration
-    public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
-            int localValue, int localChanges) {
-        SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
-        args.seq = seq;
-        args.globalVisibility = globalVisibility;
-        args.localValue = localValue;
-        args.localChanges = localChanges;
-        mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
-    }
-
     public void dispatchCheckFocus() {
         if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
             // This will result in a call to checkFocus() below.
@@ -9094,6 +9135,9 @@
 
         @Override
         public void showInsets(@InsetsType int types, boolean fromIme) {
+            if (fromIme) {
+                ImeTracing.getInstance().triggerDump();
+            }
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.showInsets(types, fromIme);
@@ -9102,6 +9146,9 @@
 
         @Override
         public void hideInsets(@InsetsType int types, boolean fromIme) {
+            if (fromIme) {
+                ImeTracing.getInstance().triggerDump();
+            }
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.hideInsets(types, fromIme);
@@ -9229,16 +9276,6 @@
         }
 
         @Override
-        public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
-                int localValue, int localChanges) {
-            final ViewRootImpl viewAncestor = mViewAncestor.get();
-            if (viewAncestor != null) {
-                viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
-                        localValue, localChanges);
-            }
-        }
-
-        @Override
         public void dispatchWindowShown() {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0d62da6..e96e98b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -3994,4 +3994,15 @@
             }
         }
     }
+
+    /**
+     * Holds the WM lock for the specified amount of milliseconds.
+     * Intended for use by the tests that need to imitate lock contention.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.INJECT_EVENTS)
+    default void holdLock(int durationMs) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index f57ee65..59e0226 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -281,4 +281,13 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    @Override
+    public void holdLock(int durationMs) {
+        try {
+            WindowManagerGlobal.getWindowManagerService().holdLock(durationMs);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index b70cb01..dbd8184 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -129,7 +129,7 @@
      * IWindowSession implementation.
      */
     @Override
-    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
+    public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
             int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
             Rect outStableInsets,
             DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
@@ -165,18 +165,18 @@
      * IWindowSession implementation. Currently this class doesn't need to support for multi-user.
      */
     @Override
-    public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs,
+    public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
             int viewVisibility, int displayId, int userId, Rect outFrame,
             Rect outContentInsets, Rect outStableInsets,
             DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
             InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
-        return addToDisplay(window, seq, attrs, viewVisibility, displayId,
+        return addToDisplay(window, attrs, viewVisibility, displayId,
                 outFrame, outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
                 outInsetsState, outActiveControls);
     }
 
     @Override
-    public int addToDisplayWithoutInputChannel(android.view.IWindow window, int seq,
+    public int addToDisplayWithoutInputChannel(android.view.IWindow window,
             android.view.WindowManager.LayoutParams attrs, int viewVisibility, int layerStackId,
             android.graphics.Rect outContentInsets, android.graphics.Rect outStableInsets,
             android.view.InsetsState insetsState) {
@@ -223,7 +223,7 @@
     }
 
     @Override
-    public int relayout(IWindow window, int seq, WindowManager.LayoutParams inAttrs,
+    public int relayout(IWindow window, WindowManager.LayoutParams inAttrs,
             int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
             ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState,
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index eef2726..73636f8 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -16,7 +16,10 @@
 
 package android.view.inputmethod;
 
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_INPUT_METHOD;
+
 import android.annotation.CallSuper;
+import android.content.ClipData;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.os.Bundle;
@@ -34,6 +37,7 @@
 import android.util.LogPrinter;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
+import android.view.OnReceiveContentCallback;
 import android.view.View;
 
 class ComposingText implements NoCopySpan {
@@ -870,9 +874,41 @@
     }
 
     /**
-     * The default implementation does nothing.
+     * Default implementation which invokes the target view's {@link OnReceiveContentCallback} if
+     * it is {@link View#setOnReceiveContentCallback set} and supports the MIME type of the given
+     * content; otherwise, simply returns false.
      */
     public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
-        return false;
+        @SuppressWarnings("unchecked") final OnReceiveContentCallback<View> receiver =
+                (OnReceiveContentCallback<View>) mTargetView.getOnReceiveContentCallback();
+        if (receiver == null) {
+            if (DEBUG) {
+                Log.d(TAG, "Can't insert content from IME; no callback");
+            }
+            return false;
+        }
+        if (!receiver.supports(mTargetView, inputContentInfo.getDescription())) {
+            if (DEBUG) {
+                Log.d(TAG, "Can't insert content from IME; callback doesn't support MIME type: "
+                        + inputContentInfo.getDescription());
+            }
+            return false;
+        }
+        if ((flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
+            try {
+                inputContentInfo.requestPermission();
+            } catch (Exception e) {
+                Log.w(TAG, "Can't insert content from IME; requestPermission() failed", e);
+                return false;
+            }
+        }
+        final ClipData clip = new ClipData(inputContentInfo.getDescription(),
+                new ClipData.Item(inputContentInfo.getContentUri()));
+        final OnReceiveContentCallback.Payload payload =
+                new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_INPUT_METHOD)
+                .setLinkUri(inputContentInfo.getLinkUri())
+                .setExtras(opts)
+                .build();
+        return receiver.onReceiveContent(mTargetView, payload);
     }
 }
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 104bc43..7dbf693 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -17,6 +17,12 @@
 package android.view.inputmethod;
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.view.inputmethod.EditorInfoProto.FIELD_ID;
+import static android.view.inputmethod.EditorInfoProto.IME_OPTIONS;
+import static android.view.inputmethod.EditorInfoProto.INPUT_TYPE;
+import static android.view.inputmethod.EditorInfoProto.PACKAGE_NAME;
+import static android.view.inputmethod.EditorInfoProto.PRIVATE_IME_OPTIONS;
+import static android.view.inputmethod.EditorInfoProto.TARGET_INPUT_METHOD_USER_ID;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -32,6 +38,7 @@
 import android.text.ParcelableSpan;
 import android.text.TextUtils;
 import android.util.Printer;
+import android.util.proto.ProtoOutputStream;
 import android.view.View;
 import android.view.autofill.AutofillId;
 
@@ -795,6 +802,26 @@
     }
 
     /**
+     * Export the state of {@link EditorInfo} into a protocol buffer output stream.
+     *
+     * @param proto Stream to write the state to
+     * @param fieldId FieldId of ViewRootImpl as defined in the parent message
+     * @hide
+     */
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(INPUT_TYPE, inputType);
+        proto.write(IME_OPTIONS, imeOptions);
+        proto.write(PRIVATE_IME_OPTIONS, privateImeOptions);
+        proto.write(PACKAGE_NAME, packageName);
+        proto.write(FIELD_ID, this.fieldId);
+        if (targetInputMethodUser != null) {
+            proto.write(TARGET_INPUT_METHOD_USER_ID, targetInputMethodUser.getIdentifier());
+        }
+        proto.end(token);
+    }
+
+    /**
      * Write debug output of this object.
      */
     public void dump(Printer pw, String prefix) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 8adb7e5..b8f04159 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -18,6 +18,17 @@
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
+import static android.util.imetracing.ImeTracing.PROTO_ARG;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.DISPLAY_ID;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.EDITOR_INFO;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.IME_INSETS_SOURCE_CONSUMER;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.INPUT_METHOD_MANAGER;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.VIEW_ROOT_IMPL;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientsProto.CLIENT;
+import static android.view.inputmethod.InputMethodManagerProto.ACTIVE;
+import static android.view.inputmethod.InputMethodManagerProto.CUR_ID;
+import static android.view.inputmethod.InputMethodManagerProto.FULLSCREEN_MODE;
+import static android.view.inputmethod.InputMethodManagerProto.SERVED_CONNECTING;
 
 import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
 import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION;
@@ -62,6 +73,8 @@
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
 import android.util.SparseArray;
+import android.util.imetracing.ImeTracing;
+import android.util.proto.ProtoOutputStream;
 import android.view.Display;
 import android.view.ImeFocusController;
 import android.view.ImeInsetsSourceConsumer;
@@ -564,6 +577,7 @@
                 @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
                 int windowFlags) {
             final View servedView;
+            ImeTracing.getInstance().triggerDump();
             synchronized (mH) {
                 mCurrentTextBoxAttribute = null;
                 mCompletions = null;
@@ -1084,6 +1098,11 @@
             mH.obtainMessage(MSG_UPDATE_ACTIVITY_VIEW_TO_SCREEN_MATRIX, bindSequence, 0,
                     matrixValues).sendToTarget();
         }
+
+        @Override
+        public void setImeTraceEnabled(boolean enabled) {
+            ImeTracing.getInstance().setEnabled(enabled);
+        }
     };
 
     final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
@@ -1652,6 +1671,7 @@
      * {@link #RESULT_HIDDEN}.
      */
     public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
+        ImeTracing.getInstance().triggerDump();
         // Re-dispatch if there is a context mismatch.
         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
         if (fallbackImm != null) {
@@ -1757,6 +1777,7 @@
      */
     public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
             ResultReceiver resultReceiver) {
+        ImeTracing.getInstance().triggerDump();
         checkFocus();
         synchronized (mH) {
             final View servedView = getServedViewLocked();
@@ -3108,6 +3129,10 @@
     }
 
     void doDump(FileDescriptor fd, PrintWriter fout, String[] args) {
+        if (processDump(fd, args)) {
+            return;
+        }
+
         final Printer p = new PrintWriterPrinter(fout);
         p.println("Input method client state for " + this + ":");
 
@@ -3202,4 +3227,74 @@
 
         return sb.toString();
     }
+
+    /**
+     * Checks the args to see if a proto-based ime dump was requested and writes the client side
+     * ime dump to the given {@link FileDescriptor}.
+     *
+     * @return {@code true} if a proto-based ime dump was requested.
+     */
+    private boolean processDump(final FileDescriptor fd, final String[] args) {
+        if (args == null) {
+            return false;
+        }
+
+        for (String arg : args) {
+            if (arg.equals(PROTO_ARG)) {
+                final ProtoOutputStream proto = new ProtoOutputStream(fd);
+                dumpProto(proto);
+                proto.flush();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Write the proto dump for all displays associated with this client.
+     *
+     * @param proto The proto stream to which the dumps are written.
+     * @hide
+     */
+    public static void dumpProto(ProtoOutputStream proto) {
+        for (int i = sInstanceMap.size() - 1; i >= 0; i--) {
+            InputMethodManager imm = sInstanceMap.valueAt(i);
+            imm.dumpDebug(proto);
+        }
+    }
+
+    /**
+     * Write the proto dump of various client side components to the provided
+     * {@link ProtoOutputStream}.
+     *
+     * @param proto The proto stream to which the dumps are written.
+     * @hide
+     */
+    @GuardedBy("mH")
+    public void dumpDebug(ProtoOutputStream proto) {
+        if (mCurMethod == null) {
+            return;
+        }
+
+        final long clientDumpToken = proto.start(CLIENT);
+        proto.write(DISPLAY_ID, mDisplayId);
+        final long token = proto.start(INPUT_METHOD_MANAGER);
+        synchronized (mH) {
+            proto.write(CUR_ID, mCurId);
+            proto.write(FULLSCREEN_MODE, mFullscreenMode);
+            proto.write(ACTIVE, mActive);
+            proto.write(SERVED_CONNECTING, mServedConnecting);
+            proto.end(token);
+            if (mCurRootView != null) {
+                mCurRootView.dumpDebug(proto, VIEW_ROOT_IMPL);
+            }
+            if (mCurrentTextBoxAttribute != null) {
+                mCurrentTextBoxAttribute.dumpDebug(proto, EDITOR_INFO);
+            }
+            if (mImeInsetsConsumer != null) {
+                mImeInsetsConsumer.dumpDebug(proto, IME_INSETS_SOURCE_CONSUMER);
+            }
+        }
+        proto.end(clientDumpToken);
+    }
 }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 60f8bb7..fa19521 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -16,6 +16,8 @@
 
 package android.widget;
 
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_DRAG_AND_DROP;
+
 import android.R;
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
@@ -96,6 +98,7 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.OnReceiveContentCallback;
 import android.view.SubMenu;
 import android.view.View;
 import android.view.View.DragShadowBuilder;
@@ -2851,9 +2854,11 @@
         try {
             final int originalLength = mTextView.getText().length();
             Selection.setSelection((Spannable) mTextView.getText(), offset);
-            ClipData clip = event.getClipData();
-            mTextView.getRichContentReceiver().onReceive(mTextView, clip,
-                    RichContentReceiver.SOURCE_DRAG_AND_DROP, 0);
+            final ClipData clip = event.getClipData();
+            final OnReceiveContentCallback.Payload payload =
+                    new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_DRAG_AND_DROP)
+                    .build();
+            mTextView.onReceiveContent(payload);
             if (dragDropIntoItself) {
                 deleteSourceAfterLocalDrop(dragLocalState, offset, originalLength);
             }
diff --git a/core/java/android/widget/RichContentReceiver.java b/core/java/android/widget/RichContentReceiver.java
deleted file mode 100644
index 80a0562..0000000
--- a/core/java/android/widget/RichContentReceiver.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * 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.widget;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.SuppressLint;
-import android.content.ClipData;
-import android.content.ClipDescription;
-import android.view.View;
-import android.view.inputmethod.InputConnection;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Set;
-
-/**
- * Callback for apps to implement handling for insertion of rich content. "Rich content" here refers
- * to both text and non-text content: plain text, styled text, HTML, images, videos, audio files,
- * etc.
- *
- * <p>This callback can be attached to different types of UI components. For editable
- * {@link TextView} components, implementations should typically wrap
- * {@link TextView#DEFAULT_RICH_CONTENT_RECEIVER}.
- *
- * <p>Example implementation:<br>
- * <pre class="prettyprint">
- *   public class MyRichContentReceiver implements RichContentReceiver&lt;TextView&gt; {
- *
- *       private static final Set&lt;String&gt; SUPPORTED_MIME_TYPES = Collections.unmodifiableSet(
- *           Set.of("text/*", "image/gif", "image/png", "image/jpg"));
- *
- *       &#64;NonNull
- *       &#64;Override
- *       public Set&lt;String&gt; getSupportedMimeTypes() {
- *           return SUPPORTED_MIME_TYPES;
- *       }
- *
- *       &#64;Override
- *       public boolean onReceive(@NonNull TextView textView, @NonNull ClipData clip,
- *               int source, int flags) {
- *         if (clip.getDescription().hasMimeType("image/*")) {
- *             return receiveImage(textView, clip);
- *         }
- *         return TextView.DEFAULT_RICH_CONTENT_RECEIVER.onReceive(textView, clip, source);
- *       }
- *
- *       private boolean receiveImage(@NonNull TextView textView, @NonNull ClipData clip) {
- *           // ... app-specific logic to handle the content URI in the clip ...
- *       }
- *   }
- * </pre>
- *
- * @param <T> The type of {@link View} with which this receiver can be associated.
- */
-@SuppressLint("CallbackMethodName")
-public interface RichContentReceiver<T extends View> {
-    /**
-     * Specifies the UI through which content is being inserted.
-     *
-     * @hide
-     */
-    @IntDef(prefix = {"SOURCE_"}, value = {SOURCE_CLIPBOARD, SOURCE_INPUT_METHOD,
-            SOURCE_DRAG_AND_DROP, SOURCE_AUTOFILL, SOURCE_PROCESS_TEXT})
-    @Retention(RetentionPolicy.SOURCE)
-    @interface Source {}
-
-    /**
-     * Specifies that the operation was triggered by a paste from the clipboard (e.g. "Paste" or
-     * "Paste as plain text" action in the insertion/selection menu).
-     */
-    int SOURCE_CLIPBOARD = 0;
-
-    /**
-     * Specifies that the operation was triggered from the soft keyboard (also known as input method
-     * editor or IME). See https://developer.android.com/guide/topics/text/image-keyboard for more
-     * info.
-     */
-    int SOURCE_INPUT_METHOD = 1;
-
-    /**
-     * Specifies that the operation was triggered by the drag/drop framework. See
-     * https://developer.android.com/guide/topics/ui/drag-drop for more info.
-     */
-    int SOURCE_DRAG_AND_DROP = 2;
-
-    /**
-     * Specifies that the operation was triggered by the autofill framework. See
-     * https://developer.android.com/guide/topics/text/autofill for more info.
-     */
-    int SOURCE_AUTOFILL = 3;
-
-    /**
-     * Specifies that the operation was triggered by a result from a
-     * {@link android.content.Intent#ACTION_PROCESS_TEXT PROCESS_TEXT} action in the selection menu.
-     */
-    int SOURCE_PROCESS_TEXT = 4;
-
-    /**
-     * Flags to configure the insertion behavior.
-     *
-     * @hide
-     */
-    @IntDef(flag = true, prefix = {"FLAG_"}, value = {FLAG_CONVERT_TO_PLAIN_TEXT})
-    @Retention(RetentionPolicy.SOURCE)
-    @interface Flags {}
-
-    /**
-     * Flag for {@link #onReceive} requesting that the content should be converted to plain text
-     * prior to inserting.
-     */
-    int FLAG_CONVERT_TO_PLAIN_TEXT = 1 << 0;
-
-    /**
-     * Insert the given clip.
-     *
-     * <p>For editable {@link TextView} components, this function will be invoked for the
-     * following scenarios:
-     * <ol>
-     *     <li>Paste from the clipboard (e.g. "Paste" or "Paste as plain text" action in the
-     *     insertion/selection menu)
-     *     <li>Content insertion from the keyboard ({@link InputConnection#commitContent})
-     *     <li>Drag and drop ({@link View#onDragEvent})
-     *     <li>Autofill, when the type for the field is
-     *     {@link android.view.View.AutofillType#AUTOFILL_TYPE_RICH_CONTENT}
-     * </ol>
-     *
-     * <p>For text, if the view has a selection, the selection should be overwritten by the
-     * clip; if there's no selection, this method should insert the content at the current
-     * cursor position.
-     *
-     * <p>For rich content (e.g. an image), this function may insert the content inline, or it may
-     * add the content as an attachment (could potentially go into a completely separate view).
-     *
-     * <p>This function may be invoked with a clip whose MIME type is not in the list of supported
-     * types returned by {@link #getSupportedMimeTypes()}. This provides the opportunity to
-     * implement custom fallback logic if desired.
-     *
-     * @param view   The view where the content insertion was requested.
-     * @param clip   The clip to insert.
-     * @param source The trigger of the operation.
-     * @param flags  Optional flags to configure the insertion behavior. Use 0 for default
-     *               behavior. See {@code FLAG_} constants on this interface for other options.
-     * @return Returns true if the clip was inserted.
-     */
-    boolean onReceive(@NonNull T view, @NonNull ClipData clip, @Source int source, int flags);
-
-    /**
-     * Returns the MIME types that can be handled by this callback.
-     *
-     * <p>Different platform features (e.g. pasting from the clipboard, inserting stickers from the
-     * keyboard, etc) may use this function to conditionally alter their behavior. For example, the
-     * keyboard may choose to hide its UI for inserting GIFs if the input field that has focus has
-     * a {@link RichContentReceiver} set and the MIME types returned from this function don't
-     * include "image/gif".
-     *
-     * @return An immutable set with the MIME types supported by this callback. The returned
-     * MIME types may contain wildcards such as "text/*", "image/*", etc.
-     */
-    @NonNull
-    Set<String> getSupportedMimeTypes();
-
-    /**
-     * Returns true if the MIME type of the given clip is {@link #getSupportedMimeTypes supported}
-     * by this receiver.
-     *
-     * @hide
-     */
-    default boolean supports(@NonNull ClipDescription description) {
-        for (String supportedMimeType : getSupportedMimeTypes()) {
-            if (description.hasMimeType(supportedMimeType)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns true if this receiver {@link #getSupportedMimeTypes supports} non-text content, such
-     * as images.
-     *
-     * @hide
-     */
-    default boolean supportsNonTextContent() {
-        for (String supportedMimeType : getSupportedMimeTypes()) {
-            if (!supportedMimeType.startsWith("text/")) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns the symbolic name of the given source.
-     *
-     * @hide
-     */
-    static String sourceToString(@Source int source) {
-        switch (source) {
-            case SOURCE_CLIPBOARD: return "SOURCE_CLIPBOARD";
-            case SOURCE_INPUT_METHOD: return "SOURCE_INPUT_METHOD";
-            case SOURCE_DRAG_AND_DROP: return "SOURCE_DRAG_AND_DROP";
-            case SOURCE_AUTOFILL: return "SOURCE_AUTOFILL";
-            case SOURCE_PROCESS_TEXT: return "SOURCE_PROCESS_TEXT";
-        }
-        return String.valueOf(source);
-    }
-
-    /**
-     * Returns the symbolic names of the set flags or {@code "0"} if no flags are set.
-     *
-     * @hide
-     */
-    static String flagsToString(@Flags int flags) {
-        if ((flags & FLAG_CONVERT_TO_PLAIN_TEXT) != 0) {
-            return "FLAG_CONVERT_TO_PLAIN_TEXT";
-        }
-        return String.valueOf(flags);
-    }
-}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6f14dfb..52a3f41 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,12 +17,15 @@
 package android.widget;
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.view.OnReceiveContentCallback.Payload.FLAG_CONVERT_TO_PLAIN_TEXT;
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_AUTOFILL;
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_CLIPBOARD;
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_PROCESS_TEXT;
 import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY;
 import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH;
 import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX;
 import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY;
 import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
-import static android.widget.RichContentReceiver.SOURCE_PROCESS_TEXT;
 
 import android.R;
 import android.annotation.CallSuper;
@@ -39,6 +42,7 @@
 import android.annotation.Size;
 import android.annotation.StringRes;
 import android.annotation.StyleRes;
+import android.annotation.TestApi;
 import android.annotation.XmlRes;
 import android.app.Activity;
 import android.app.PendingIntent;
@@ -149,6 +153,7 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.OnReceiveContentCallback;
 import android.view.PointerIcon;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -426,7 +431,8 @@
     /**
      * @hide
      */
-    static final int PROCESS_TEXT_REQUEST_CODE = 100;
+    @TestApi
+    public static final int PROCESS_TEXT_REQUEST_CODE = 100;
 
     /**
      *  Return code of {@link #doKeyDown}.
@@ -735,6 +741,10 @@
     private boolean mLocalesChanged = false;
     private int mTextSizeUnit = -1;
 
+    // True if force bold text feature is enabled. This feature makes all text bolder.
+    private boolean mForceBoldTextEnabled;
+    private Typeface mOriginalTypeface;
+
     // True if setKeyListener() has been explicitly called
     private boolean mListenerChanged = false;
     // True if internationalized input should be used for numbers and date and time.
@@ -882,12 +892,10 @@
 
     /**
      * The default content insertion callback used by {@link TextView}. See
-     * {@link #setRichContentReceiver} for more info.
+     * {@link #setOnReceiveContentCallback} for more info.
      */
-    public static final @NonNull RichContentReceiver<TextView> DEFAULT_RICH_CONTENT_RECEIVER =
-            TextViewRichContentReceiver.INSTANCE;
-
-    private RichContentReceiver<TextView> mRichContentReceiver = DEFAULT_RICH_CONTENT_RECEIVER;
+    private static final TextViewOnReceiveContentCallback DEFAULT_ON_RECEIVE_CONTENT_CALLBACK =
+            new TextViewOnReceiveContentCallback();
 
     private static final int DEVICE_PROVISIONED_UNKNOWN = 0;
     private static final int DEVICE_PROVISIONED_NO = 1;
@@ -1645,6 +1653,8 @@
             attributes.mTypefaceIndex = MONOSPACE;
         }
 
+        mForceBoldTextEnabled = getContext().getResources().getConfiguration().forceBoldText
+                == Configuration.FORCE_BOLD_TEXT_YES;
         applyTextAppearance(attributes);
 
         if (isPassword) {
@@ -2138,15 +2148,20 @@
     /**
      * @hide
      */
+    @TestApi
     @Override
-    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
         if (requestCode == PROCESS_TEXT_REQUEST_CODE) {
             if (resultCode == Activity.RESULT_OK && data != null) {
                 CharSequence result = data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT);
                 if (result != null) {
                     if (isTextEditable()) {
                         ClipData clip = ClipData.newPlainText("", result);
-                        mRichContentReceiver.onReceive(this, clip, SOURCE_PROCESS_TEXT, 0);
+                        OnReceiveContentCallback.Payload payload =
+                                new OnReceiveContentCallback.Payload.Builder(
+                                        clip, SOURCE_PROCESS_TEXT)
+                                        .build();
+                        onReceiveContent(payload);
                         if (mEditor != null) {
                             mEditor.refreshTextActionMode();
                         }
@@ -4267,6 +4282,14 @@
                 invalidate();
             }
         }
+        if (newConfig.forceBoldText == Configuration.FORCE_BOLD_TEXT_YES) {
+            mForceBoldTextEnabled = true;
+            setTypeface(getTypeface());
+        } else  if (newConfig.forceBoldText == Configuration.FORCE_BOLD_TEXT_NO
+                || newConfig.forceBoldText == Configuration.FORCE_BOLD_TEXT_UNDEFINED) {
+            mForceBoldTextEnabled = false;
+            setTypeface(getTypeface());
+        }
     }
 
     /**
@@ -4418,6 +4441,14 @@
      * @attr ref android.R.styleable#TextView_textStyle
      */
     public void setTypeface(@Nullable Typeface tf) {
+        mOriginalTypeface = tf;
+        if (mForceBoldTextEnabled) {
+            int newWeight = tf != null ? tf.getWeight() + 300 : 400;
+            newWeight = Math.min(newWeight, 1000);
+            int typefaceStyle = tf != null ? tf.getStyle() : 0;
+            boolean italic = (typefaceStyle & Typeface.ITALIC) != 0;
+            tf = Typeface.create(tf, newWeight, italic);
+        }
         if (mTextPaint.getTypeface() != tf) {
             mTextPaint.setTypeface(tf);
 
@@ -4441,7 +4472,7 @@
      */
     @InspectableProperty
     public Typeface getTypeface() {
-        return mTextPaint.getTypeface();
+        return mOriginalTypeface;
     }
 
     /**
@@ -8722,9 +8753,10 @@
                 outAttrs.initialSelEnd = getSelectionEnd();
                 outAttrs.initialCapsMode = ic.getCursorCapsMode(getInputType());
                 outAttrs.setInitialSurroundingText(mText);
-                int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
-                if (targetSdkVersion > Build.VERSION_CODES.R) {
-                    outAttrs.contentMimeTypes = mRichContentReceiver.getSupportedMimeTypes()
+                // If a custom `OnReceiveContentCallback` is set, pass its supported MIME types.
+                OnReceiveContentCallback<TextView> receiver = getOnReceiveContentCallback();
+                if (receiver != null) {
+                    outAttrs.contentMimeTypes = receiver.getSupportedMimeTypes(this)
                             .toArray(new String[0]);
                 }
                 return ic;
@@ -11827,7 +11859,7 @@
             Log.w(LOG_TAG, "cannot autofill non-editable TextView: " + this);
             return;
         }
-        ClipData clip;
+        final ClipData clip;
         if (value.isRichContent()) {
             clip = value.getRichContentValue();
         } else if (value.isText()) {
@@ -11837,22 +11869,14 @@
                     + " cannot be autofilled into " + this);
             return;
         }
-        mRichContentReceiver.onReceive(this, clip, RichContentReceiver.SOURCE_AUTOFILL, 0);
+        final OnReceiveContentCallback.Payload payload =
+                new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_AUTOFILL).build();
+        onReceiveContent(payload);
     }
 
     @Override
     public @AutofillType int getAutofillType() {
-        if (!isTextEditable()) {
-            return AUTOFILL_TYPE_NONE;
-        }
-        final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
-        if (targetSdkVersion <= Build.VERSION_CODES.R) {
-            return AUTOFILL_TYPE_TEXT;
-        }
-        // TODO(b/147301047): Update autofill framework code to check the target SDK of the autofill
-        //  provider and force the type AUTOFILL_TYPE_TEXT for providers that target older SDKs.
-        return mRichContentReceiver.supportsNonTextContent() ? AUTOFILL_TYPE_RICH_CONTENT
-                : AUTOFILL_TYPE_TEXT;
+        return isTextEditable() ? AUTOFILL_TYPE_TEXT : AUTOFILL_TYPE_NONE;
     }
 
     /**
@@ -12913,8 +12937,11 @@
         if (clip == null) {
             return;
         }
-        int flags = withFormatting ? 0 : RichContentReceiver.FLAG_CONVERT_TO_PLAIN_TEXT;
-        mRichContentReceiver.onReceive(this, clip, RichContentReceiver.SOURCE_CLIPBOARD, flags);
+        final OnReceiveContentCallback.Payload payload =
+                new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_CLIPBOARD)
+                .setFlags(withFormatting ? 0 : FLAG_CONVERT_TO_PLAIN_TEXT)
+                .build();
+        onReceiveContent(payload);
         sLastCutCopyOrTextChangedTime = 0;
     }
 
@@ -13697,43 +13724,58 @@
     }
 
     /**
-     * Returns the callback that handles insertion of content into this view (e.g. pasting from
-     * the clipboard). See {@link #setRichContentReceiver} for more info.
+     * Returns the callback used for handling insertion of content into this view. See
+     * {@link #setOnReceiveContentCallback} for more info.
      *
-     * @return The callback that this view is using to handle insertion of content. Returns
-     * {@link #DEFAULT_RICH_CONTENT_RECEIVER} if no custom callback has been
-     * {@link #setRichContentReceiver set}.
+     * @return The callback for handling insertion of content. Returns null if no callback has been
+     * {@link #setOnReceiveContentCallback set}.
      */
-    @NonNull
-    public RichContentReceiver<TextView> getRichContentReceiver() {
-        return mRichContentReceiver;
+    @SuppressWarnings("unchecked")
+    @Nullable
+    @Override
+    public OnReceiveContentCallback<TextView> getOnReceiveContentCallback() {
+        return (OnReceiveContentCallback<TextView>) super.getOnReceiveContentCallback();
     }
 
     /**
      * Sets the callback to handle insertion of content into this view.
      *
-     * <p>"Content" and "rich content" here refers to both text and non-text: plain text, styled
-     * text, HTML, images, videos, audio files, etc.
-     *
-     * <p>The callback configured here should typically wrap {@link #DEFAULT_RICH_CONTENT_RECEIVER}
-     * to provide consistent behavior for text content.
-     *
      * <p>This callback will be invoked for the following scenarios:
      * <ol>
      *     <li>Paste from the clipboard (e.g. "Paste" or "Paste as plain text" action in the
      *     insertion/selection menu)
-     *     <li>Content insertion from the keyboard ({@link InputConnection#commitContent})
-     *     <li>Drag and drop ({@link View#onDragEvent})
-     *     <li>Autofill, when the type for the field is
-     *     {@link android.view.View.AutofillType#AUTOFILL_TYPE_RICH_CONTENT}
+     *     <li>Content insertion from the keyboard (from {@link InputConnection#commitContent})
+     *     <li>Drag and drop (drop events from {@link #onDragEvent(DragEvent)})
+     *     <li>Autofill (from {@link #autofill(AutofillValue)})
+     *     <li>{@link Intent#ACTION_PROCESS_TEXT} replacement
      * </ol>
      *
-     * @param receiver The callback to use. This can be {@link #DEFAULT_RICH_CONTENT_RECEIVER} to
-     * reset to the default behavior.
+     * <p>The callback will only be invoked if the MIME type of the content is
+     * {@link OnReceiveContentCallback#getSupportedMimeTypes declared as supported} by the callback.
+     * If the content type is not supported by the callback, the default platform handling will be
+     * executed instead.
+     *
+     * @param callback The callback to use. This can be null to reset to the default behavior.
      */
-    public void setRichContentReceiver(@NonNull RichContentReceiver<TextView> receiver) {
-        mRichContentReceiver = Objects.requireNonNull(receiver,
-                "RichContentReceiver should not be null.");
+    @Override
+    public void setOnReceiveContentCallback(
+            @Nullable OnReceiveContentCallback<? extends View> callback) {
+        super.setOnReceiveContentCallback(callback);
+    }
+
+    /**
+     * Handles the request to insert content using the configured callback or the default callback.
+     *
+     * @hide
+     */
+    void onReceiveContent(@NonNull OnReceiveContentCallback.Payload payload) {
+        OnReceiveContentCallback<TextView> receiver = getOnReceiveContentCallback();
+        ClipDescription description = payload.getClip().getDescription();
+        if (receiver != null && receiver.supports(this, description)) {
+            receiver.onReceiveContent(this, payload);
+        } else {
+            DEFAULT_ON_RECEIVE_CONTENT_CALLBACK.onReceiveContent(this, payload);
+        }
     }
 
     private static void logCursor(String location, @Nullable String msgFormat, Object ... msgArgs) {
diff --git a/core/java/android/widget/TextViewRichContentReceiver.java b/core/java/android/widget/TextViewOnReceiveContentCallback.java
similarity index 71%
rename from core/java/android/widget/TextViewRichContentReceiver.java
rename to core/java/android/widget/TextViewOnReceiveContentCallback.java
index 4f2d954..35618cb 100644
--- a/core/java/android/widget/TextViewRichContentReceiver.java
+++ b/core/java/android/widget/TextViewOnReceiveContentCallback.java
@@ -16,7 +16,12 @@
 
 package android.widget;
 
+import static android.view.OnReceiveContentCallback.Payload.FLAG_CONVERT_TO_PLAIN_TEXT;
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_AUTOFILL;
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_DRAG_AND_DROP;
+
 import android.annotation.NonNull;
+import android.annotation.SuppressLint;
 import android.content.ClipData;
 import android.content.Context;
 import android.text.Editable;
@@ -24,54 +29,45 @@
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.util.Log;
+import android.view.OnReceiveContentCallback;
+import android.view.OnReceiveContentCallback.Payload.Flags;
+import android.view.OnReceiveContentCallback.Payload.Source;
 
 import java.util.Collections;
 import java.util.Set;
 
 /**
- * Default implementation of {@link RichContentReceiver} for editable {@link TextView} components.
- * This class handles insertion of text (plain text, styled text, HTML, etc) but not images or other
- * rich content. Typically this class will be used as a delegate by custom implementations of
- * {@link RichContentReceiver}, to provide consistent behavior for insertion of text while
- * implementing custom behavior for insertion of other content (images, etc). See
- * {@link TextView#DEFAULT_RICH_CONTENT_RECEIVER}.
- *
- * @hide
+ * Default implementation of {@link android.view.OnReceiveContentCallback} for editable
+ * {@link TextView} components. This class handles insertion of text (plain text, styled text, HTML,
+ * etc) but not images or other content. This class can be used as a base class for an
+ * implementation of {@link android.view.OnReceiveContentCallback} for a {@link TextView}, to
+ * provide consistent behavior for insertion of text.
  */
-final class TextViewRichContentReceiver implements RichContentReceiver<TextView> {
-    static final TextViewRichContentReceiver INSTANCE = new TextViewRichContentReceiver();
-
-    private static final String LOG_TAG = "RichContentReceiver";
+public class TextViewOnReceiveContentCallback implements OnReceiveContentCallback<TextView> {
+    private static final String LOG_TAG = "OnReceiveContent";
 
     private static final Set<String> MIME_TYPES_ALL_TEXT = Collections.singleton("text/*");
 
+    @SuppressLint("CallbackMethodName")
+    @NonNull
     @Override
-    public Set<String> getSupportedMimeTypes() {
+    public Set<String> getSupportedMimeTypes(@NonNull TextView view) {
         return MIME_TYPES_ALL_TEXT;
     }
 
     @Override
-    public boolean onReceive(@NonNull TextView textView, @NonNull ClipData clip,
-            @Source int source, @Flags int flags) {
+    public boolean onReceiveContent(@NonNull TextView view, @NonNull Payload payload) {
         if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
-            StringBuilder sb = new StringBuilder("onReceive: clip=");
-            if (clip.getDescription() == null) {
-                sb.append("null");
-            } else {
-                clip.getDescription().toShortStringTypesOnly(sb);
-            }
-            sb.append(", source=").append(RichContentReceiver.sourceToString(source));
-            sb.append(", flags=").append(RichContentReceiver.flagsToString(flags));
-            Log.d(LOG_TAG, sb.toString());
+            Log.d(LOG_TAG, "onReceive:" + payload);
         }
+        ClipData clip = payload.getClip();
+        @Source int source = payload.getSource();
+        @Flags int flags = payload.getFlags();
         if (source == SOURCE_AUTOFILL) {
-            return onReceiveForAutofill(textView, clip, flags);
+            return onReceiveForAutofill(view, clip, flags);
         }
         if (source == SOURCE_DRAG_AND_DROP) {
-            return onReceiveForDragAndDrop(textView, clip, flags);
-        }
-        if (source == SOURCE_INPUT_METHOD && !supports(clip.getDescription())) {
-            return false;
+            return onReceiveForDragAndDrop(view, clip, flags);
         }
 
         // The code here follows the original paste logic from TextView:
@@ -79,8 +75,8 @@
         // In particular, multiple items within the given ClipData will trigger separate calls to
         // replace/insert. This is to preserve the original behavior with respect to TextWatcher
         // notifications fired from SpannableStringBuilder when replace/insert is called.
-        final Editable editable = (Editable) textView.getText();
-        final Context context = textView.getContext();
+        final Editable editable = (Editable) view.getText();
+        final Context context = view.getContext();
         boolean didFirst = false;
         for (int i = 0; i < clip.getItemCount(); i++) {
             CharSequence itemText;
@@ -100,7 +96,7 @@
                 }
             }
         }
-        return didFirst;
+        return true;
     }
 
     private static void replaceSelection(@NonNull Editable editable,
@@ -128,7 +124,7 @@
             @NonNull ClipData clip, @Flags int flags) {
         final CharSequence text = coerceToText(clip, textView.getContext(), flags);
         if (text.length() == 0) {
-            return false;
+            return true;
         }
         replaceSelection((Editable) textView.getText(), text);
         return true;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 944f2ec..61a625e 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1771,7 +1771,7 @@
                 case ChooserListAdapter.TARGET_CALLER:
                 case ChooserListAdapter.TARGET_STANDARD:
                     cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET;
-                    value -= currentListAdapter.getSelectableServiceTargetCount();
+                    value -= currentListAdapter.getSurfacedTargetInfo().size();
                     numCallerProvided = currentListAdapter.getCallerTargetCount();
                     getChooserActivityLogger().logShareTargetSelected(
                             SELECTION_TYPE_APP,
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 4a0e26a..308af99 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -145,7 +145,7 @@
     private static final boolean DEBUG = false;
     public static final boolean DEBUG_ENERGY = false;
     private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY;
-    private static final boolean DEBUG_BINDER_STATS = true;
+    private static final boolean DEBUG_BINDER_STATS = false;
     private static final boolean DEBUG_MEMORY = false;
     private static final boolean DEBUG_HISTORY = false;
     private static final boolean USE_OLD_HISTORY = false;   // for debugging.
@@ -156,7 +156,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    static final int VERSION = 188 + (USE_OLD_HISTORY ? 1000 : 0);
+    static final int VERSION = 189 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -221,7 +221,8 @@
     @VisibleForTesting
     protected KernelSingleUidTimeReader mKernelSingleUidTimeReader;
     @VisibleForTesting
-    protected SystemServerCpuThreadReader mSystemServerCpuThreadReader;
+    protected SystemServerCpuThreadReader mSystemServerCpuThreadReader =
+            SystemServerCpuThreadReader.create();
 
     private final KernelMemoryBandwidthStats mKernelMemoryBandwidthStats
             = new KernelMemoryBandwidthStats();
@@ -1014,14 +1015,21 @@
     private long[] mCpuFreqs;
 
     /**
+     * Times spent by the system server process grouped by cluster and CPU speed.
+     */
+    private LongSamplingCounterArray mSystemServerCpuTimesUs;
+
+    private long[] mTmpSystemServerCpuTimesUs;
+
+    /**
      * Times spent by the system server threads grouped by cluster and CPU speed.
      */
-    private LongSamplingCounter[][] mSystemServerThreadCpuTimesUs;
+    private LongSamplingCounterArray mSystemServerThreadCpuTimesUs;
 
     /**
      * Times spent by the system server threads handling incoming binder requests.
      */
-    private LongSamplingCounter[][] mBinderThreadCpuTimesUs;
+    private LongSamplingCounterArray mBinderThreadCpuTimesUs;
 
     @VisibleForTesting
     protected PowerProfile mPowerProfile;
@@ -10610,8 +10618,6 @@
             firstCpuOfCluster += mPowerProfile.getNumCoresInCpuCluster(i);
         }
 
-        mSystemServerCpuThreadReader = SystemServerCpuThreadReader.create();
-
         if (mEstimatedBatteryCapacity == -1) {
             // Initialize the estimated battery capacity to a known preset one.
             mEstimatedBatteryCapacity = (int) mPowerProfile.getBatteryCapacity();
@@ -11291,6 +11297,7 @@
 
         mTmpRailStats.reset();
 
+        resetIfNotNull(mSystemServerCpuTimesUs, false, elapsedRealtimeUs);
         resetIfNotNull(mSystemServerThreadCpuTimesUs, false, elapsedRealtimeUs);
         resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs);
 
@@ -12421,38 +12428,58 @@
 
         SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
                     mSystemServerCpuThreadReader.readDelta();
+        if (systemServiceCpuThreadTimes == null) {
+            return;
+        }
 
-        int index = 0;
         int numCpuClusters = mPowerProfile.getNumCpuClusters();
-        if (mSystemServerThreadCpuTimesUs == null) {
-            mSystemServerThreadCpuTimesUs = new LongSamplingCounter[numCpuClusters][];
-            mBinderThreadCpuTimesUs = new LongSamplingCounter[numCpuClusters][];
+        if (mSystemServerCpuTimesUs == null) {
+            mSystemServerCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
+            mSystemServerThreadCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
+            mBinderThreadCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
         }
-        for (int cluster = 0; cluster < numCpuClusters; cluster++) {
-            int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
-            if (mSystemServerThreadCpuTimesUs[cluster] == null) {
-                mSystemServerThreadCpuTimesUs[cluster] = new LongSamplingCounter[numSpeeds];
-                mBinderThreadCpuTimesUs[cluster] = new LongSamplingCounter[numSpeeds];
-                for (int speed = 0; speed < numSpeeds; speed++) {
-                    mSystemServerThreadCpuTimesUs[cluster][speed] =
-                            new LongSamplingCounter(mOnBatteryTimeBase);
-                    mBinderThreadCpuTimesUs[cluster][speed] =
-                            new LongSamplingCounter(mOnBatteryTimeBase);
-                }
-            }
-            for (int speed = 0; speed < numSpeeds; speed++) {
-                mSystemServerThreadCpuTimesUs[cluster][speed].addCountLocked(
-                        systemServiceCpuThreadTimes.threadCpuTimesUs[index]);
-                mBinderThreadCpuTimesUs[cluster][speed].addCountLocked(
-                        systemServiceCpuThreadTimes.binderThreadCpuTimesUs[index]);
-                index++;
-            }
+        mSystemServerThreadCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.threadCpuTimesUs);
+        mBinderThreadCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
+
+        long totalCpuTimeAllThreads = 0;
+        for (int index = systemServiceCpuThreadTimes.threadCpuTimesUs.length - 1; index >= 0;
+                index--) {
+            totalCpuTimeAllThreads += systemServiceCpuThreadTimes.threadCpuTimesUs[index];
         }
+
+        // Estimate per cluster per frequency CPU time for the entire process
+        // by distributing the total process CPU time proportionately to how much
+        // CPU time its threads took on those clusters/frequencies.  This algorithm
+        // works more accurately when when we have equally distributed concurrency.
+        // TODO(b/169279846): obtain actual process CPU times from the kernel
+        long processCpuTime = systemServiceCpuThreadTimes.processCpuTimeUs;
+        if (mTmpSystemServerCpuTimesUs == null) {
+            mTmpSystemServerCpuTimesUs =
+                    new long[systemServiceCpuThreadTimes.threadCpuTimesUs.length];
+        }
+        for (int index = systemServiceCpuThreadTimes.threadCpuTimesUs.length - 1; index >= 0;
+                index--) {
+            mTmpSystemServerCpuTimesUs[index] =
+                    processCpuTime * systemServiceCpuThreadTimes.threadCpuTimesUs[index]
+                            / totalCpuTimeAllThreads;
+
+        }
+
+        mSystemServerCpuTimesUs.addCountLocked(mTmpSystemServerCpuTimesUs);
+
         if (DEBUG_BINDER_STATS) {
             Slog.d(TAG, "System server threads per CPU cluster (binder threads/total threads/%)");
-            long binderThreadTimeMs = 0;
+            long totalCpuTimeMs = 0;
             long totalThreadTimeMs = 0;
+            long binderThreadTimeMs = 0;
             int cpuIndex = 0;
+            final long[] systemServerCpuTimesUs =
+                    mSystemServerCpuTimesUs.getCountsLocked(0);
+            final long[] systemServerThreadCpuTimesUs =
+                    mSystemServerThreadCpuTimesUs.getCountsLocked(0);
+            final long[] binderThreadCpuTimesUs =
+                    mBinderThreadCpuTimesUs.getCountsLocked(0);
+            int index = 0;
             for (int cluster = 0; cluster < numCpuClusters; cluster++) {
                 StringBuilder sb = new StringBuilder();
                 sb.append("cpu").append(cpuIndex).append(": [");
@@ -12461,15 +12488,14 @@
                     if (speed != 0) {
                         sb.append(", ");
                     }
-                    long totalCountMs =
-                            mSystemServerThreadCpuTimesUs[cluster][speed].getCountLocked(0) / 1000;
-                    long binderCountMs = mBinderThreadCpuTimesUs[cluster][speed].getCountLocked(0)
-                            / 1000;
+                    long totalCountMs = systemServerThreadCpuTimesUs[index] / 1000;
+                    long binderCountMs = binderThreadCpuTimesUs[index] / 1000;
                     sb.append(String.format("%d/%d(%.1f%%)",
                             binderCountMs,
                             totalCountMs,
                             totalCountMs != 0 ? (double) binderCountMs * 100 / totalCountMs : 0));
 
+                    totalCpuTimeMs += systemServerCpuTimesUs[index] / 1000;
                     totalThreadTimeMs += totalCountMs;
                     binderThreadTimeMs += binderCountMs;
                     index++;
@@ -12477,6 +12503,8 @@
                 cpuIndex += mPowerProfile.getNumCoresInCpuCluster(cluster);
                 Slog.d(TAG, sb.toString());
             }
+
+            Slog.d(TAG, "Total system server CPU time (ms): " + totalCpuTimeMs);
             Slog.d(TAG, "Total system server thread time (ms): " + totalThreadTimeMs);
             Slog.d(TAG, String.format("Total Binder thread time (ms): %d (%.1f%%)",
                     binderThreadTimeMs,
@@ -13715,7 +13743,7 @@
 
 
     @Override
-    public long getSystemServiceTimeAtCpuSpeed(int cluster, int step) {
+    public long[] getSystemServiceTimeAtCpuSpeeds() {
         // Estimates the time spent by the system server handling incoming binder requests.
         //
         // The data that we can get from the kernel is this:
@@ -13731,7 +13759,7 @@
         // - These 10 threads spent 1000 ms of CPU time in aggregate
         // - Of the 10 threads 4 were execute exclusively incoming binder calls.
         // - These 4 "binder" threads consumed 600 ms of CPU time in aggregate
-        // - The real time spent by the system server UID doing all of this is, say, 200 ms.
+        // - The real time spent by the system server process doing all of this is, say, 200 ms.
         //
         // We will assume that power consumption is proportional to the time spent by the CPU
         // across all threads.  This is a crude assumption, but we don't have more detailed data.
@@ -13745,41 +13773,29 @@
         // of the total power consumed by incoming binder calls for the given cluster/speed
         // combination.
 
-        if (mSystemServerThreadCpuTimesUs == null) {
-            return 0;
+        if (mSystemServerCpuTimesUs == null) {
+            return null;
         }
 
-        if (cluster < 0 || cluster >= mSystemServerThreadCpuTimesUs.length) {
-            return 0;
-        }
-
-        final LongSamplingCounter[] threadTimesForCluster = mSystemServerThreadCpuTimesUs[cluster];
-
-        if (step < 0 || step >= threadTimesForCluster.length) {
-            return 0;
-        }
-
-        Uid systemUid = mUidStats.get(Process.SYSTEM_UID);
-        if (systemUid == null) {
-            return 0;
-        }
-
-        final long uidTimeAtCpuSpeedUs = systemUid.getTimeAtCpuSpeed(cluster, step,
+        final long[] systemServerCpuTimesUs = mSystemServerCpuTimesUs.getCountsLocked(
                 BatteryStats.STATS_SINCE_CHARGED);
-        if (uidTimeAtCpuSpeedUs == 0) {
-            return 0;
-        }
-
-        final long uidThreadTimeUs =
-                threadTimesForCluster[step].getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
-
-        if (uidThreadTimeUs == 0) {
-            return 0;
-        }
-
-        final long binderThreadTimeUs = mBinderThreadCpuTimesUs[cluster][step].getCountLocked(
+        final long [] systemServerThreadCpuTimesUs = mSystemServerThreadCpuTimesUs.getCountsLocked(
                 BatteryStats.STATS_SINCE_CHARGED);
-        return uidTimeAtCpuSpeedUs * binderThreadTimeUs / uidThreadTimeUs;
+        final long[] binderThreadCpuTimesUs = mBinderThreadCpuTimesUs.getCountsLocked(
+                BatteryStats.STATS_SINCE_CHARGED);
+
+        final int size = systemServerCpuTimesUs.length;
+        final long[] results = new long[size];
+
+        for (int i = 0; i < size; i++) {
+            if (systemServerThreadCpuTimesUs[i] == 0) {
+                continue;
+            }
+
+            results[i] = systemServerCpuTimesUs[i] * binderThreadCpuTimesUs[i]
+                    / systemServerThreadCpuTimesUs[i];
+        }
+        return results;
     }
 
     /**
@@ -14181,18 +14197,14 @@
         updateSystemServiceCallStats();
         if (mSystemServerThreadCpuTimesUs != null) {
             pw.println("Per UID System server binder time in ms:");
+            long[] systemServiceTimeAtCpuSpeeds = getSystemServiceTimeAtCpuSpeeds();
             for (int i = 0; i < size; i++) {
                 int u = mUidStats.keyAt(i);
                 Uid uid = mUidStats.get(u);
                 double proportionalSystemServiceUsage = uid.getProportionalSystemServiceUsage();
-
                 long timeUs = 0;
-                for (int cluster = 0; cluster < mSystemServerThreadCpuTimesUs.length; cluster++) {
-                    int numSpeeds = mSystemServerThreadCpuTimesUs[cluster].length;
-                    for (int speed = 0; speed < numSpeeds; speed++) {
-                        timeUs += getSystemServiceTimeAtCpuSpeed(cluster, speed)
-                                * proportionalSystemServiceUsage;
-                    }
+                for (int j = systemServiceTimeAtCpuSpeeds.length - 1; j >= 0; j--) {
+                    timeUs += systemServiceTimeAtCpuSpeeds[j] * proportionalSystemServiceUsage;
                 }
 
                 pw.print("  ");
@@ -15728,8 +15740,10 @@
             mUidStats.append(uid, u);
         }
 
-        mSystemServerThreadCpuTimesUs = readCpuSpeedCountersFromParcel(in);
-        mBinderThreadCpuTimesUs = readCpuSpeedCountersFromParcel(in);
+        mSystemServerCpuTimesUs = LongSamplingCounterArray.readFromParcel(in, mOnBatteryTimeBase);
+        mSystemServerThreadCpuTimesUs = LongSamplingCounterArray.readFromParcel(in,
+                mOnBatteryTimeBase);
+        mBinderThreadCpuTimesUs = LongSamplingCounterArray.readFromParcel(in, mOnBatteryTimeBase);
     }
 
     public void writeToParcel(Parcel out, int flags) {
@@ -15778,7 +15792,7 @@
 
         mScreenOnTimer.writeToParcel(out, uSecRealtime);
         mScreenDozeTimer.writeToParcel(out, uSecRealtime);
-        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+        for (int i = 0; i < NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i].writeToParcel(out, uSecRealtime);
         }
         mInteractiveTimer.writeToParcel(out, uSecRealtime);
@@ -15794,7 +15808,7 @@
             mPhoneSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
         }
         mPhoneSignalScanningTimer.writeToParcel(out, uSecRealtime);
-        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
+        for (int i = 0; i < NUM_DATA_CONNECTION_TYPES; i++) {
             mPhoneDataConnectionsTimer[i].writeToParcel(out, uSecRealtime);
         }
         for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
@@ -15809,18 +15823,18 @@
         mWifiMulticastWakelockTimer.writeToParcel(out, uSecRealtime);
         mWifiOnTimer.writeToParcel(out, uSecRealtime);
         mGlobalWifiRunningTimer.writeToParcel(out, uSecRealtime);
-        for (int i=0; i<NUM_WIFI_STATES; i++) {
+        for (int i = 0; i < NUM_WIFI_STATES; i++) {
             mWifiStateTimer[i].writeToParcel(out, uSecRealtime);
         }
-        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+        for (int i = 0; i < NUM_WIFI_SUPPL_STATES; i++) {
             mWifiSupplStateTimer[i].writeToParcel(out, uSecRealtime);
         }
-        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+        for (int i = 0; i < NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
             mWifiSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
         }
         mWifiActiveTimer.writeToParcel(out, uSecRealtime);
         mWifiActivity.writeToParcel(out, 0);
-        for (int i=0; i< GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
+        for (int i = 0; i < GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
             mGpsSignalQualityTimer[i].writeToParcel(out, uSecRealtime);
         }
         mBluetoothActivity.writeToParcel(out, 0);
@@ -15930,8 +15944,9 @@
         } else {
             out.writeInt(0);
         }
-        writeCpuSpeedCountersToParcel(out, mSystemServerThreadCpuTimesUs);
-        writeCpuSpeedCountersToParcel(out, mBinderThreadCpuTimesUs);
+        LongSamplingCounterArray.writeToParcel(out, mSystemServerCpuTimesUs);
+        LongSamplingCounterArray.writeToParcel(out, mSystemServerThreadCpuTimesUs);
+        LongSamplingCounterArray.writeToParcel(out, mBinderThreadCpuTimesUs);
     }
 
     private void writeCpuSpeedCountersToParcel(Parcel out, LongSamplingCounter[][] counters) {
diff --git a/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java b/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
new file mode 100644
index 0000000..0578b89
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
@@ -0,0 +1,259 @@
+/*
+ * 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.internal.os;
+
+import static android.os.Process.PROC_OUT_LONG;
+import static android.os.Process.PROC_SPACE_TERM;
+
+import android.annotation.Nullable;
+import android.os.Process;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.IOException;
+import java.nio.file.DirectoryIteratorException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Iterates over all threads owned by a given process, and return the CPU usage for
+ * each thread. The CPU usage statistics contain the amount of time spent in a frequency band. CPU
+ * usage is collected using {@link ProcTimeInStateReader}.
+ */
+public class KernelSingleProcessCpuThreadReader {
+
+    private static final String TAG = "KernelSingleProcCpuThreadRdr";
+
+    private static final boolean DEBUG = false;
+
+    /**
+     * The name of the file to read CPU statistics from, must be found in {@code
+     * /proc/$PID/task/$TID}
+     */
+    private static final String CPU_STATISTICS_FILENAME = "time_in_state";
+
+    private static final String PROC_STAT_FILENAME = "stat";
+
+    /** Directory under /proc/$PID containing CPU stats files for threads */
+    public static final String THREAD_CPU_STATS_DIRECTORY = "task";
+
+    /** Default mount location of the {@code proc} filesystem */
+    private static final Path DEFAULT_PROC_PATH = Paths.get("/proc");
+
+    /** The initial {@code time_in_state} file for {@link ProcTimeInStateReader} */
+    private static final Path INITIAL_TIME_IN_STATE_PATH = Paths.get("self/time_in_state");
+
+    /** See https://man7.org/linux/man-pages/man5/proc.5.html */
+    private static final int[] PROCESS_FULL_STATS_FORMAT = new int[]{
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM | PROC_OUT_LONG,                  // 14: utime
+            PROC_SPACE_TERM | PROC_OUT_LONG,                  // 15: stime
+            // Ignore remaining fields
+    };
+
+    private final long[] mProcessFullStatsData = new long[2];
+
+    private static final int PROCESS_FULL_STAT_UTIME = 0;
+    private static final int PROCESS_FULL_STAT_STIME = 1;
+
+    /** Used to read and parse {@code time_in_state} files */
+    private final ProcTimeInStateReader mProcTimeInStateReader;
+
+    private final int mPid;
+
+    /** Where the proc filesystem is mounted */
+    private final Path mProcPath;
+
+    // How long a CPU jiffy is in milliseconds.
+    private final long mJiffyMillis;
+
+    // Path: /proc/<pid>/stat
+    private final String mProcessStatFilePath;
+
+    // Path: /proc/<pid>/task
+    private final Path mThreadsDirectoryPath;
+
+    /**
+     * Count of frequencies read from the {@code time_in_state} file. Read from {@link
+     * #mProcTimeInStateReader#getCpuFrequenciesKhz()}.
+     */
+    private int mFrequencyCount;
+
+    /**
+     * Create with a path where `proc` is mounted. Used primarily for testing
+     *
+     * @param pid      PID of the process whose threads are to be read.
+     * @param procPath where `proc` is mounted (to find, see {@code mount | grep ^proc})
+     */
+    @VisibleForTesting
+    public KernelSingleProcessCpuThreadReader(
+            int pid,
+            Path procPath) throws IOException {
+        mPid = pid;
+        mProcPath = procPath;
+        mProcTimeInStateReader = new ProcTimeInStateReader(
+                mProcPath.resolve(INITIAL_TIME_IN_STATE_PATH));
+        long jiffyHz = Os.sysconf(OsConstants._SC_CLK_TCK);
+        mJiffyMillis = 1000 / jiffyHz;
+        mProcessStatFilePath =
+                mProcPath.resolve(String.valueOf(mPid)).resolve(PROC_STAT_FILENAME).toString();
+        mThreadsDirectoryPath =
+                mProcPath.resolve(String.valueOf(mPid)).resolve(THREAD_CPU_STATS_DIRECTORY);
+    }
+
+    /**
+     * Create the reader and handle exceptions during creation
+     *
+     * @return the reader, null if an exception was thrown during creation
+     */
+    @Nullable
+    public static KernelSingleProcessCpuThreadReader create(int pid) {
+        try {
+            return new KernelSingleProcessCpuThreadReader(pid, DEFAULT_PROC_PATH);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to initialize KernelSingleProcessCpuThreadReader", e);
+            return null;
+        }
+    }
+
+    /**
+     * Get the CPU frequencies that correspond to the times reported in {@link
+     * ThreadCpuUsage#usageTimesMillis}
+     */
+    public int getCpuFrequencyCount() {
+        if (mFrequencyCount == 0) {
+            mFrequencyCount = mProcTimeInStateReader.getFrequenciesKhz().length;
+        }
+        return mFrequencyCount;
+    }
+
+    /**
+     * Get the total and per-thread CPU usage of the process with the PID specified in the
+     * constructor.
+     */
+    @Nullable
+    public ProcessCpuUsage getProcessCpuUsage() {
+        if (DEBUG) {
+            Slog.d(TAG, "Reading CPU thread usages with directory " + mProcPath + " process ID "
+                    + mPid);
+        }
+
+        if (!Process.readProcFile(mProcessStatFilePath, PROCESS_FULL_STATS_FORMAT, null,
+                mProcessFullStatsData, null)) {
+            Slog.e(TAG, "Failed to read process stat file " + mProcessStatFilePath);
+            return null;
+        }
+
+        long utime = mProcessFullStatsData[PROCESS_FULL_STAT_UTIME];
+        long stime = mProcessFullStatsData[PROCESS_FULL_STAT_STIME];
+
+        long processCpuTimeMillis = (utime + stime) * mJiffyMillis;
+
+        final ArrayList<ThreadCpuUsage> threadCpuUsages = new ArrayList<>();
+        try (DirectoryStream<Path> threadPaths = Files.newDirectoryStream(mThreadsDirectoryPath)) {
+            for (Path threadDirectory : threadPaths) {
+                ThreadCpuUsage threadCpuUsage = getThreadCpuUsage(threadDirectory);
+                if (threadCpuUsage == null) {
+                    continue;
+                }
+                threadCpuUsages.add(threadCpuUsage);
+            }
+        } catch (IOException | DirectoryIteratorException e) {
+            // Expected when a process finishes
+            return null;
+        }
+
+        // If we found no threads, then the process has exited while we were reading from it
+        if (threadCpuUsages.isEmpty()) {
+            return null;
+        }
+        if (DEBUG) {
+            Slog.d(TAG, "Read CPU usage of " + threadCpuUsages.size() + " threads");
+        }
+        return new ProcessCpuUsage(processCpuTimeMillis, threadCpuUsages);
+    }
+
+    /**
+     * Get a thread's CPU usage
+     *
+     * @param threadDirectory the {@code /proc} directory of the thread
+     * @return thread CPU usage. Null if the thread exited and its {@code proc} directory was
+     * removed while collecting information
+     */
+    @Nullable
+    private ThreadCpuUsage getThreadCpuUsage(Path threadDirectory) {
+        // Get the thread ID from the directory name
+        final int threadId;
+        try {
+            final String directoryName = threadDirectory.getFileName().toString();
+            threadId = Integer.parseInt(directoryName);
+        } catch (NumberFormatException e) {
+            Slog.w(TAG, "Failed to parse thread ID when iterating over /proc/*/task", e);
+            return null;
+        }
+
+        // Get the CPU statistics from the directory
+        final Path threadCpuStatPath = threadDirectory.resolve(CPU_STATISTICS_FILENAME);
+        final long[] cpuUsages = mProcTimeInStateReader.getUsageTimesMillis(threadCpuStatPath);
+        if (cpuUsages == null) {
+            return null;
+        }
+
+        return new ThreadCpuUsage(threadId, cpuUsages);
+    }
+
+    /** CPU usage of a process and all of its threads */
+    public static class ProcessCpuUsage {
+        public final long cpuTimeMillis;
+        public final List<ThreadCpuUsage> threadCpuUsages;
+
+        ProcessCpuUsage(long cpuTimeMillis, List<ThreadCpuUsage> threadCpuUsages) {
+            this.cpuTimeMillis = cpuTimeMillis;
+            this.threadCpuUsages = threadCpuUsages;
+        }
+    }
+
+    /** CPU usage of a thread */
+    public static class ThreadCpuUsage {
+        public final int threadId;
+        public final long[] usageTimesMillis;
+
+        ThreadCpuUsage(int threadId, long[] usageTimesMillis) {
+            this.threadId = threadId;
+            this.usageTimesMillis = usageTimesMillis;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
index 3aa2390..d9f0dc0 100644
--- a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
+++ b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
@@ -16,25 +16,28 @@
 
 package com.android.internal.os;
 
+import android.annotation.Nullable;
 import android.os.Process;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.IOException;
 import java.nio.file.Path;
-import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * Reads /proc/UID/task/TID/time_in_state files to obtain statistics on CPU usage
  * by various threads of the System Server.
  */
 public class SystemServerCpuThreadReader {
-    private KernelCpuThreadReader mKernelCpuThreadReader;
+    private final KernelSingleProcessCpuThreadReader mKernelCpuThreadReader;
     private int[] mBinderThreadNativeTids = new int[0];  // Sorted
 
-    private int[] mThreadCpuTimesUs;
-    private int[] mBinderThreadCpuTimesUs;
+    private long mProcessCpuTimeUs;
+    private long[] mThreadCpuTimesUs;
+    private long[] mBinderThreadCpuTimesUs;
+    private long mLastProcessCpuTimeUs;
     private long[] mLastThreadCpuTimesUs;
     private long[] mLastBinderThreadCpuTimesUs;
 
@@ -42,6 +45,8 @@
      * Times (in microseconds) spent by the system server UID.
      */
     public static class SystemServiceCpuThreadTimes {
+        // The entire process
+        public long processCpuTimeUs;
         // All threads
         public long[] threadCpuTimesUs;
         // Just the threads handling incoming binder calls
@@ -55,22 +60,16 @@
      */
     public static SystemServerCpuThreadReader create() {
         return new SystemServerCpuThreadReader(
-                KernelCpuThreadReader.create(0, uid -> uid == Process.myUid()));
+                KernelSingleProcessCpuThreadReader.create(Process.myPid()));
     }
 
     @VisibleForTesting
-    public SystemServerCpuThreadReader(Path procPath, int systemServerUid) throws IOException {
-        this(new KernelCpuThreadReader(0, uid -> uid == systemServerUid, null, null,
-                new KernelCpuThreadReader.Injector() {
-                    @Override
-                    public int getUidForPid(int pid) {
-                        return systemServerUid;
-                    }
-                }));
+    public SystemServerCpuThreadReader(Path procPath, int pid) throws IOException {
+        this(new KernelSingleProcessCpuThreadReader(pid, procPath));
     }
 
     @VisibleForTesting
-    public SystemServerCpuThreadReader(KernelCpuThreadReader kernelCpuThreadReader) {
+    public SystemServerCpuThreadReader(KernelSingleProcessCpuThreadReader kernelCpuThreadReader) {
         mKernelCpuThreadReader = kernelCpuThreadReader;
     }
 
@@ -82,11 +81,12 @@
     /**
      * Returns delta of CPU times, per thread, since the previous call to this method.
      */
+    @Nullable
     public SystemServiceCpuThreadTimes readDelta() {
+        int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequencyCount();
         if (mBinderThreadCpuTimesUs == null) {
-            int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequenciesKhz().length;
-            mThreadCpuTimesUs = new int[numCpuFrequencies];
-            mBinderThreadCpuTimesUs = new int[numCpuFrequencies];
+            mThreadCpuTimesUs = new long[numCpuFrequencies];
+            mBinderThreadCpuTimesUs = new long[numCpuFrequencies];
 
             mLastThreadCpuTimesUs = new long[numCpuFrequencies];
             mLastBinderThreadCpuTimesUs = new long[numCpuFrequencies];
@@ -95,49 +95,47 @@
             mDeltaCpuThreadTimes.binderThreadCpuTimesUs = new long[numCpuFrequencies];
         }
 
+        mProcessCpuTimeUs = 0;
         Arrays.fill(mThreadCpuTimesUs, 0);
         Arrays.fill(mBinderThreadCpuTimesUs, 0);
 
-        ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsage =
+        KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
                 mKernelCpuThreadReader.getProcessCpuUsage();
-        int processCpuUsageSize = processCpuUsage.size();
-        for (int i = 0; i < processCpuUsageSize; i++) {
-            KernelCpuThreadReader.ProcessCpuUsage pcu = processCpuUsage.get(i);
-            ArrayList<KernelCpuThreadReader.ThreadCpuUsage> threadCpuUsages = pcu.threadCpuUsages;
-            if (threadCpuUsages != null) {
-                int threadCpuUsagesSize = threadCpuUsages.size();
-                for (int j = 0; j < threadCpuUsagesSize; j++) {
-                    KernelCpuThreadReader.ThreadCpuUsage tcu = threadCpuUsages.get(j);
-                    boolean isBinderThread =
-                            Arrays.binarySearch(mBinderThreadNativeTids, tcu.threadId) >= 0;
+        if (processCpuUsage == null) {
+            return null;
+        }
 
-                    final int len = Math.min(tcu.usageTimesMillis.length, mThreadCpuTimesUs.length);
-                    for (int k = 0; k < len; k++) {
-                        int usageTimeUs = tcu.usageTimesMillis[k] * 1000;
-                        mThreadCpuTimesUs[k] += usageTimeUs;
-                        if (isBinderThread) {
-                            mBinderThreadCpuTimesUs[k] += usageTimeUs;
-                        }
-                    }
+        mProcessCpuTimeUs = processCpuUsage.cpuTimeMillis * 1000;
+
+        List<KernelSingleProcessCpuThreadReader.ThreadCpuUsage> threadCpuUsages =
+                processCpuUsage.threadCpuUsages;
+        int threadCpuUsagesSize = threadCpuUsages.size();
+        for (int i = 0; i < threadCpuUsagesSize; i++) {
+            KernelSingleProcessCpuThreadReader.ThreadCpuUsage tcu = threadCpuUsages.get(i);
+            boolean isBinderThread =
+                    Arrays.binarySearch(mBinderThreadNativeTids, tcu.threadId) >= 0;
+            for (int k = 0; k < numCpuFrequencies; k++) {
+                long usageTimeUs = tcu.usageTimesMillis[k] * 1000;
+                mThreadCpuTimesUs[k] += usageTimeUs;
+                if (isBinderThread) {
+                    mBinderThreadCpuTimesUs[k] += usageTimeUs;
                 }
             }
         }
 
         for (int i = 0; i < mThreadCpuTimesUs.length; i++) {
-            if (mThreadCpuTimesUs[i] < mLastThreadCpuTimesUs[i]) {
-                mDeltaCpuThreadTimes.threadCpuTimesUs[i] = mThreadCpuTimesUs[i];
-                mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] = mBinderThreadCpuTimesUs[i];
-            } else {
-                mDeltaCpuThreadTimes.threadCpuTimesUs[i] =
-                        mThreadCpuTimesUs[i] - mLastThreadCpuTimesUs[i];
-                mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] =
-                        mBinderThreadCpuTimesUs[i] - mLastBinderThreadCpuTimesUs[i];
-            }
+            mDeltaCpuThreadTimes.processCpuTimeUs =
+                    Math.max(0, mProcessCpuTimeUs - mLastProcessCpuTimeUs);
+            mDeltaCpuThreadTimes.threadCpuTimesUs[i] =
+                    Math.max(0, mThreadCpuTimesUs[i] - mLastThreadCpuTimesUs[i]);
+            mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] =
+                    Math.max(0, mBinderThreadCpuTimesUs[i] - mLastBinderThreadCpuTimesUs[i]);
             mLastThreadCpuTimesUs[i] = mThreadCpuTimesUs[i];
             mLastBinderThreadCpuTimesUs[i] = mBinderThreadCpuTimesUs[i];
         }
 
+        mLastProcessCpuTimeUs = mProcessCpuTimeUs;
+
         return mDeltaCpuThreadTimes;
     }
-
 }
diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
index 481b901..fc36e50 100644
--- a/core/java/com/android/internal/os/SystemServicePowerCalculator.java
+++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
@@ -34,7 +34,9 @@
     private final PowerProfile mPowerProfile;
     private final BatteryStats mBatteryStats;
     // Tracks system server CPU [cluster][speed] power in milliAmp-microseconds
-    private double[][] mSystemServicePowerMaUs;
+    // Data organized like this:
+    // {cluster1-speed1, cluster1-speed2, ..., cluster2-speed1, cluster2-speed2, ...}
+    private double[] mSystemServicePowerMaUs;
 
     public SystemServicePowerCalculator(PowerProfile powerProfile, BatteryStats batteryStats) {
         mPowerProfile = powerProfile;
@@ -50,37 +52,41 @@
                 updateSystemServicePower();
             }
 
-            double cpuPowerMaUs = 0;
-            int numCpuClusters = mPowerProfile.getNumCpuClusters();
-            for (int cluster = 0; cluster < numCpuClusters; cluster++) {
-                final int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
-                for (int speed = 0; speed < numSpeeds; speed++) {
-                    cpuPowerMaUs += mSystemServicePowerMaUs[cluster][speed] * proportionalUsage;
+            if (mSystemServicePowerMaUs != null) {
+                double cpuPowerMaUs = 0;
+                for (int i = 0; i < mSystemServicePowerMaUs.length; i++) {
+                    cpuPowerMaUs += mSystemServicePowerMaUs[i] * proportionalUsage;
                 }
-            }
 
-            app.systemServiceCpuPowerMah = cpuPowerMaUs / MICROSEC_IN_HR;
+                app.systemServiceCpuPowerMah = cpuPowerMaUs / MICROSEC_IN_HR;
+            }
         }
     }
 
     private void updateSystemServicePower() {
+        final long[] systemServiceTimeAtCpuSpeeds = mBatteryStats.getSystemServiceTimeAtCpuSpeeds();
+        if (systemServiceTimeAtCpuSpeeds == null) {
+            return;
+        }
+
+        if (mSystemServicePowerMaUs == null) {
+            mSystemServicePowerMaUs = new double[systemServiceTimeAtCpuSpeeds.length];
+        }
+        int index = 0;
         final int numCpuClusters = mPowerProfile.getNumCpuClusters();
-        mSystemServicePowerMaUs = new double[numCpuClusters][];
         for (int cluster = 0; cluster < numCpuClusters; cluster++) {
             final int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
-            mSystemServicePowerMaUs[cluster] = new double[numSpeeds];
             for (int speed = 0; speed < numSpeeds; speed++) {
-                mSystemServicePowerMaUs[cluster][speed] =
-                        mBatteryStats.getSystemServiceTimeAtCpuSpeed(cluster, speed)
+                mSystemServicePowerMaUs[index] =
+                        systemServiceTimeAtCpuSpeeds[index]
                                 * mPowerProfile.getAveragePowerForCpuCore(cluster, speed);
+                index++;
             }
         }
+
         if (DEBUG) {
-            Log.d(TAG, "System service power per CPU cluster and frequency");
-            for (int cluster = 0; cluster < numCpuClusters; cluster++) {
-                Log.d(TAG, "Cluster[" + cluster  + "]: "
-                        + Arrays.toString(mSystemServicePowerMaUs[cluster]));
-            }
+            Log.d(TAG, "System service power per CPU cluster and frequency:"
+                    + Arrays.toString(mSystemServicePowerMaUs));
         }
     }
 
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index d5f54a1..fff9ac9 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -43,7 +43,6 @@
     public BaseIWindow() {}
 
     private IWindowSession mSession;
-    public int mSeq;
 
     public void setSession(IWindowSession session) {
         mSession = session;
@@ -140,12 +139,6 @@
     }
 
     @Override
-    public void dispatchSystemUiVisibilityChanged(int seq, int globalUi,
-            int localValue, int localChanges) {
-        mSeq = seq;
-    }
-
-    @Override
     public void dispatchWallpaperCommand(String action, int x, int y,
             int z, Bundle extras, boolean sync) {
         if (sync) {
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index 4509032..c9443b0 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -33,4 +33,5 @@
     void reportPreRendered(in EditorInfo info);
     void applyImeVisibility(boolean setVisible);
     void updateActivityViewToScreenMatrix(int bindSequence, in float[] matrixValues);
+    void setImeTraceEnabled(boolean enabled);
 }
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index a1cbd3f..5a06273 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -77,4 +77,6 @@
     void removeImeSurface();
     /** Remove the IME surface. Requires passing the currently focused window. */
     void removeImeSurfaceFromWindow(in IBinder windowToken);
+    void startProtoDump(in byte[] clientProtoDump);
+    boolean isImeTraceEnabled();
 }
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index ddee81a6..ff3543c8 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -17,9 +17,6 @@
 package com.android.internal.widget;
 
 import android.compat.annotation.UnsupportedAppUsage;
-import android.content.ClipData;
-import android.content.ClipDescription;
-import android.os.Build;
 import android.os.Bundle;
 import android.text.Editable;
 import android.text.method.KeyListener;
@@ -30,8 +27,6 @@
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputContentInfo;
-import android.widget.RichContentReceiver;
 import android.widget.TextView;
 
 public class EditableInputConnection extends BaseInputConnection {
@@ -186,28 +181,6 @@
     }
 
     @Override
-    public boolean commitContent(InputContentInfo content, int flags, Bundle opts) {
-        int targetSdkVersion = mTextView.getContext().getApplicationInfo().targetSdkVersion;
-        if (targetSdkVersion <= Build.VERSION_CODES.R) {
-            return false;
-        }
-
-        final ClipDescription description = content.getDescription();
-        final RichContentReceiver<TextView> receiver = mTextView.getRichContentReceiver();
-        if ((flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
-            try {
-                content.requestPermission();
-            } catch (Exception e) {
-                // TODO(b/147299828): Can we catch SecurityException instead?
-                Log.w(TAG, "Can't insert content from IME; requestPermission() failed: " + e);
-                return false; // Can't insert the content if we don't have permission to read it
-            }
-        }
-        ClipData clip = new ClipData(description, new ClipData.Item(content.getContentUri()));
-        return receiver.onReceive(mTextView, clip, RichContentReceiver.SOURCE_INPUT_METHOD, 0);
-    }
-
-    @Override
     public boolean requestCursorUpdates(int cursorUpdateMode) {
         if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode);
 
diff --git a/core/jni/core_jni_helpers.h b/core/jni/core_jni_helpers.h
index d629e0d..013c65f 100644
--- a/core/jni/core_jni_helpers.h
+++ b/core/jni/core_jni_helpers.h
@@ -90,6 +90,12 @@
     return res;
 }
 
+static inline jobject jniGetReferent(JNIEnv* env, jobject ref) {
+    jclass cls = FindClassOrDie(env, "java/lang/ref/Reference");
+    jmethodID get = GetMethodIDOrDie(env, cls, "get", "()Ljava/lang/Object;");
+    return env->CallObjectMethod(ref, get);
+}
+
 /**
  * Read the specified field from jobject, and convert to std::string.
  * If the field cannot be obtained, return defaultValue.
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 11f6a91..542d26f 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -17,6 +17,9 @@
 roosa@google.com
 per-file usagestatsservice.proto, usagestatsservice_v2.proto = mwachens@google.com
 
+# Biometrics
+kchyn@google.com
+
 # Launcher
 hyunyoungs@google.com
 
diff --git a/core/proto/android/server/peopleservice.proto b/core/proto/android/server/peopleservice.proto
index 59556c4..c465233 100644
--- a/core/proto/android/server/peopleservice.proto
+++ b/core/proto/android/server/peopleservice.proto
@@ -46,6 +46,10 @@
   // The notification channel id of the conversation.
   optional string notification_channel_id = 4 [(.android.privacy).dest = DEST_EXPLICIT];
 
+  // The parent notification channel ID of the conversation. This is the notification channel where
+  // the notifications are posted before this conversation is customized by the user.
+  optional string parent_notification_channel_id = 8 [(.android.privacy).dest = DEST_EXPLICIT];
+
   // Integer representation of shortcut bit flags.
   optional int32 shortcut_flags = 5;
 
@@ -54,6 +58,11 @@
 
   // The phone number of the contact.
   optional string contact_phone_number = 7 [(.android.privacy).dest = DEST_EXPLICIT];
+
+  // The timestamp of the last event in millis.
+  optional int64 last_event_timestamp = 9;
+
+  // Next tag: 10
 }
 
 // On disk data of events.
diff --git a/core/proto/android/telephony/enums.proto b/core/proto/android/telephony/enums.proto
index f14e3ed..b56bd2b 100644
--- a/core/proto/android/telephony/enums.proto
+++ b/core/proto/android/telephony/enums.proto
@@ -159,3 +159,50 @@
      */
     SIM_STATE_PRESENT = 11;
 }
+
+// Format of SMS message
+enum SmsFormatEnum {
+    /** Unknown format */
+    SMS_FORMAT_UNKNOWN = 0;
+    /** Format compliant with 3GPP TS 23.040 */
+    SMS_FORMAT_3GPP = 1;
+    /** Format compliant with 3GPP2 TS C.S0015-B */
+    SMS_FORMAT_3GPP2 = 2;
+}
+
+// Technology used to carry an SMS message
+enum SmsTechEnum {
+    /**
+     * Unknown SMS technology used to carry the SMS.
+     * This value is also used for injected SMS.
+     */
+    SMS_TECH_UNKNOWN = 0;
+    /** The SMS was carried over CS bearer in 3GPP network */
+    SMS_TECH_CS_3GPP = 1;
+    /** The SMS was carried over CS bearer in 3GPP2 network */
+    SMS_TECH_CS_3GPP2 = 2;
+    /** The SMS was carried over IMS */
+    SMS_TECH_IMS = 3;
+}
+
+// Types of SMS message
+enum SmsTypeEnum {
+    /** Normal type. */
+    SMS_TYPE_NORMAL = 0;
+    /** SMS-PP (point-to-point). */
+    SMS_TYPE_SMS_PP = 1;
+    /** Voicemail indication. */
+    SMS_TYPE_VOICEMAIL_INDICATION = 2;
+    /** Type 0 message (3GPP TS 23.040 9.2.3.9). */
+    SMS_TYPE_ZERO = 3;
+    /** WAP-PUSH message. */
+    SMS_TYPE_WAP_PUSH = 4;
+}
+
+// SMS errors
+enum SmsIncomingErrorEnum {
+    SMS_SUCCESS = 0;
+    SMS_ERROR_GENERIC = 1;
+    SMS_ERROR_NO_MEMORY = 2;
+    SMS_ERROR_NOT_SUPPORTED = 3;
+}
diff --git a/core/proto/android/view/imeinsetssourceconsumer.proto b/core/proto/android/view/imeinsetssourceconsumer.proto
index 6809163..5bee81b 100644
--- a/core/proto/android/view/imeinsetssourceconsumer.proto
+++ b/core/proto/android/view/imeinsetssourceconsumer.proto
@@ -17,6 +17,7 @@
 syntax = "proto2";
 
 import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
+import "frameworks/base/core/proto/android/view/insetssourceconsumer.proto";
 
 package android.view;
 
@@ -26,6 +27,7 @@
  * Represents a {@link android.view.ImeInsetsSourceConsumer} object.
  */
 message ImeInsetsSourceConsumerProto {
-    optional .android.view.inputmethod.EditorInfoProto focused_editor = 1;
-    optional bool is_requested_visible_awaiting_control = 2;
+    optional InsetsSourceConsumerProto insets_source_consumer = 1;
+    optional .android.view.inputmethod.EditorInfoProto focused_editor = 2;
+    optional bool is_requested_visible_awaiting_control = 3;
 }
\ No newline at end of file
diff --git a/core/proto/android/view/inputmethod/inputmethodeditortrace.proto b/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
index 7322139..f31d35b 100644
--- a/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
+++ b/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
@@ -22,7 +22,6 @@
 import "frameworks/base/core/proto/android/view/inputmethod/inputmethodmanager.proto";
 import "frameworks/base/core/proto/android/view/viewrootimpl.proto";
 import "frameworks/base/core/proto/android/view/insetscontroller.proto";
-import "frameworks/base/core/proto/android/view/insetssourceconsumer.proto";
 import "frameworks/base/core/proto/android/view/imeinsetssourceconsumer.proto";
 import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
 import "frameworks/base/core/proto/android/view/imefocuscontroller.proto";
@@ -54,14 +53,19 @@
 
     /* required: elapsed realtime in nanos since boot of when this entry was logged */
     optional fixed64 elapsed_realtime_nanos = 1;
-    optional ClientSideProto client_side_dump = 2;
+    optional ClientsProto clients = 2;
+
+    // this wrapper helps to simplify the dumping logic
+    message ClientsProto {
+        repeated ClientSideProto client = 1;
+    }
 
     /* groups together the dump from ime related client side classes */
     message ClientSideProto {
-        optional InputMethodManagerProto input_method_manager = 1;
-        optional ViewRootImplProto view_root_impl = 2;
-        optional InsetsControllerProto insets_controller = 3;
-        optional InsetsSourceConsumerProto insets_source_consumer = 4;
+        optional int32 display_id = 1;
+        optional InputMethodManagerProto input_method_manager = 2;
+        optional ViewRootImplProto view_root_impl = 3;
+        optional InsetsControllerProto insets_controller = 4;
         optional ImeInsetsSourceConsumerProto ime_insets_source_consumer = 5;
         optional EditorInfoProto editor_info = 6;
         optional ImeFocusControllerProto ime_focus_controller = 7;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 34543f1..723cceb 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4322,6 +4322,10 @@
     <permission android:name="android.permission.WRITE_DREAM_STATE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @hide Allows applications to read whether ambient display is suppressed. -->
+    <permission android:name="android.permission.READ_DREAM_SUPPRESSION"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Allow an application to read and write the cache partition.
          @hide -->
     <permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 71cb2ac..56f18d5 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1599,6 +1599,7 @@
         </activity>
 
         <activity android:name="android.app.activity.ActivityThreadTest$TestActivity"
+            android:configChanges="screenLayout|screenSize|orientation|smallestScreenSize"
             android:supportsPictureInPicture="true"
             android:exported="true">
         </activity>
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 23534e2..8b25afb 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -69,6 +69,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Test for verifying {@link android.app.ActivityThread} class.
@@ -78,6 +79,7 @@
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class ActivityThreadTest {
+    private static final int TIMEOUT_SEC = 10;
 
     // The first sequence number to try with. Use a large number to avoid conflicts with the first a
     // few sequence numbers the framework used to launch the test activity.
@@ -309,7 +311,7 @@
         transaction.addCallback(ActivityConfigurationChangeItem.obtain(activityConfigPortrait));
         appThread.scheduleTransaction(transaction);
 
-        activity.mTestLatch.await();
+        activity.mTestLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS);
         activity.mConfigLatch.countDown();
 
         activity.mConfigLatch = null;
@@ -352,7 +354,7 @@
         // Wait until the main thread is performing the configuration change for the configuration
         // with sequence number BASE_SEQ + 1 before proceeding. This is to mimic the situation where
         // the activity takes very long time to process configuration changes.
-        activity.mTestLatch.await();
+        activity.mTestLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS);
 
         config = new Configuration();
         config.seq = BASE_SEQ + 2;
@@ -738,7 +740,7 @@
                     mTestLatch.countDown();
                 }
                 try {
-                    mConfigLatch.await();
+                    mConfigLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS);
                 } catch (InterruptedException e) {
                     throw new IllegalStateException(e);
                 }
diff --git a/core/tests/coretests/src/android/view/InsetsFlagsTest.java b/core/tests/coretests/src/android/view/InsetsFlagsTest.java
deleted file mode 100644
index b4302e7..0000000
--- a/core/tests/coretests/src/android/view/InsetsFlagsTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-
-import static android.view.InsetsFlags.getAppearance;
-import static android.view.View.NAVIGATION_BAR_TRANSLUCENT;
-import static android.view.View.NAVIGATION_BAR_TRANSPARENT;
-import static android.view.View.STATUS_BAR_TRANSLUCENT;
-import static android.view.View.STATUS_BAR_TRANSPARENT;
-import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
-import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
-import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
-import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
-import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
-import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
-import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
-import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
-
-import static org.junit.Assert.assertTrue;
-
-import android.platform.test.annotations.Presubmit;
-import android.view.WindowInsetsController.Appearance;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for {@link InsetsFlags}.
- *
- * <p>Build/Install/Run:
- *  atest FrameworksCoreTests:InsetsFlagsTest
- *
- * <p>This test class is a part of Window Manager Service tests and specified in
- * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
- */
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class InsetsFlagsTest {
-
-    @Test
-    public void testGetAppearance() {
-        assertContainsAppearance(APPEARANCE_LOW_PROFILE_BARS, SYSTEM_UI_FLAG_LOW_PROFILE);
-        assertContainsAppearance(APPEARANCE_LIGHT_STATUS_BARS, SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
-        assertContainsAppearance(APPEARANCE_LIGHT_NAVIGATION_BARS,
-                SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
-        assertContainsAppearance(APPEARANCE_OPAQUE_STATUS_BARS,
-                0xffffffff & ~(STATUS_BAR_TRANSLUCENT | STATUS_BAR_TRANSPARENT));
-        assertContainsAppearance(APPEARANCE_OPAQUE_NAVIGATION_BARS,
-                0xffffffff & ~(NAVIGATION_BAR_TRANSLUCENT | NAVIGATION_BAR_TRANSPARENT));
-    }
-
-    void assertContainsAppearance(@Appearance int appearance, int systemUiVisibility) {
-        assertTrue((getAppearance(systemUiVisibility) & appearance) == appearance);
-    }
-}
diff --git a/core/tests/coretests/src/android/widget/TextViewProcessTextTest.java b/core/tests/coretests/src/android/widget/TextViewProcessTextTest.java
index ec8dfcb..91266f0 100644
--- a/core/tests/coretests/src/android/widget/TextViewProcessTextTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewProcessTextTest.java
@@ -16,20 +16,10 @@
 
 package android.widget;
 
-import static android.widget.RichContentReceiver.SOURCE_PROCESS_TEXT;
-
 import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.app.Activity;
 import android.app.Instrumentation;
-import android.content.ClipData;
-import android.content.ClipDescription;
 import android.content.Intent;
 import android.text.Selection;
 import android.text.Spannable;
@@ -44,10 +34,6 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mockito;
-
-import java.util.Set;
 
 /**
  * Tests for {@link Intent#ACTION_PROCESS_TEXT} functionality in {@link TextView}.
@@ -78,9 +64,6 @@
         mTextView.setTextIsSelectable(true);
         Selection.setSelection((Spannable) mTextView.getText(), 0, mTextView.getText().length());
 
-        MockReceiverWrapper mockReceiverWrapper = new MockReceiverWrapper();
-        mTextView.setRichContentReceiver(mockReceiverWrapper);
-
         // We need to run this in the UI thread, as it will create a Toast.
         mActivityRule.runOnUiThread(() -> {
             triggerOnActivityResult(Activity.RESULT_OK, "Text is replaced.");
@@ -89,46 +72,6 @@
 
         // This is a TextView, which can't be modified. Hence no change should have been made.
         assertEquals(originalText, mTextView.getText().toString());
-        verifyZeroInteractions(mockReceiverWrapper.mMock);
-    }
-
-    @Test
-    public void testProcessTextActivityResultEditable_defaultRichContentReceiver()
-            throws Throwable {
-        mActivityRule.runOnUiThread(() -> mTextView = new EditText(mActivity));
-        mInstrumentation.waitForIdleSync();
-        CharSequence originalText = "This is some text.";
-        mTextView.setText(originalText, BufferType.SPANNABLE);
-        assertEquals(originalText, mTextView.getText().toString());
-        mTextView.setTextIsSelectable(true);
-        Selection.setSelection(((EditText) mTextView).getText(), 0, mTextView.getText().length());
-
-        CharSequence newText = "Text is replaced.";
-        triggerOnActivityResult(Activity.RESULT_OK, newText);
-
-        assertEquals(newText, mTextView.getText().toString());
-    }
-
-    @Test
-    public void testProcessTextActivityResultEditable_customRichContentReceiver() throws Throwable {
-        mActivityRule.runOnUiThread(() -> mTextView = new EditText(mActivity));
-        mInstrumentation.waitForIdleSync();
-        CharSequence originalText = "This is some text.";
-        mTextView.setText(originalText, BufferType.SPANNABLE);
-        assertEquals(originalText, mTextView.getText().toString());
-        mTextView.setTextIsSelectable(true);
-        Selection.setSelection(((EditText) mTextView).getText(), 0, mTextView.getText().length());
-
-        MockReceiverWrapper mockReceiverWrapper = new MockReceiverWrapper();
-        mTextView.setRichContentReceiver(mockReceiverWrapper);
-
-        CharSequence newText = "Text is replaced.";
-        triggerOnActivityResult(Activity.RESULT_OK, newText);
-
-        ClipData expectedClip = ClipData.newPlainText("", newText);
-        verify(mockReceiverWrapper.mMock, times(1)).onReceive(
-                eq(mTextView), clipEq(expectedClip), eq(SOURCE_PROCESS_TEXT), eq(0));
-        verifyNoMoreInteractions(mockReceiverWrapper.mMock);
     }
 
     @Test
@@ -141,14 +84,10 @@
         mTextView.setTextIsSelectable(true);
         Selection.setSelection(((EditText) mTextView).getText(), 0, mTextView.getText().length());
 
-        MockReceiverWrapper mockReceiverWrapper = new MockReceiverWrapper();
-        mTextView.setRichContentReceiver(mockReceiverWrapper);
-
         CharSequence newText = "Text is replaced.";
         triggerOnActivityResult(Activity.RESULT_CANCELED, newText);
 
         assertEquals(originalText, mTextView.getText().toString());
-        verifyZeroInteractions(mockReceiverWrapper.mMock);
     }
 
     @Test
@@ -161,13 +100,9 @@
         mTextView.setTextIsSelectable(true);
         Selection.setSelection(((EditText) mTextView).getText(), 0, mTextView.getText().length());
 
-        MockReceiverWrapper mockReceiverWrapper = new MockReceiverWrapper();
-        mTextView.setRichContentReceiver(mockReceiverWrapper);
-
         mTextView.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_OK, null);
 
         assertEquals(originalText, mTextView.getText().toString());
-        verifyZeroInteractions(mockReceiverWrapper.mMock);
     }
 
     private void triggerOnActivityResult(int resultCode, CharSequence replacementText) {
@@ -175,55 +110,4 @@
         data.putExtra(Intent.EXTRA_PROCESS_TEXT, replacementText);
         mTextView.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, resultCode, data);
     }
-
-    // This wrapper is used so that we only mock and verify the public callback methods. In addition
-    // to the public methods, the RichContentReceiver interface has some hidden default methods;
-    // we don't want to mock or assert calls to these helper functions (they are an implementation
-    // detail).
-    private static class MockReceiverWrapper implements RichContentReceiver<TextView> {
-        private final RichContentReceiver<TextView> mMock;
-
-        @SuppressWarnings("unchecked")
-        MockReceiverWrapper() {
-            this.mMock = Mockito.mock(RichContentReceiver.class);
-        }
-
-        public RichContentReceiver<TextView> getMock() {
-            return mMock;
-        }
-
-        @Override
-        public boolean onReceive(TextView view, ClipData clip, @Source int source,
-                @Flags int flags) {
-            return mMock.onReceive(view, clip, source, flags);
-        }
-
-        @Override
-        public Set<String> getSupportedMimeTypes() {
-            return mMock.getSupportedMimeTypes();
-        }
-    }
-
-    private static ClipData clipEq(ClipData expected) {
-        return argThat(new ClipDataArgumentMatcher(expected));
-    }
-
-    private static class ClipDataArgumentMatcher implements ArgumentMatcher<ClipData> {
-        private final ClipData mExpected;
-
-        private ClipDataArgumentMatcher(ClipData expected) {
-            this.mExpected = expected;
-        }
-
-        @Override
-        public boolean matches(ClipData actual) {
-            ClipDescription actualDesc = actual.getDescription();
-            ClipDescription expectedDesc = mExpected.getDescription();
-            return expectedDesc.getLabel().equals(actualDesc.getLabel())
-                    && actualDesc.getMimeTypeCount() == 1
-                    && expectedDesc.getMimeType(0).equals(actualDesc.getMimeType(0))
-                    && actual.getItemCount() == 1
-                    && mExpected.getItemAt(0).getText().equals(actual.getItemAt(0).getText());
-        }
-    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
new file mode 100644
index 0000000..403c1c2
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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.internal.os;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.FileUtils;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Comparator;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KernelSingleProcessCpuThreadReaderTest {
+
+    private File mProcDirectory;
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getContext();
+        mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        FileUtils.deleteContents(mProcDirectory);
+    }
+
+    @Test
+    public void getThreadCpuUsage() throws IOException {
+        setupDirectory(42,
+                new int[] {42, 1, 2, 3},
+                new int[] {1000, 2000},
+                // Units are 10ms aka 10000Us
+                new int[][] {{100, 200}, {0, 200}, {100, 300}, {0, 400}},
+                new int[] {1400, 1500});
+
+        KernelSingleProcessCpuThreadReader reader = new KernelSingleProcessCpuThreadReader(42,
+                mProcDirectory.toPath());
+        KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
+                reader.getProcessCpuUsage();
+        assertThat(processCpuUsage.cpuTimeMillis).isEqualTo(29000);
+        List<KernelSingleProcessCpuThreadReader.ThreadCpuUsage> threadCpuUsage =
+                processCpuUsage.threadCpuUsages;
+        threadCpuUsage.sort(Comparator.comparingInt(o -> o.threadId));
+        assertThat(threadCpuUsage).hasSize(4);
+        assertThat(threadCpuUsage.get(0).threadId).isEqualTo(1);
+        assertThat(threadCpuUsage.get(0).usageTimesMillis).isEqualTo(new long[]{0, 2000});
+        assertThat(threadCpuUsage.get(1).threadId).isEqualTo(2);
+        assertThat(threadCpuUsage.get(1).usageTimesMillis).isEqualTo(new long[]{1000, 3000});
+        assertThat(threadCpuUsage.get(2).threadId).isEqualTo(3);
+        assertThat(threadCpuUsage.get(2).usageTimesMillis).isEqualTo(new long[]{0, 4000});
+        assertThat(threadCpuUsage.get(3).threadId).isEqualTo(42);
+        assertThat(threadCpuUsage.get(3).usageTimesMillis).isEqualTo(new long[]{1000, 2000});
+    }
+
+    @Test
+    public void getCpuFrequencyCount() throws IOException {
+        setupDirectory(13,
+                new int[] {13},
+                new int[] {1000, 2000, 3000},
+                new int[][] {{100, 200, 300}},
+                new int[] {14, 15});
+
+        KernelSingleProcessCpuThreadReader reader = new KernelSingleProcessCpuThreadReader(13,
+                mProcDirectory.toPath());
+        int cpuFrequencyCount = reader.getCpuFrequencyCount();
+        assertThat(cpuFrequencyCount).isEqualTo(3);
+    }
+
+    private void setupDirectory(int pid, int[] threadIds, int[] cpuFrequencies,
+            int[][] threadCpuTimes, int[] processCpuTimes)
+            throws IOException {
+
+        assertTrue(mProcDirectory.toPath().resolve("self").toFile().mkdirs());
+
+        try (OutputStream timeInStateStream =
+                     Files.newOutputStream(
+                             mProcDirectory.toPath().resolve("self").resolve("time_in_state"))) {
+            for (int i = 0; i < cpuFrequencies.length; i++) {
+                final String line = cpuFrequencies[i] + " 0\n";
+                timeInStateStream.write(line.getBytes());
+            }
+        }
+
+        Path processPath = mProcDirectory.toPath().resolve(String.valueOf(pid));
+
+        // Make /proc/$PID
+        assertTrue(processPath.toFile().mkdirs());
+
+        // Write /proc/$PID/stat. Only the fields 14-17 matter.
+        try (OutputStream timeInStateStream = Files.newOutputStream(processPath.resolve("stat"))) {
+            timeInStateStream.write(
+                    (pid + " (test) S 4 5 6 7 8 9 10 11 12 13 "
+                            + processCpuTimes[0] + " "
+                            + processCpuTimes[1] + " "
+                            + "16 17 18 19 20 ...").getBytes());
+        }
+
+        // Make /proc/$PID/task
+        final Path selfThreadsPath = processPath.resolve("task");
+        assertTrue(selfThreadsPath.toFile().mkdirs());
+
+        // Make thread directories
+        for (int i = 0; i < threadIds.length; i++) {
+            // Make /proc/$PID/task/$TID
+            final Path threadPath = selfThreadsPath.resolve(String.valueOf(threadIds[i]));
+            assertTrue(threadPath.toFile().mkdirs());
+
+            // Make /proc/$PID/task/$TID/time_in_state
+            try (OutputStream timeInStateStream =
+                         Files.newOutputStream(threadPath.resolve("time_in_state"))) {
+                for (int j = 0; j < cpuFrequencies.length; j++) {
+                    final String line = cpuFrequencies[j] + " " + threadCpuTimes[i][j] + "\n";
+                    timeInStateStream.write(line.getBytes());
+                }
+            }
+        }
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
index 10ba548..121c637 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
@@ -55,82 +55,107 @@
 
     @Test
     public void testReaderDelta_firstTime() throws IOException {
-        int uid = 42;
+        int pid = 42;
         setupDirectory(
-                mProcDirectory.toPath().resolve(String.valueOf(uid)),
-                new int[]{42, 1, 2, 3},
-                new int[]{1000, 2000},
+                pid,
+                new int[] {42, 1, 2, 3},
+                new int[] {1000, 2000},
                 // Units are 10ms aka 10000Us
-                new int[][]{{100, 200}, {0, 200}, {0, 300}, {0, 400}});
+                new int[][] {{100, 200}, {0, 200}, {0, 300}, {0, 400}},
+                new int[] {1400, 1500});
 
         SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
-                mProcDirectory.toPath(), uid);
-        reader.setBinderThreadNativeTids(new int[]{1, 3});
+                mProcDirectory.toPath(), pid);
+        reader.setBinderThreadNativeTids(new int[] {1, 3});
         SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
                 reader.readDelta();
-        assertArrayEquals(new long[]{100 * 10000, 1100 * 10000},
+        assertArrayEquals(new long[] {100 * 10000, 1100 * 10000},
                 systemServiceCpuThreadTimes.threadCpuTimesUs);
-        assertArrayEquals(new long[]{0, 600 * 10000},
+        assertArrayEquals(new long[] {0, 600 * 10000},
                 systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
     }
 
     @Test
     public void testReaderDelta_nextTime() throws IOException {
-        int uid = 42;
+        int pid = 42;
         setupDirectory(
-                mProcDirectory.toPath().resolve(String.valueOf(uid)),
-                new int[]{42, 1, 2, 3},
-                new int[]{1000, 2000},
-                new int[][]{{100, 200}, {0, 200}, {0, 300}, {0, 400}});
+                pid,
+                new int[] {42, 1, 2, 3},
+                new int[] {1000, 2000},
+                new int[][] {{100, 200}, {0, 200}, {0, 300}, {0, 400}},
+                new int[] {1400, 1500});
 
         SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
-                mProcDirectory.toPath(), uid);
-        reader.setBinderThreadNativeTids(new int[]{1, 3});
+                mProcDirectory.toPath(), pid);
+        reader.setBinderThreadNativeTids(new int[] {1, 3});
 
         // First time, populate "last" snapshot
         reader.readDelta();
 
         FileUtils.deleteContents(mProcDirectory);
         setupDirectory(
-                mProcDirectory.toPath().resolve(String.valueOf(uid)),
-                new int[]{42, 1, 2, 3},
-                new int[]{1000, 2000},
-                new int[][]{{500, 600}, {700, 800}, {900, 1000}, {1100, 1200}});
+                pid,
+                new int[] {42, 1, 2, 3},
+                new int[] {1000, 2000},
+                new int[][] {{500, 600}, {700, 800}, {900, 1000}, {1100, 1200}},
+                new int[] {2400, 2500});
 
         // Second time, get the actual delta
         SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
                 reader.readDelta();
 
-        assertArrayEquals(new long[]{3100 * 10000, 2500 * 10000},
+        assertArrayEquals(new long[] {3100 * 10000, 2500 * 10000},
                 systemServiceCpuThreadTimes.threadCpuTimesUs);
-        assertArrayEquals(new long[]{1800 * 10000, 1400 * 10000},
+        assertArrayEquals(new long[] {1800 * 10000, 1400 * 10000},
                 systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
     }
 
-    private void setupDirectory(Path processPath, int[] threadIds, int[] cpuFrequencies,
-            int[][] cpuTimes) throws IOException {
+    private void setupDirectory(int pid, int[] threadIds, int[] cpuFrequencies, int[][] cpuTimes,
+            int[] processCpuTimes)
+            throws IOException {
+
+        assertTrue(mProcDirectory.toPath().resolve("self").toFile().mkdirs());
+
+        try (OutputStream timeInStateStream =
+                     Files.newOutputStream(
+                             mProcDirectory.toPath().resolve("self").resolve("time_in_state"))) {
+            for (int i = 0; i < cpuFrequencies.length; i++) {
+                final String line = cpuFrequencies[i] + " 0\n";
+                timeInStateStream.write(line.getBytes());
+            }
+        }
+
+        Path processPath = mProcDirectory.toPath().resolve(String.valueOf(pid));
         // Make /proc/$PID
         assertTrue(processPath.toFile().mkdirs());
 
+        // Write /proc/$PID/stat. Only the fields 14-17 matter.
+        try (OutputStream timeInStateStream = Files.newOutputStream(processPath.resolve("stat"))) {
+            timeInStateStream.write(
+                    (pid + " (test) S 4 5 6 7 8 9 10 11 12 13 "
+                            + processCpuTimes[0] + " "
+                            + processCpuTimes[1] + " "
+                            + "16 17 18 19 20 ...").getBytes());
+        }
+
         // Make /proc/$PID/task
         final Path selfThreadsPath = processPath.resolve("task");
         assertTrue(selfThreadsPath.toFile().mkdirs());
 
-        // Make thread directories in reverse order, as they are read in order of creation by
-        // CpuThreadProcReader
+        // Make thread directories
         for (int i = 0; i < threadIds.length; i++) {
             // Make /proc/$PID/task/$TID
             final Path threadPath = selfThreadsPath.resolve(String.valueOf(threadIds[i]));
             assertTrue(threadPath.toFile().mkdirs());
 
             // Make /proc/$PID/task/$TID/time_in_state
-            final OutputStream timeInStateStream =
-                    Files.newOutputStream(threadPath.resolve("time_in_state"));
-            for (int j = 0; j < cpuFrequencies.length; j++) {
-                final String line = cpuFrequencies[j] + " " + cpuTimes[i][j] + "\n";
-                timeInStateStream.write(line.getBytes());
+            try (OutputStream timeInStateStream =
+                         Files.newOutputStream(threadPath.resolve("time_in_state"))) {
+                for (int j = 0; j < cpuFrequencies.length; j++) {
+                    final String line = cpuFrequencies[j] + " " + cpuTimes[i][j] + "\n";
+                    timeInStateStream.write(line.getBytes());
+                }
             }
-            timeInStateStream.close();
         }
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
index 2eee140..37e1efd 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -43,18 +43,18 @@
     private PowerProfile mProfile;
     private MockBatteryStatsImpl mMockBatteryStats;
     private MockKernelCpuUidFreqTimeReader mMockCpuUidFreqTimeReader;
-    private MockServerCpuThreadReader mMockServerCpuThreadReader;
+    private MockSystemServerCpuThreadReader mMockSystemServerCpuThreadReader;
     private SystemServicePowerCalculator mSystemServicePowerCalculator;
 
     @Before
     public void setUp() throws IOException {
         Context context = InstrumentationRegistry.getContext();
         mProfile = new PowerProfile(context, true /* forTest */);
-        mMockServerCpuThreadReader = new MockServerCpuThreadReader();
+        mMockSystemServerCpuThreadReader = new MockSystemServerCpuThreadReader();
         mMockCpuUidFreqTimeReader = new MockKernelCpuUidFreqTimeReader();
         mMockBatteryStats = new MockBatteryStatsImpl(new MockClocks())
                 .setPowerProfile(mProfile)
-                .setSystemServerCpuThreadReader(mMockServerCpuThreadReader)
+                .setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader)
                 .setKernelCpuUidFreqTimeReader(mMockCpuUidFreqTimeReader)
                 .setUserInfoProvider(new MockUserInfoProvider());
         mMockBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0);
@@ -65,12 +65,13 @@
     @Test
     public void testCalculateApp() {
         // Test Power Profile has two CPU clusters with 3 and 4 speeds, thus 7 freq times total
-        mMockServerCpuThreadReader.setThreadTimes(
-                new long[]{30000, 40000, 50000, 60000, 70000, 80000, 90000},
-                new long[]{20000, 30000, 40000, 50000, 60000, 70000, 80000});
+        mMockSystemServerCpuThreadReader.setCpuTimes(
+                210000,
+                new long[] {30000, 40000, 50000, 60000, 70000, 80000, 90000},
+                new long[] {20000, 30000, 40000, 50000, 60000, 70000, 80000});
 
         mMockCpuUidFreqTimeReader.setSystemServerCpuTimes(
-                new long[]{10000, 20000, 30000, 40000, 50000, 60000, 70000}
+                new long[] {10000, 20000, 30000, 40000, 50000, 60000, 70000}
         );
 
         mMockBatteryStats.readKernelUidCpuFreqTimesLocked(null, true, false);
@@ -106,13 +107,13 @@
                 mMockBatteryStats.getUidStatsLocked(workSourceUid1), 0);
         mSystemServicePowerCalculator.calculateApp(app1, app1.uidObj, 0, 0,
                 BatteryStats.STATS_SINCE_CHARGED);
-        assertEquals(0.27162, app1.systemServiceCpuPowerMah, 0.00001);
+        assertEquals(0.00018958, app1.systemServiceCpuPowerMah, 0.0000001);
 
         BatterySipper app2 = new BatterySipper(BatterySipper.DrainType.APP,
                 mMockBatteryStats.getUidStatsLocked(workSourceUid2), 0);
         mSystemServicePowerCalculator.calculateApp(app2, app2.uidObj, 0, 0,
                 BatteryStats.STATS_SINCE_CHARGED);
-        assertEquals(2.44458, app2.systemServiceCpuPowerMah, 0.00001);
+        assertEquals(0.00170625, app2.systemServiceCpuPowerMah, 0.0000001);
     }
 
     private static class MockKernelCpuUidFreqTimeReader extends
@@ -140,14 +141,16 @@
         }
     }
 
-    private static class MockServerCpuThreadReader extends SystemServerCpuThreadReader {
+    private static class MockSystemServerCpuThreadReader extends SystemServerCpuThreadReader {
         private SystemServiceCpuThreadTimes mThreadTimes = new SystemServiceCpuThreadTimes();
 
-        MockServerCpuThreadReader() {
+        MockSystemServerCpuThreadReader() {
             super(null);
         }
 
-        public void setThreadTimes(long[] threadCpuTimesUs, long[] binderThreadCpuTimesUs) {
+        public void setCpuTimes(long processCpuTimeUs, long[] threadCpuTimesUs,
+                long[] binderThreadCpuTimesUs) {
+            mThreadTimes.processCpuTimeUs = processCpuTimeUs;
             mThreadTimes.threadCpuTimesUs = threadCpuTimesUs;
             mThreadTimes.binderThreadCpuTimesUs = binderThreadCpuTimesUs;
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index c18e9ce..d810fb8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -43,6 +43,7 @@
 import com.android.internal.view.IInputMethodManager;
 
 import java.util.ArrayList;
+import java.util.concurrent.Executor;
 
 /**
  * Manages IME control at the display-level. This occurs when IME comes up in multi-window mode.
@@ -62,15 +63,21 @@
     private static final int FLOATING_IME_BOTTOM_INSET = -80;
 
     protected final IWindowManager mWmService;
-    protected final Handler mHandler;
+    protected final Executor mExecutor;
     private final TransactionPool mTransactionPool;
     private final DisplayController mDisplayController;
     private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
     private final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
 
+    @Deprecated
     public DisplayImeController(IWindowManager wmService, DisplayController displayController,
             Handler mainHandler, TransactionPool transactionPool) {
-        mHandler = mainHandler;
+        this(wmService, displayController, mainHandler::post, transactionPool);
+    }
+
+    public DisplayImeController(IWindowManager wmService, DisplayController displayController,
+            Executor mainExecutor, TransactionPool transactionPool) {
+        mExecutor = mainExecutor;
         mWmService = wmService;
         mTransactionPool = transactionPool;
         mDisplayController = displayController;
@@ -197,7 +204,7 @@
 
         @Override
         public void insetsChanged(InsetsState insetsState) {
-            mHandler.post(() -> {
+            mExecutor.execute(() -> {
                 if (mInsetsState.equals(insetsState)) {
                     return;
                 }
@@ -224,15 +231,25 @@
                         continue;
                     }
                     if (activeControl.getType() == InsetsState.ITYPE_IME) {
-                        mHandler.post(() -> {
+                        mExecutor.execute(() -> {
                             final Point lastSurfacePosition = mImeSourceControl != null
                                     ? mImeSourceControl.getSurfacePosition() : null;
+                            final boolean positionChanged =
+                                    !activeControl.getSurfacePosition().equals(lastSurfacePosition);
+                            final boolean leashChanged =
+                                    !haveSameLeash(mImeSourceControl, activeControl);
                             mImeSourceControl = activeControl;
-                            if (!activeControl.getSurfacePosition().equals(lastSurfacePosition)
-                                    && mAnimation != null) {
-                                startAnimation(mImeShowing, true /* forceRestart */);
-                            } else if (!mImeShowing) {
-                                removeImeSurface();
+                            if (mAnimation != null) {
+                                if (positionChanged) {
+                                    startAnimation(mImeShowing, true /* forceRestart */);
+                                }
+                            } else {
+                                if (leashChanged) {
+                                    applyVisibilityToLeash();
+                                }
+                                if (!mImeShowing) {
+                                    removeImeSurface();
+                                }
                             }
                         });
                     }
@@ -240,13 +257,27 @@
             }
         }
 
+        private void applyVisibilityToLeash() {
+            SurfaceControl leash = mImeSourceControl.getLeash();
+            if (leash != null) {
+                SurfaceControl.Transaction t = mTransactionPool.acquire();
+                if (mImeShowing) {
+                    t.show(leash);
+                } else {
+                    t.hide(leash);
+                }
+                t.apply();
+                mTransactionPool.release(t);
+            }
+        }
+
         @Override
         public void showInsets(int types, boolean fromIme) {
             if ((types & WindowInsets.Type.ime()) == 0) {
                 return;
             }
             if (DEBUG) Slog.d(TAG, "Got showInsets for ime");
-            mHandler.post(() -> startAnimation(true /* show */, false /* forceRestart */));
+            mExecutor.execute(() -> startAnimation(true /* show */, false /* forceRestart */));
         }
 
         @Override
@@ -255,7 +286,7 @@
                 return;
             }
             if (DEBUG) Slog.d(TAG, "Got hideInsets for ime");
-            mHandler.post(() -> startAnimation(false /* show */, false /* forceRestart */));
+            mExecutor.execute(() -> startAnimation(false /* show */, false /* forceRestart */));
         }
 
         @Override
@@ -495,4 +526,20 @@
         return IInputMethodManager.Stub.asInterface(
                 ServiceManager.getService(Context.INPUT_METHOD_SERVICE));
     }
+
+    private static boolean haveSameLeash(InsetsSourceControl a, InsetsSourceControl b) {
+        if (a == b) {
+            return true;
+        }
+        if (a == null || b == null) {
+            return false;
+        }
+        if (a.getLeash() == b.getLeash()) {
+            return true;
+        }
+        if (a.getLeash() == null || b.getLeash() == null) {
+            return false;
+        }
+        return a.getLeash().isSameSurface(b.getLeash());
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index b4620e27..84b98f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -271,14 +271,14 @@
         }
 
         @Override
-        public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
+        public int relayout(IWindow window, WindowManager.LayoutParams attrs,
                 int requestedWidth, int requestedHeight, int viewVisibility, int flags,
                 long frameNumber, ClientWindowFrames outFrames,
                 MergedConfiguration mergedConfiguration,
                 SurfaceControl outSurfaceControl, InsetsState outInsetsState,
                 InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
                 SurfaceControl outBLASTSurfaceControl) {
-            int res = super.relayout(window, seq, attrs, requestedWidth, requestedHeight,
+            int res = super.relayout(window, attrs, requestedWidth, requestedHeight,
                     viewVisibility, flags, frameNumber, outFrames,
                     mergedConfiguration, outSurfaceControl, outInsetsState,
                     outActiveControls, outSurfaceSize, outBLASTSurfaceControl);
@@ -365,10 +365,6 @@
         public void updatePointerIcon(float x, float y) {}
 
         @Override
-        public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
-                int localValue, int localChanges) {}
-
-        @Override
         public void dispatchWindowShown() {}
 
         @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index 9954618..6bc838f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -239,9 +239,14 @@
             throw new RuntimeException("Callers should call scheduleOffset() instead of this "
                     + "directly");
         }
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
         mDisplayAreaMap.forEach(
-                (key, leash) -> animateWindows(leash, fromBounds, toBounds, direction,
-                        durationMs));
+                (key, leash) -> {
+                    animateWindows(leash, fromBounds, toBounds, direction,
+                            durationMs);
+                    wct.setBounds(key.token, toBounds);
+                });
+        applyTransaction(wct);
     }
 
     private void resetWindowsOffset() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
index 7c0c738..b6b518d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
@@ -184,9 +184,8 @@
                 mDisplaySize.x, mTutorialAreaHeight, 0, 0,
                 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
-                PixelFormat.TRANSLUCENT);
+                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+                    PixelFormat.TRANSLUCENT);
         lp.gravity = Gravity.TOP | Gravity.LEFT;
         lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
         lp.setFitInsetsTypes(0 /* types */);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java
index edbbd69..cdb27da 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java
@@ -1319,34 +1319,6 @@
                 mBackground.getRight(), mBackground.getBottom(), Op.UNION);
     }
 
-    void onDockedTopTask() {
-        mState.animateAfterRecentsDrawn = true;
-        startDragging(false /* animate */, false /* touching */);
-        updateDockSide();
-        mEntranceAnimationRunning = true;
-
-        resizeStackSurfaces(calculatePositionForInsetBounds(),
-                mSplitLayout.getSnapAlgorithm().getMiddleTarget().position,
-                mSplitLayout.getSnapAlgorithm().getMiddleTarget(),
-                null /* transaction */);
-    }
-
-    void onRecentsDrawn() {
-        updateDockSide();
-        final int position = calculatePositionForInsetBounds();
-        if (mState.animateAfterRecentsDrawn) {
-            mState.animateAfterRecentsDrawn = false;
-
-            mHandler.post(() -> {
-                // Delay switching resizing mode because this might cause jank in recents animation
-                // that's longer than this animation.
-                stopDragging(position, getSnapAlgorithm().getMiddleTarget(),
-                        mLongPressEntraceAnimDuration, Interpolators.FAST_OUT_SLOW_IN,
-                        200 /* endDelay */);
-            });
-        }
-    }
-
     void onUndockingTask() {
         int dockSide = mSplitLayout.getPrimarySplitSide();
         if (inSplitMode()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 58106c9..985dff2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -48,14 +48,6 @@
     /** Switch to minimized state if appropriate. */
     void setMinimized(boolean minimized);
 
-    /**
-     * Workaround for b/62528361, at the time recents has drawn, it may happen before a
-     * configuration change to the Divider, and internally, the event will be posted to the
-     * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
-     * register the event handler here and proxy the event to the current DividerView.
-     */
-    void onRecentsDrawn();
-
     /** Called when there's an activity forced resizable. */
     void onActivityForcedResizable(String packageName, int taskId, int reason);
 
@@ -68,9 +60,6 @@
     /** Called when there's a task undocking. */
     void onUndockingTask();
 
-    /** Called when top task docked. */
-    void onDockedTopTask();
-
     /** Called when app transition finished. */
     void onAppTransitionFinished();
 
@@ -85,4 +74,13 @@
 
     /** @return the container token for the secondary split root task. */
     WindowContainerToken getSecondaryRoot();
+
+    /**
+     * Splits the primary task if feasible, this is to preserve legacy way to toggle split screen.
+     * Like triggering split screen through long pressing recents app button or through
+     * {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN}.
+     *
+     * @return {@code true} if it successes to split the primary task.
+     */
+    boolean splitPrimaryTask();
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index ce49dd9..43e4d62 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -16,19 +16,25 @@
 
 package com.android.wm.shell.splitscreen;
 
+import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Handler;
+import android.os.RemoteException;
 import android.provider.Settings;
 import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.widget.Toast;
 import android.window.TaskOrganizer;
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
@@ -47,6 +53,7 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.List;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
@@ -57,7 +64,7 @@
         DisplayController.OnDisplaysChangedListener {
     static final boolean DEBUG = false;
 
-    private static final String TAG = "Divider";
+    private static final String TAG = "SplitScreenCtrl";
     private static final int DEFAULT_APP_TRANSITION_DURATION = 336;
 
     private final Context mContext;
@@ -157,12 +164,12 @@
         // Don't initialize the divider or anything until we get the default display.
     }
 
-    /** Returns {@code true} if split screen is supported on the device. */
+    @Override
     public boolean isSplitScreenSupported() {
         return mSplits.isSplitScreenSupported();
     }
 
-    /** Called when keyguard showing state changed. */
+    @Override
     public void onKeyguardVisibilityChanged(boolean showing) {
         if (!isSplitActive() || mView == null) {
             return;
@@ -229,21 +236,22 @@
         mHandler.post(task);
     }
 
-    /** Returns {@link DividerView}. */
+    @Override
     public DividerView getDividerView() {
         return mView;
     }
 
-    /** Returns {@code true} if one of the split screen is in minimized mode. */
+    @Override
     public boolean isMinimized() {
         return mMinimized;
     }
 
+    @Override
     public boolean isHomeStackResizable() {
         return mHomeStackResizable;
     }
 
-    /** Returns {@code true} if the divider is visible. */
+    @Override
     public boolean isDividerVisible() {
         return mView != null && mView.getVisibility() == View.VISIBLE;
     }
@@ -328,7 +336,7 @@
         }
     }
 
-    /** Switch to minimized state if appropriate. */
+    @Override
     public void setMinimized(final boolean minimized) {
         if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
         mHandler.post(() -> {
@@ -392,48 +400,29 @@
         mWindowManager.setTouchable(!mAdjustedForIme);
     }
 
-    /**
-     * Workaround for b/62528361, at the time recents has drawn, it may happen before a
-     * configuration change to the Divider, and internally, the event will be posted to the
-     * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
-     * register the event handler here and proxy the event to the current DividerView.
-     */
-    public void onRecentsDrawn() {
-        if (mView != null) {
-            mView.onRecentsDrawn();
-        }
-    }
-
-    /** Called when there's an activity forced resizable. */
+    @Override
     public void onActivityForcedResizable(String packageName, int taskId, int reason) {
         mForcedResizableController.activityForcedResizable(packageName, taskId, reason);
     }
 
-    /** Called when there's an activity dismissing split screen. */
+    @Override
     public void onActivityDismissingSplitScreen() {
         mForcedResizableController.activityDismissingSplitScreen();
     }
 
-    /** Called when there's an activity launch on secondary display failed. */
+    @Override
     public void onActivityLaunchOnSecondaryDisplayFailed() {
         mForcedResizableController.activityLaunchOnSecondaryDisplayFailed();
     }
 
-    /** Called when there's a task undocking. */
+    @Override
     public void onUndockingTask() {
         if (mView != null) {
             mView.onUndockingTask();
         }
     }
 
-    /** Called when top task docked. */
-    public void onDockedTopTask() {
-        if (mView != null) {
-            mView.onDockedTopTask();
-        }
-    }
-
-    /** Called when app transition finished. */
+    @Override
     public void onAppTransitionFinished() {
         if (mView == null) {
             return;
@@ -441,7 +430,7 @@
         mForcedResizableController.onAppTransitionFinished();
     }
 
-    /** Dumps current status of Split Screen. */
+    @Override
     public void dump(PrintWriter pw) {
         pw.print("  mVisible="); pw.println(mVisible);
         pw.print("  mMinimized="); pw.println(mMinimized);
@@ -458,7 +447,7 @@
         return (long) (transitionDuration * transitionScale);
     }
 
-    /** Registers listener that gets called whenever the existence of the divider changes. */
+    @Override
     public void registerInSplitScreenListener(Consumer<Boolean> listener) {
         listener.accept(isDividerVisible());
         synchronized (mDockedStackExistsListeners) {
@@ -473,6 +462,42 @@
         }
     }
 
+    @Override
+    public boolean splitPrimaryTask() {
+        try {
+            if (ActivityTaskManager.getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED
+                    || isSplitActive()) {
+                return false;
+            }
+
+            // Try fetching the top running task.
+            final List<RunningTaskInfo> runningTasks =
+                    ActivityTaskManager.getService().getTasks(1 /* maxNum */);
+            if (runningTasks == null || runningTasks.isEmpty()) {
+                return false;
+            }
+            // Note: The set of running tasks from the system is ordered by recency.
+            final RunningTaskInfo topRunningTask = runningTasks.get(0);
+
+            final int activityType = topRunningTask.configuration.windowConfiguration
+                    .getActivityType();
+            if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
+                return false;
+            }
+
+            if (!topRunningTask.supportsSplitScreenMultiWindow) {
+                Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
+                        Toast.LENGTH_SHORT).show();
+                return false;
+            }
+
+            return ActivityTaskManager.getService().setTaskWindowingModeSplitScreenPrimary(
+                    topRunningTask.taskId, true /* onTop */);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
     /** Notifies the bounds of split screen changed. */
     void notifyBoundsChanged(Rect secondaryWindowBounds, Rect secondaryWindowInsets) {
         synchronized (mBoundsChangedListeners) {
@@ -532,7 +557,7 @@
         return mWindowManagerProxy;
     }
 
-    /** @return the container token for the secondary split root task. */
+    @Override
     public WindowContainerToken getSecondaryRoot() {
         if (mSplits == null || mSplits.mSecondary == null) {
             return null;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
new file mode 100644
index 0000000..080cddc
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.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.wm.shell.common;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.InsetsState.ITYPE_IME;
+import static android.view.Surface.ROTATION_0;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.graphics.Point;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.view.IInputMethodManager;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@SmallTest
+public class DisplayImeControllerTest {
+
+    private SurfaceControl.Transaction mT;
+    private DisplayImeController.PerDisplay mPerDisplay;
+    private IInputMethodManager mMock;
+
+    @Before
+    public void setUp() throws Exception {
+        mT = mock(SurfaceControl.Transaction.class);
+        mMock = mock(IInputMethodManager.class);
+        mPerDisplay = new DisplayImeController(null, null, Runnable::run, new TransactionPool() {
+            @Override
+            public SurfaceControl.Transaction acquire() {
+                return mT;
+            }
+
+            @Override
+            public void release(SurfaceControl.Transaction t) {
+            }
+        }) {
+            @Override
+            public IInputMethodManager getImms() {
+                return mMock;
+            }
+        }.new PerDisplay(DEFAULT_DISPLAY, ROTATION_0);
+    }
+
+    @Test
+    public void reappliesVisibilityToChangedLeash() {
+        verifyZeroInteractions(mT);
+
+        mPerDisplay.mImeShowing = false;
+        mPerDisplay.insetsControlChanged(new InsetsState(), new InsetsSourceControl[] {
+                new InsetsSourceControl(ITYPE_IME, mock(SurfaceControl.class), new Point(0, 0))
+        });
+
+        verify(mT).hide(any());
+
+        mPerDisplay.mImeShowing = true;
+        mPerDisplay.insetsControlChanged(new InsetsState(), new InsetsSourceControl[] {
+                new InsetsSourceControl(ITYPE_IME, mock(SurfaceControl.class), new Point(0, 0))
+        });
+
+        verify(mT).show(any());
+    }
+}
diff --git a/libs/androidfw/include/androidfw/CursorWindow.h b/libs/androidfw/include/androidfw/CursorWindow.h
index 73c76f0..0bee609 100644
--- a/libs/androidfw/include/androidfw/CursorWindow.h
+++ b/libs/androidfw/include/androidfw/CursorWindow.h
@@ -170,7 +170,7 @@
     Header* mHeader;
 
     inline void* offsetToPtr(uint32_t offset, uint32_t bufferSize = 0) {
-        if (offset >= mSize) {
+        if (offset > mSize) {
             ALOGE("Offset %" PRIu32 " out of bounds, max value %zu", offset, mSize);
             return NULL;
         }
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index 523a072..dbf4ad0 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -18,13 +18,13 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.StringDef;
-import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.media.browse.MediaBrowser;
 import android.media.session.MediaController;
+import android.media.session.MediaSession;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -417,14 +417,17 @@
     }
 
     private final Bundle mBundle;
+    private final int mBitmapDimensionLimit;
     private MediaDescription mDescription;
 
-    private MediaMetadata(Bundle bundle) {
+    private MediaMetadata(Bundle bundle, int bitmapDimensionLimit) {
         mBundle = new Bundle(bundle);
+        mBitmapDimensionLimit = bitmapDimensionLimit;
     }
 
     private MediaMetadata(Parcel in) {
         mBundle = in.readBundle();
+        mBitmapDimensionLimit = Math.max(in.readInt(), 0);
     }
 
     /**
@@ -513,6 +516,22 @@
         return bmp;
     }
 
+    /**
+     * Gets the width/height limit (in pixels) for the bitmaps when this metadata was created.
+     * This method returns a positive value or zero.
+     * <p>
+     * If it returns a positive value, then all the bitmaps in this metadata has width/height
+     * not greater than this limit. Bitmaps may have been scaled down according to the limit.
+     * <p>
+     * If it returns zero, then no scaling down was applied to the bitmaps when this metadata
+     * was created.
+     *
+     * @see Builder#setBitmapDimensionLimit(int)
+     */
+    public @IntRange(from = 0) int getBitmapDimensionLimit() {
+        return mBitmapDimensionLimit;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -521,6 +540,7 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeBundle(mBundle);
+        dest.writeInt(mBitmapDimensionLimit);
     }
 
     /**
@@ -718,6 +738,7 @@
      */
     public static final class Builder {
         private final Bundle mBundle;
+        private int mBitmapDimensionLimit;
 
         /**
          * Create an empty Builder. Any field that should be included in the
@@ -736,30 +757,7 @@
          */
         public Builder(MediaMetadata source) {
             mBundle = new Bundle(source.mBundle);
-        }
-
-        /**
-         * Create a Builder using a {@link MediaMetadata} instance to set
-         * initial values, but replace bitmaps with a scaled down copy if their width (or height)
-         * is larger than maxBitmapSize.
-         *
-         * @param source The original metadata to copy.
-         * @param maxBitmapSize The maximum height/width for bitmaps contained
-         *            in the metadata.
-         * @hide
-         */
-        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-        public Builder(@NonNull MediaMetadata source, @IntRange(from = 1) int maxBitmapSize) {
-            this(source);
-            for (String key : mBundle.keySet()) {
-                Object value = mBundle.get(key);
-                if (value != null && value instanceof Bitmap) {
-                    Bitmap bmp = (Bitmap) value;
-                    if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) {
-                        putBitmap(key, scaleBitmap(bmp, maxBitmapSize));
-                    }
-                }
-            }
+            mBitmapDimensionLimit = source.mBitmapDimensionLimit;
         }
 
         /**
@@ -902,9 +900,9 @@
          * <li>{@link #METADATA_KEY_DISPLAY_ICON}</li>
          * </ul>
          * <p>
-         * Large bitmaps may be scaled down by the system when
-         * {@link android.media.session.MediaSession#setMetadata} is called.
-         * To pass full resolution images {@link Uri Uris} should be used with
+         * Large bitmaps may be scaled down by the system with
+         * {@link Builder#setBitmapDimensionLimit(int)} when {@link MediaSession#setMetadata}
+         * is called. To pass full resolution images {@link Uri Uris} should be used with
          * {@link #putString}.
          *
          * @param key The key for referencing this value
@@ -923,18 +921,46 @@
         }
 
         /**
+         * Sets the maximum width/height (in pixels) for the bitmaps in the metadata.
+         * Bitmaps will be replaced with scaled down copies if their width (or height) is
+         * larger than {@code bitmapDimensionLimit}.
+         * <p>
+         * In order to unset the limit, pass zero as {@code bitmapDimensionLimit}.
+         *
+         * @param bitmapDimensionLimit The maximum width/height (in pixels) for bitmaps
+         *                             contained in the metadata. Pass {@code 0} to unset the limit.
+         */
+        @NonNull
+        public Builder setBitmapDimensionLimit(int bitmapDimensionLimit) {
+            mBitmapDimensionLimit = Math.max(bitmapDimensionLimit, 0);
+            return this;
+        }
+
+        /**
          * Creates a {@link MediaMetadata} instance with the specified fields.
          *
          * @return The new MediaMetadata instance
          */
         public MediaMetadata build() {
-            return new MediaMetadata(mBundle);
+            if (mBitmapDimensionLimit > 0) {
+                for (String key : mBundle.keySet()) {
+                    Object value = mBundle.get(key);
+                    if (value instanceof Bitmap) {
+                        Bitmap bmp = (Bitmap) value;
+                        if (bmp.getHeight() > mBitmapDimensionLimit
+                                || bmp.getWidth() > mBitmapDimensionLimit) {
+                            putBitmap(key, scaleBitmap(bmp, mBitmapDimensionLimit));
+                        }
+                    }
+                }
+            }
+            return new MediaMetadata(mBundle, mBitmapDimensionLimit);
         }
 
-        private Bitmap scaleBitmap(Bitmap bmp, int maxSize) {
-            float maxSizeF = maxSize;
-            float widthScale = maxSizeF / bmp.getWidth();
-            float heightScale = maxSizeF / bmp.getHeight();
+        private Bitmap scaleBitmap(Bitmap bmp, int maxDimension) {
+            float maxDimensionF = maxDimension;
+            float widthScale = maxDimensionF / bmp.getWidth();
+            float heightScale = maxDimensionF / bmp.getHeight();
             float scale = Math.min(widthScale, heightScale);
             int height = (int) (bmp.getHeight() * scale);
             int width = (int) (bmp.getWidth() * scale);
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index d35bc41..d02b496 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -372,7 +372,7 @@
                     AudioAttributes.toLegacyStreamType(mAudioAttributes)) != 0) {
                 startLocalPlayer();
             }
-        } else if (mAllowRemote && (mRemotePlayer != null)) {
+        } else if (mAllowRemote && (mRemotePlayer != null) && (mUri != null)) {
             final Uri canonicalUri = mUri.getCanonicalUri();
             final boolean looping;
             final float volume;
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 8deb0c4..c75296c 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -1130,11 +1130,13 @@
 
             // Try finding the scanned ringtone
             final String filename = getDefaultRingtoneFilename(type);
+            final String whichAudio = getQueryStringForType(type);
+            final String where = MediaColumns.DISPLAY_NAME + "=? AND " + whichAudio + "=?";
             final Uri baseUri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
             try (Cursor cursor = context.getContentResolver().query(baseUri,
                     new String[] { MediaColumns._ID },
-                    MediaColumns.DISPLAY_NAME + "=?",
-                    new String[] { filename }, null)) {
+                    where,
+                    new String[] { filename, "1" }, null)) {
                 if (cursor.moveToFirst()) {
                     final Uri ringtoneUri = context.getContentResolver().canonicalizeOrElse(
                             ContentUris.withAppendedId(baseUri, cursor.getLong(0)));
@@ -1162,4 +1164,13 @@
             default: throw new IllegalArgumentException();
         }
     }
+
+    private static String getQueryStringForType(int type) {
+        switch (type) {
+            case TYPE_RINGTONE: return MediaStore.Audio.AudioColumns.IS_RINGTONE;
+            case TYPE_NOTIFICATION: return MediaStore.Audio.AudioColumns.IS_NOTIFICATION;
+            case TYPE_ALARM: return MediaStore.Audio.AudioColumns.IS_ALARM;
+            default: throw new IllegalArgumentException();
+        }
+    }
 }
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 624607b..e17e069 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -464,7 +464,9 @@
         int fields = 0;
         MediaDescription description = null;
         if (metadata != null) {
-            metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build();
+            metadata = new MediaMetadata.Builder(metadata)
+                    .setBitmapDimensionLimit(mMaxBitmapSize)
+                    .build();
             if (metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
                 duration = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
             }
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index dd06ae0..ff95469 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -6138,6 +6138,7 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.app.PendingIntent> CREATOR;
     field public static final int FLAG_CANCEL_CURRENT = 268435456; // 0x10000000
     field public static final int FLAG_IMMUTABLE = 67108864; // 0x4000000
+    field public static final int FLAG_MUTABLE = 33554432; // 0x2000000
     field public static final int FLAG_NO_CREATE = 536870912; // 0x20000000
     field public static final int FLAG_ONE_SHOT = 1073741824; // 0x40000000
     field public static final int FLAG_UPDATE_CURRENT = 134217728; // 0x8000000
@@ -26317,6 +26318,7 @@
     method public boolean containsKey(String);
     method public int describeContents();
     method public android.graphics.Bitmap getBitmap(String);
+    method @IntRange(from=0) public int getBitmapDimensionLimit();
     method @NonNull public android.media.MediaDescription getDescription();
     method public long getLong(String);
     method public android.media.Rating getRating(String);
@@ -26366,6 +26368,7 @@
     method public android.media.MediaMetadata.Builder putRating(String, android.media.Rating);
     method public android.media.MediaMetadata.Builder putString(String, String);
     method public android.media.MediaMetadata.Builder putText(String, CharSequence);
+    method @NonNull public android.media.MediaMetadata.Builder setBitmapDimensionLimit(int);
   }
 
   @Deprecated public abstract class MediaMetadataEditor {
@@ -44934,6 +44937,7 @@
     field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
     field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool";
     field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
+    field public static final String KEY_CARRIER_USSD_METHOD_INT = "carrier_ussd_method_int";
     field public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL = "carrier_ut_provisioning_required_bool";
     field public static final String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
     field public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL = "carrier_volte_override_wfc_provisioning_bool";
@@ -45128,6 +45132,10 @@
     field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
     field public static final int SERVICE_CLASS_NONE = 0; // 0x0
     field public static final int SERVICE_CLASS_VOICE = 1; // 0x1
+    field public static final int USSD_OVER_CS_ONLY = 2; // 0x2
+    field public static final int USSD_OVER_CS_PREFERRED = 0; // 0x0
+    field public static final int USSD_OVER_IMS_ONLY = 3; // 0x3
+    field public static final int USSD_OVER_IMS_PREFERRED = 1; // 0x1
   }
 
   public static final class CarrierConfigManager.Apn {
@@ -51774,6 +51782,33 @@
     field public int toolType;
   }
 
+  public interface OnReceiveContentCallback<T extends android.view.View> {
+    method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull T);
+    method public boolean onReceiveContent(@NonNull T, @NonNull android.view.OnReceiveContentCallback.Payload);
+  }
+
+  public static final class OnReceiveContentCallback.Payload {
+    method @NonNull public android.content.ClipData getClip();
+    method @Nullable public android.os.Bundle getExtras();
+    method public int getFlags();
+    method @Nullable public android.net.Uri getLinkUri();
+    method public int getSource();
+    field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
+    field public static final int SOURCE_AUTOFILL = 3; // 0x3
+    field public static final int SOURCE_CLIPBOARD = 0; // 0x0
+    field public static final int SOURCE_DRAG_AND_DROP = 2; // 0x2
+    field public static final int SOURCE_INPUT_METHOD = 1; // 0x1
+    field public static final int SOURCE_PROCESS_TEXT = 4; // 0x4
+  }
+
+  public static final class OnReceiveContentCallback.Payload.Builder {
+    ctor public OnReceiveContentCallback.Payload.Builder(@NonNull android.content.ClipData, int);
+    method @NonNull public android.view.OnReceiveContentCallback.Payload build();
+    method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setExtras(@Nullable android.os.Bundle);
+    method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setFlags(int);
+    method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setLinkUri(@Nullable android.net.Uri);
+  }
+
   public abstract class OrientationEventListener {
     ctor public OrientationEventListener(android.content.Context);
     ctor public OrientationEventListener(android.content.Context, int);
@@ -52325,6 +52360,7 @@
     method @IdRes public int getNextFocusRightId();
     method @IdRes public int getNextFocusUpId();
     method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
+    method @Nullable public android.view.OnReceiveContentCallback<? extends android.view.View> getOnReceiveContentCallback();
     method @ColorInt public int getOutlineAmbientShadowColor();
     method public android.view.ViewOutlineProvider getOutlineProvider();
     method @ColorInt public int getOutlineSpotShadowColor();
@@ -52676,6 +52712,7 @@
     method public void setOnHoverListener(android.view.View.OnHoverListener);
     method public void setOnKeyListener(android.view.View.OnKeyListener);
     method public void setOnLongClickListener(@Nullable android.view.View.OnLongClickListener);
+    method public void setOnReceiveContentCallback(@Nullable android.view.OnReceiveContentCallback<? extends android.view.View>);
     method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener);
     method @Deprecated public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
     method public void setOnTouchListener(android.view.View.OnTouchListener);
@@ -58938,17 +58975,6 @@
     method public android.view.View newGroupView(android.content.Context, android.database.Cursor, boolean, android.view.ViewGroup);
   }
 
-  public interface RichContentReceiver<T extends android.view.View> {
-    method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes();
-    method public boolean onReceive(@NonNull T, @NonNull android.content.ClipData, int, int);
-    field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
-    field public static final int SOURCE_AUTOFILL = 3; // 0x3
-    field public static final int SOURCE_CLIPBOARD = 0; // 0x0
-    field public static final int SOURCE_DRAG_AND_DROP = 2; // 0x2
-    field public static final int SOURCE_INPUT_METHOD = 1; // 0x1
-    field public static final int SOURCE_PROCESS_TEXT = 4; // 0x4
-  }
-
   public class ScrollView extends android.widget.FrameLayout {
     ctor public ScrollView(android.content.Context);
     ctor public ScrollView(android.content.Context, android.util.AttributeSet);
@@ -59503,10 +59529,10 @@
     method public int getMinWidth();
     method public final android.text.method.MovementMethod getMovementMethod();
     method public int getOffsetForPosition(float, float);
+    method @Nullable public android.view.OnReceiveContentCallback<android.widget.TextView> getOnReceiveContentCallback();
     method public android.text.TextPaint getPaint();
     method public int getPaintFlags();
     method public String getPrivateImeOptions();
-    method @NonNull public android.widget.RichContentReceiver<android.widget.TextView> getRichContentReceiver();
     method public int getSelectionEnd();
     method public int getSelectionStart();
     method @ColorInt public int getShadowColor();
@@ -59634,7 +59660,6 @@
     method public void setPaintFlags(int);
     method public void setPrivateImeOptions(String);
     method public void setRawInputType(int);
-    method public void setRichContentReceiver(@NonNull android.widget.RichContentReceiver<android.widget.TextView>);
     method public void setScroller(android.widget.Scroller);
     method public void setSelectAllOnFocus(boolean);
     method public void setShadowLayer(float, float, float, int);
@@ -59675,7 +59700,6 @@
     method public void setWidth(int);
     field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
     field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
-    field @NonNull public static final android.widget.RichContentReceiver<android.widget.TextView> DEFAULT_RICH_CONTENT_RECEIVER;
   }
 
   public enum TextView.BufferType {
@@ -59692,6 +59716,12 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.widget.TextView.SavedState> CREATOR;
   }
 
+  public class TextViewOnReceiveContentCallback implements android.view.OnReceiveContentCallback<android.widget.TextView> {
+    ctor public TextViewOnReceiveContentCallback();
+    method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull android.widget.TextView);
+    method public boolean onReceiveContent(@NonNull android.widget.TextView, @NonNull android.view.OnReceiveContentCallback.Payload);
+  }
+
   public interface ThemedSpinnerAdapter extends android.widget.SpinnerAdapter {
     method @Nullable public android.content.res.Resources.Theme getDropDownViewTheme();
     method public void setDropDownViewTheme(@Nullable android.content.res.Resources.Theme);
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index 44b0ab8..11cd6a9 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -53,10 +53,6 @@
     field public static final int FLAG_FROM_KEY = 4096; // 0x1000
   }
 
-  public static final class MediaMetadata.Builder {
-    ctor public MediaMetadata.Builder(@NonNull android.media.MediaMetadata, @IntRange(from=1) int);
-  }
-
 }
 
 package android.media.session {
diff --git a/packages/CarSystemUI/res/drawable/car_ic_settings_icon.xml b/packages/CarSystemUI/res/drawable/car_ic_settings_icon.xml
new file mode 100644
index 0000000..147f539
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/car_ic_settings_icon.xml
@@ -0,0 +1,26 @@
+<?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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@*android:dimen/status_bar_system_icon_size"
+    android:height="@*android:dimen/status_bar_system_icon_size"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="@color/system_bar_icon_color"
+      android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4C9.75,2 9.54,2.18 9.51,2.42L9.13,5.07C8.52,5.32 7.96,5.66 7.44,6.05l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46C2.21,8.95 2.27,9.22 2.46,9.37l2.11,1.65C4.53,11.34 4.5,11.67 4.5,12s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65C9.54,21.82 9.75,22 10,22h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64L19.43,12.98zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5s3.5,1.57 3.5,3.5S13.93,15.5 12,15.5z"/>
+</vector>
diff --git a/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml b/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml
index 1195d05..270d932 100644
--- a/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml
@@ -21,5 +21,5 @@
     android:viewportHeight="24">
   <path
       android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"
-      android:fillColor="@color/system_bar_user_icon_color"/>
+      android:fillColor="@color/system_bar_icon_color"/>
 </vector>
\ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
index 07c11c7..7994b19 100644
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
@@ -36,6 +36,7 @@
             android:layout_height="match_parent"
             android:layout_alignParentStart="true"
             android:layout_marginTop="@dimen/car_padding_2"
+            android:layout_marginStart="@dimen/car_padding_2"
             android:layout_centerVertical="true"
             android:gravity="center_vertical"
         >
@@ -44,7 +45,6 @@
                 android:layout_height="match_parent"
                 android:background="@drawable/system_bar_background_pill"
                 android:layout_weight="1"
-                android:layout_marginStart="@dimen/car_padding_2"
                 android:gravity="center_vertical"
                 systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivities$QuickSettingActivity;launchFlags=0x24000000;end">
 
@@ -53,6 +53,8 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
+                    android:layout_marginStart="@dimen/car_padding_2"
+                    android:layout_marginEnd="@dimen/car_padding_2"
                     android:gravity="center_vertical"
                 />
             </com.android.systemui.car.navigationbar.CarNavigationButton>
diff --git a/packages/CarSystemUI/res/layout/system_icons.xml b/packages/CarSystemUI/res/layout/system_icons.xml
index 5c06075..f6ffcc8 100644
--- a/packages/CarSystemUI/res/layout/system_icons.xml
+++ b/packages/CarSystemUI/res/layout/system_icons.xml
@@ -20,16 +20,24 @@
     android:id="@+id/system_icons"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:gravity="center_vertical">
+    android:gravity="center_vertical"
+    android:orientation="horizontal">
 
     <com.android.systemui.statusbar.phone.StatusIconContainer
         android:id="@+id/statusIcons"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:layout_weight="1"
-        android:padding="10dp"
         android:scaleType="fitCenter"
         android:gravity="center_vertical"
         android:orientation="horizontal"
     />
+
+    <ImageView
+        android:id="@+id/settingsIcon"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginStart="@dimen/car_padding_2"
+        android:src="@drawable/car_ic_settings_icon"
+    />
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml
index 6fe5004..0181b9a 100644
--- a/packages/CarSystemUI/res/values/colors.xml
+++ b/packages/CarSystemUI/res/values/colors.xml
@@ -33,7 +33,7 @@
 
     <!-- colors for status bar -->
     <color name="system_bar_background_pill_color">#282A2D</color>
-    <color name="system_bar_user_icon_color">#FFFFFF</color>
+    <color name="system_bar_icon_color">#FFFFFF</color>
     <color name="system_bar_text_color">#FFFFFF</color>
     <color name="status_bar_background_color">#33000000</color>
     <drawable name="system_bar_background">@color/status_bar_background_color</drawable>
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
index fe060ac..86bfa75 100644
--- a/packages/CarSystemUI/res/values/dimens.xml
+++ b/packages/CarSystemUI/res/values/dimens.xml
@@ -46,6 +46,10 @@
        in frameworks/base/core package and thus will have no effect if
        set here. See car_product overlay for car specific defaults-->
 
+    <!-- Overrides the space between each status icon in the system bar -->
+    <dimen name="status_bar_system_icon_spacing">16dp</dimen>
+    <!-- Overrides the size of the network signal icon -->
+    <dimen name="signal_icon_size">32dp</dimen>
     <dimen name="system_bar_user_icon_padding">16dp</dimen>
     <dimen name="system_bar_user_icon_drawing_size">36dp</dimen>
     <!-- Padding on either side of the group of all system bar buttons -->
diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
index b113d29..f2ca495 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
@@ -50,6 +50,7 @@
 
     private final Context mContext;
     private final DisplayController mDisplayController;
+    private final Handler mHandler;
     private SparseArray<PerDisplay> mPerDisplaySparseArray;
 
     public DisplaySystemBarsController(
@@ -58,9 +59,10 @@
             DisplayController displayController,
             @Main Handler mainHandler,
             TransactionPool transactionPool) {
-        super(wmService, displayController, mainHandler, transactionPool);
+        super(wmService, displayController, (r) -> mainHandler.post(r), transactionPool);
         mContext = context;
         mDisplayController = displayController;
+        mHandler = mainHandler;
     }
 
     @Override
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 9788b30..0810979 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -437,6 +437,7 @@
                     Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG,
                     Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED,
                     Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
+                    Settings.Global.SHOW_PEOPLE_SPACE,
                     Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
                     Settings.Global.SHOW_TEMPERATURE_WARNING,
                     Settings.Global.SHOW_USB_TEMPERATURE_ALARM,
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index ce427cb..0eac4ad 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -511,14 +511,14 @@
             }
 
             if (msg.what != MSG_SERVICE_COMMAND) {
-                // Sanity check.
+                // Confidence check.
                 Log.e(TAG, "Invalid message type: " + msg.what);
                 return;
             }
 
             // At this point it's handling onStartCommand(), with the intent passed as an Extra.
             if (!(msg.obj instanceof Intent)) {
-                // Sanity check.
+                // Confidence check.
                 Log.wtf(TAG, "handleMessage(): invalid msg.obj type: " + msg.obj);
                 return;
             }
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index cd3cad1..3b02e3b 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -466,7 +466,7 @@
             // Clear properties
             mContext.getSharedPreferences(PREFS_BUGREPORT, Context.MODE_PRIVATE)
                     .edit().clear().commit();
-            // Sanity check...
+            // Confidence check...
             assertEquals("Did not reset properties", STATE_UNKNOWN,
                     getWarningState(mContext, STATE_UNKNOWN));
         } else {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index cffc10f..ee05c6c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -373,19 +373,6 @@
     }
 
     /**
-     * Moves an already resumed task to the side of the screen to initiate split screen.
-     */
-    public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode,
-            Rect initialBounds) {
-        try {
-            return ActivityTaskManager.getService().setTaskWindowingModeSplitScreenPrimary(taskId,
-                    true /* onTop */);
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
      * Registers a task stack listener with the system.
      * This should be called on the main thread.
      */
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index 2985a61..86129e0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -47,6 +47,7 @@
     public static final int FLAG_BACKGROUND_BLUR_RADIUS = 1 << 5;
     public static final int FLAG_VISIBILITY = 1 << 6;
     public static final int FLAG_RELATIVE_LAYER = 1 << 7;
+    public static final int FLAG_SHADOW_RADIUS = 1 << 8;
 
     private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
 
@@ -196,6 +197,7 @@
             SurfaceControl relativeTo;
             int relativeLayer;
             boolean visible;
+            float shadowRadius;
 
             /**
              * @param surface The surface to modify.
@@ -274,6 +276,16 @@
             }
 
             /**
+             * @param radius the Radius for the shadows to apply to the surface.
+             * @return this Builder
+             */
+            public Builder withShadowRadius(float radius) {
+                this.shadowRadius = radius;
+                flags |= FLAG_SHADOW_RADIUS;
+                return this;
+            }
+
+            /**
              * @param radius the Radius for blur to apply to the background surfaces.
              * @return this Builder
              */
@@ -298,31 +310,14 @@
              */
             public SurfaceParams build() {
                 return new SurfaceParams(surface, flags, alpha, matrix, windowCrop, layer,
-                        relativeTo, relativeLayer, cornerRadius, backgroundBlurRadius, visible);
+                        relativeTo, relativeLayer, cornerRadius, backgroundBlurRadius, visible,
+                        shadowRadius);
             }
         }
 
-        /**
-         * Constructs surface parameters to be applied when the current view state gets pushed to
-         * RenderThread.
-         *
-         * @param surface The surface to modify.
-         * @param alpha Alpha to apply.
-         * @param matrix Matrix to apply.
-         * @param windowCrop Crop to apply, only applied if not {@code null}
-         */
-        public SurfaceParams(SurfaceControlCompat surface, float alpha, Matrix matrix,
-                Rect windowCrop, int layer, SurfaceControl relativeTo, int relativeLayer,
-                float cornerRadius) {
-            this(surface.mSurfaceControl,
-                    FLAG_ALL & ~(FLAG_VISIBILITY | FLAG_BACKGROUND_BLUR_RADIUS), alpha,
-                    matrix, windowCrop, layer, relativeTo, relativeLayer, cornerRadius,
-                    0 /* backgroundBlurRadius */, true);
-        }
-
         private SurfaceParams(SurfaceControl surface, int flags, float alpha, Matrix matrix,
                 Rect windowCrop, int layer, SurfaceControl relativeTo, int relativeLayer,
-                float cornerRadius, int backgroundBlurRadius, boolean visible) {
+                float cornerRadius, int backgroundBlurRadius, boolean visible, float shadowRadius) {
             this.flags = flags;
             this.surface = surface;
             this.alpha = alpha;
@@ -334,6 +329,7 @@
             this.cornerRadius = cornerRadius;
             this.backgroundBlurRadius = backgroundBlurRadius;
             this.visible = visible;
+            this.shadowRadius = shadowRadius;
         }
 
         private final int flags;
@@ -349,6 +345,7 @@
         public final SurfaceControl relativeTo;
         public final int relativeLayer;
         public final boolean visible;
+        public final float shadowRadius;
 
         public void applyTo(SurfaceControl.Transaction t) {
             if ((flags & FLAG_MATRIX) != 0) {
@@ -379,6 +376,9 @@
             if ((flags & FLAG_RELATIVE_LAYER) != 0) {
                 t.setRelativeLayer(surface, relativeTo, relativeLayer);
             }
+            if ((flags & FLAG_SHADOW_RADIUS) != 0) {
+                t.setShadowRadius(surface, shadowRadius);
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index d79c96e..289ffbe 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.biometrics;
 
+import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.annotation.SuppressLint;
@@ -25,6 +26,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorProperties;
 import android.hardware.fingerprint.IUdfpsOverlayController;
 import android.os.PowerManager;
 import android.os.UserHandle;
@@ -41,6 +43,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.BrightnessSynchronizer;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.DozeReceiver;
@@ -50,13 +53,22 @@
 
 import java.io.FileWriter;
 import java.io.IOException;
+import java.util.List;
 
 import javax.inject.Inject;
 
 /**
  * Shows and hides the under-display fingerprint sensor (UDFPS) overlay, handles UDFPS touch events,
  * and coordinates triggering of the high-brightness mode (HBM).
+ *
+ * Note that the current architecture is designed so that a single {@link UdfpsController}
+ * controls/manages all UDFPS sensors. In other words, a single controller is registered with
+ * {@link com.android.server.biometrics.sensors.fingerprint.FingerprintService}, and interfaces such
+ * as {@link FingerprintManager#onFingerDown(int, int, int, float, float)} or
+ * {@link IUdfpsOverlayController#showUdfpsOverlay(int)}should all have
+ * {@code sensorId} parameters.
  */
+@SuppressWarnings("deprecation")
 class UdfpsController implements DozeReceiver {
     private static final String TAG = "UdfpsController";
     // Gamma approximation for the sRGB color space.
@@ -64,6 +76,10 @@
     private static final long AOD_INTERRUPT_TIMEOUT_MILLIS = 1000;
 
     private final FingerprintManager mFingerprintManager;
+    // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
+    // sensors, this, in addition to a lot of the code here, will be updated.
+    @VisibleForTesting
+    final int mUdfpsSensorId;
     private final WindowManager mWindowManager;
     private final SystemSettings mSystemSettings;
     private final DelayableExecutor mFgExecutor;
@@ -103,17 +119,17 @@
 
     public class UdfpsOverlayController extends IUdfpsOverlayController.Stub {
         @Override
-        public void showUdfpsOverlay() {
+        public void showUdfpsOverlay(int sensorId) {
             UdfpsController.this.setShowOverlay(true);
         }
 
         @Override
-        public void hideUdfpsOverlay() {
+        public void hideUdfpsOverlay(int sensorId) {
             UdfpsController.this.setShowOverlay(false);
         }
 
         @Override
-        public void setDebugMessage(String message) {
+        public void setDebugMessage(int sensorId, String message) {
             mView.setDebugMessage(message);
         }
     }
@@ -165,6 +181,17 @@
         mFgExecutor = fgExecutor;
         mLayoutParams = createLayoutParams(context);
 
+        int udfpsSensorId = -1;
+        for (FingerprintSensorProperties props : mFingerprintManager.getSensorProperties()) {
+            if (props.isAnyUdfpsType()) {
+                udfpsSensorId = props.sensorId;
+                break;
+            }
+        }
+        // At least one UDFPS sensor exists
+        checkArgument(udfpsSensorId != -1);
+        mUdfpsSensorId = udfpsSensorId;
+
         mView = (UdfpsView) inflater.inflate(R.layout.udfps_view, null, false);
 
         mHbmPath = resources.getString(R.string.udfps_hbm_sysfs_path);
@@ -347,7 +374,7 @@
                 fw.write(mHbmEnableCommand);
                 fw.close();
             }
-            mFingerprintManager.onFingerDown(x, y, minor, major);
+            mFingerprintManager.onFingerDown(mUdfpsSensorId, x, y, minor, major);
         } catch (IOException e) {
             mView.hideScrimAndDot();
             Log.e(TAG, "onFingerDown | failed to enable HBM: " + e.getMessage());
@@ -355,7 +382,7 @@
     }
 
     private void onFingerUp() {
-        mFingerprintManager.onFingerUp();
+        mFingerprintManager.onFingerUp(mUdfpsSensorId);
         // Hiding the scrim before disabling HBM results in less noticeable flicker.
         mView.hideScrimAndDot();
         if (mHbmSupported) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index e835ea2..46ef9bc 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -74,7 +74,7 @@
      */
     public static final int DEFAULT_STIFFNESS = 12000;
     public static final float IME_ANIMATION_STIFFNESS = SpringForce.STIFFNESS_LOW;
-    private static final int FLING_FOLLOW_STIFFNESS = 20000;
+    private static final int FLING_FOLLOW_STIFFNESS = 500;
     public static final float DEFAULT_BOUNCINESS = 0.9f;
 
     private final PhysicsAnimator.SpringConfig mAnimateOutSpringConfig =
diff --git a/packages/SystemUI/src/com/android/systemui/emergency/EmergencyGesture.java b/packages/SystemUI/src/com/android/systemui/emergency/EmergencyGesture.java
new file mode 100644
index 0000000..dccb24d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/emergency/EmergencyGesture.java
@@ -0,0 +1,40 @@
+/*
+ * 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.emergency;
+
+/**
+ * Constants for the Emergency gesture.
+ *
+ * TODO (b/169175022) Update classname and docs when feature name is locked
+ */
+public final class EmergencyGesture {
+
+    /**
+     * Launches the emergency flow.
+     *
+     * <p>The emergency flow is triggered by the Emergency gesture. By default the flow will call
+     * local emergency services, though OEMs can customize the flow.
+     *
+     * <p>This action can only be triggered by System UI through the emergency gesture.
+     *
+     * <p>TODO (b/169175022) Update action name and docs when feature name is locked
+     */
+    public static final String ACTION_LAUNCH_EMERGENCY =
+            "com.android.systemui.action.LAUNCH_EMERGENCY";
+
+    private EmergencyGesture() {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index daef2c5..5f726cd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -38,6 +38,7 @@
 import android.service.notification.ZenModeConfig;
 import android.text.TextUtils;
 import android.text.style.StyleSpan;
+import android.util.Log;
 
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
@@ -52,6 +53,8 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SystemUIAppComponentFactory;
+import com.android.systemui.SystemUIFactory;
+import com.android.systemui.dagger.SysUIComponent;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.StatusBarState;
@@ -62,6 +65,8 @@
 import com.android.systemui.util.wakelock.SettableWakeLock;
 import com.android.systemui.util.wakelock.WakeLock;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.Date;
 import java.util.Locale;
 import java.util.TimeZone;
@@ -80,6 +85,8 @@
         NotificationMediaManager.MediaListener, StatusBarStateController.StateListener,
         SystemUIAppComponentFactory.ContextInitializer {
 
+    private static final String TAG = "KgdSliceProvider";
+
     private static final StyleSpan BOLD_STYLE = new StyleSpan(Typeface.BOLD);
     public static final String KEYGUARD_SLICE_URI = "content://com.android.systemui.keyguard/main";
     private static final String KEYGUARD_HEADER_URI =
@@ -310,7 +317,25 @@
             mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
             mPendingIntent = PendingIntent.getActivity(getContext(), 0,
                     new Intent(getContext(), KeyguardSliceProvider.class), 0);
-            mMediaManager.addCallback(this);
+            try {
+                //TODO(b/168778439): Remove this whole try catch. This is for debugging in dogfood.
+                mMediaManager.addCallback(this);
+            } catch (NullPointerException e) {
+                // We are sometimes failing to set the media manager. Why?
+                Log.w(TAG, "Failed to setup mMediaManager. Trying again.");
+                SysUIComponent rootComponent = SystemUIFactory.getInstance().getSysUIComponent();
+                try {
+                    Method injectMethod = rootComponent.getClass()
+                            .getMethod("inject", getClass());
+                    injectMethod.invoke(rootComponent, this);
+                    Log.w("TAG", "mMediaManager is now: " + mMediaManager);
+                } catch (NoSuchMethodException ex) {
+                    Log.e(TAG, "Failed to find inject method for KeyguardSliceProvider", ex);
+                } catch (IllegalAccessException | InvocationTargetException ex) {
+                    Log.e(TAG, "Failed to call inject", ex);
+                }
+                throw e;
+            }
             mStatusBarStateController.addCallback(this);
             mNextAlarmController.addCallback(this);
             mZenModeController.addCallback(this);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index fb86535..b0fcdf8 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -325,9 +325,13 @@
             return;
         }
 
+        final Configuration initialConfig = mInitialState.remove(mToken.asBinder());
+        if (initialConfig == null) {
+            Log.wtf(TAG, "Token not in record, this should not happen mToken=" + mToken);
+            return;
+        }
         mPipUiEventLoggerLogger.log(
                 PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
-        final Configuration initialConfig = mInitialState.remove(mToken.asBinder());
         final boolean orientationDiffers = initialConfig.windowConfiguration.getRotation()
                 != mPipBoundsHandler.getDisplayRotation();
         final WindowContainerTransaction wct = new WindowContainerTransaction();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 2e258d5..8fec5a2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -30,6 +30,7 @@
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.media.AudioManager;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.AlarmClock;
@@ -64,6 +65,8 @@
 import com.android.systemui.DualToneHandler;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.demomode.DemoMode;
+import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
@@ -151,6 +154,8 @@
     private Space mSpace;
     private BatteryMeterView mBatteryRemainingIcon;
     private RingerModeTracker mRingerModeTracker;
+    private DemoModeController mDemoModeController;
+    private DemoMode mDemoModeReceiver;
     private boolean mAllIndicatorsEnabled;
     private boolean mMicCameraIndicatorsEnabled;
 
@@ -207,7 +212,7 @@
             StatusBarIconController statusBarIconController,
             ActivityStarter activityStarter, PrivacyItemController privacyItemController,
             CommandQueue commandQueue, RingerModeTracker ringerModeTracker,
-            UiEventLogger uiEventLogger) {
+            UiEventLogger uiEventLogger, DemoModeController demoModeController) {
         super(context, attrs);
         mAlarmController = nextAlarmController;
         mZenController = zenModeController;
@@ -219,6 +224,7 @@
         mCommandQueue = commandQueue;
         mRingerModeTracker = ringerModeTracker;
         mUiEventLogger = uiEventLogger;
+        mDemoModeController = demoModeController;
     }
 
     @Override
@@ -268,6 +274,7 @@
 
         mClockView = findViewById(R.id.clock);
         mClockView.setOnClickListener(this);
+        mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
         mDateView = findViewById(R.id.date);
         mSpace = findViewById(R.id.space);
 
@@ -526,6 +533,7 @@
             updateStatusText();
         });
         mStatusBarIconController.addIconGroup(mIconManager);
+        mDemoModeController.addCallback(mDemoModeReceiver);
         requestApplyInsets();
     }
 
@@ -606,6 +614,7 @@
         setListening(false);
         mRingerModeTracker.getRingerModeInternal().removeObservers(this);
         mStatusBarIconController.removeIconGroup(mIconManager);
+        mDemoModeController.removeCallback(mDemoModeReceiver);
         super.onDetachedFromWindow();
     }
 
@@ -769,4 +778,33 @@
     private boolean getChipEnabled() {
         return mMicCameraIndicatorsEnabled || mAllIndicatorsEnabled;
     }
+
+    private static class ClockDemoModeReceiver implements DemoMode {
+        private Clock mClockView;
+
+        @Override
+        public List<String> demoCommands() {
+            return List.of(COMMAND_CLOCK);
+        }
+
+        ClockDemoModeReceiver(Clock clockView) {
+            mClockView = clockView;
+        }
+
+        @Override
+        public void dispatchDemoCommand(String command, Bundle args) {
+            mClockView.dispatchDemoCommand(command, args);
+        }
+
+        @Override
+        public void onDemoModeStarted() {
+            mClockView.onDemoModeStarted();
+        }
+
+        @Override
+        public void onDemoModeFinished() {
+            mClockView.onDemoModeFinished();
+        }
+    }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index 47002683..bbeff6e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -16,30 +16,17 @@
 
 package com.android.systemui.recents;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-
 import android.annotation.Nullable;
-import android.app.ActivityManager;
 import android.app.trust.TrustManager;
 import android.content.Context;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.util.Log;
-import android.view.Display;
-import android.widget.Toast;
 
 import com.android.systemui.Dependency;
-import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.shared.recents.IOverviewProxy;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.wm.shell.splitscreen.SplitScreen;
 
 import java.util.Optional;
 
@@ -56,7 +43,6 @@
     private final static String TAG = "OverviewProxyRecentsImpl";
     @Nullable
     private final Lazy<StatusBar> mStatusBarLazy;
-    private final Optional<SplitScreen> mSplitScreenOptional;
 
     private Context mContext;
     private Handler mHandler;
@@ -65,10 +51,8 @@
 
     @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
     @Inject
-    public OverviewProxyRecentsImpl(Optional<Lazy<StatusBar>> statusBarLazy,
-            Optional<SplitScreen> splitScreenOptional) {
+    public OverviewProxyRecentsImpl(Optional<Lazy<StatusBar>> statusBarLazy) {
         mStatusBarLazy = statusBarLazy.orElse(null);
-        mSplitScreenOptional = splitScreenOptional;
     }
 
     @Override
@@ -140,42 +124,4 @@
             // Do nothing
         }
     }
-
-    @Override
-    public boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,
-            int metricsDockAction) {
-        Point realSize = new Point();
-        if (initialBounds == null) {
-            mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
-                    .getRealSize(realSize);
-            initialBounds = new Rect(0, 0, realSize.x, realSize.y);
-        }
-
-        ActivityManager.RunningTaskInfo runningTask =
-                ActivityManagerWrapper.getInstance().getRunningTask();
-        final int activityType = runningTask != null
-                ? runningTask.configuration.windowConfiguration.getActivityType()
-                : ACTIVITY_TYPE_UNDEFINED;
-        boolean screenPinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
-        boolean isRunningTaskInHomeOrRecentsStack =
-                activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS;
-        if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) {
-            if (runningTask.supportsSplitScreenMultiWindow) {
-                if (ActivityManagerWrapper.getInstance().setTaskWindowingModeSplitScreenPrimary(
-                        runningTask.id, stackCreateMode, initialBounds)) {
-                    mSplitScreenOptional.ifPresent(splitScreen -> {
-                        splitScreen.onDockedTopTask();
-                        // The overview service is handling split screen, so just skip the wait
-                        // for the first draw and notify the divider to start animating now
-                        splitScreen.onRecentsDrawn();
-                    });
-                    return true;
-                }
-            } else {
-                Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
-                        Toast.LENGTH_SHORT).show();
-            }
-        }
-        return false;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index df61fd1..6f6dd9c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -19,7 +19,6 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Configuration;
-import android.graphics.Rect;
 import android.provider.Settings;
 
 import com.android.systemui.SystemUI;
@@ -120,17 +119,6 @@
         mImpl.cancelPreloadRecentApps();
     }
 
-    public boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,
-            int metricsDockAction) {
-        // Ensure the device has been provisioned before allowing the user to interact with
-        // recents
-        if (!isUserSetup()) {
-            return false;
-        }
-
-        return mImpl.splitPrimaryTask(stackCreateMode, initialBounds, metricsDockAction);
-    }
-
     /**
      * @return whether this device is provisioned and the current user is set up.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
index a641730..8848dbb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
@@ -17,7 +17,6 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
-import android.graphics.Rect;
 
 import java.io.PrintWriter;
 
@@ -35,10 +34,6 @@
     default void showRecentApps(boolean triggeredFromAltTab) {}
     default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {}
     default void toggleRecentApps() {}
-    default boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,
-            int metricsDockAction) {
-        return false;
-    }
 
     default void dump(PrintWriter pw) {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index b9b4f42..6202057 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -16,9 +16,6 @@
 
 package com.android.systemui.shortcut;
 
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
-
 import android.content.Context;
 import android.content.res.Configuration;
 import android.os.RemoteException;
@@ -29,7 +26,6 @@
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.systemui.SystemUI;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.recents.Recents;
 import com.android.wm.shell.splitscreen.DividerView;
 import com.android.wm.shell.splitscreen.SplitScreen;
 
@@ -46,7 +42,6 @@
 
     private static final String TAG = "ShortcutKeyDispatcher";
     private final Optional<SplitScreen> mSplitScreenOptional;
-    private final Recents mRecents;
 
     private ShortcutKeyServiceProxy mShortcutKeyServiceProxy = new ShortcutKeyServiceProxy(this);
     private IWindowManager mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
@@ -60,11 +55,9 @@
     protected final long SC_DOCK_RIGHT = META_MASK | KeyEvent.KEYCODE_RIGHT_BRACKET;
 
     @Inject
-    public ShortcutKeyDispatcher(Context context,
-            Optional<SplitScreen> splitScreenOptional, Recents recents) {
+    public ShortcutKeyDispatcher(Context context, Optional<SplitScreen> splitScreenOptional) {
         super(context);
         mSplitScreenOptional = splitScreenOptional;
-        mRecents = recents;
     }
 
     /**
@@ -96,8 +89,7 @@
     }
 
     private void handleDockKey(long shortcutCode) {
-        if (mSplitScreenOptional.isPresent()) {
-            SplitScreen splitScreen = mSplitScreenOptional.get();
+        mSplitScreenOptional.ifPresent(splitScreen -> {
             if (splitScreen.isDividerVisible()) {
                 // If there is already a docked window, we respond by resizing the docking pane.
                 DividerView dividerView = splitScreen.getDividerView();
@@ -112,12 +104,9 @@
                 dividerView.stopDragging(target.position, 0f, false /* avoidDismissStart */,
                         true /* logMetrics */);
                 return;
+            } else {
+                splitScreen.splitPrimaryTask();
             }
-        }
-
-        // Split the screen
-        mRecents.splitPrimaryTask((shortcutCode == SC_DOCK_LEFT)
-                ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
-                : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1);
+        });
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 3d51854..54fb863 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -168,7 +168,7 @@
         int iconRes = isAnim ? getThemedAnimationResId(lockAnimIndex) : getIconForState(newState);
 
         if (!mDrawableCache.contains(iconRes)) {
-            mDrawableCache.put(iconRes, getResources().getDrawable(iconRes));
+            mDrawableCache.put(iconRes, getContext().getDrawable(iconRes));
         }
 
         return mDrawableCache.get(iconRes);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 994af09..e7c29b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 import static android.app.StatusBarManager.WindowType;
@@ -37,7 +35,6 @@
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
 import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID;
-import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_LEFT;
 import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
@@ -174,7 +171,6 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.qs.QSPanel;
-import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -718,7 +714,6 @@
             DozeScrimController dozeScrimController,
             VolumeComponent volumeComponent,
             CommandQueue commandQueue,
-            Optional<Recents> recentsOptional,
             Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
             PluginManager pluginManager,
             Optional<SplitScreen> splitScreenOptional,
@@ -799,7 +794,6 @@
         mNotificationShadeDepthControllerLazy = notificationShadeDepthControllerLazy;
         mVolumeComponent = volumeComponent;
         mCommandQueue = commandQueue;
-        mRecentsOptional = recentsOptional;
         mStatusBarComponentBuilder = statusBarComponentBuilder;
         mPluginManager = pluginManager;
         mSplitScreenOptional = splitScreenOptional;
@@ -1548,35 +1542,37 @@
     }
 
     public boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
-        if (!mRecentsOptional.isPresent()) {
+        if (!mSplitScreenOptional.isPresent()) {
             return false;
         }
 
-        if (mSplitScreenOptional.isPresent()) {
-            SplitScreen splitScreen = mSplitScreenOptional.get();
-            if (splitScreen.isDividerVisible()) {
-                if (splitScreen.isMinimized()
-                        && !splitScreen.isHomeStackResizable()) {
-                    // Undocking from the minimized state is not supported
-                    return false;
-                } else {
-                    splitScreen.onUndockingTask();
-                    if (metricsUndockAction != -1) {
-                        mMetricsLogger.action(metricsUndockAction);
-                    }
-                }
-                return true;
+        final SplitScreen splitScreen = mSplitScreenOptional.get();
+        if (splitScreen.isDividerVisible()) {
+            if (splitScreen.isMinimized() && !splitScreen.isHomeStackResizable()) {
+                // Undocking from the minimized state is not supported
+                return false;
             }
+
+            splitScreen.onUndockingTask();
+            if (metricsUndockAction != -1) {
+                mMetricsLogger.action(metricsUndockAction);
+            }
+            return true;
         }
 
         final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(mDisplayId);
         if (navbarPos == NAV_BAR_POS_INVALID) {
             return false;
         }
-        int createMode = navbarPos == NAV_BAR_POS_LEFT
-                ? SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT
-                : SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
-        return mRecentsOptional.get().splitPrimaryTask(createMode, null, metricsDockAction);
+
+        if (splitScreen.splitPrimaryTask()) {
+            if (metricsDockAction != -1) {
+                mMetricsLogger.action(metricsDockAction);
+            }
+            return true;
+        }
+
+        return false;
     }
 
     /**
@@ -4121,8 +4117,6 @@
     protected Display mDisplay;
     private int mDisplayId;
 
-    private final Optional<Recents> mRecentsOptional;
-
     protected NotificationShelfController mNotificationShelfController;
 
     private final Lazy<AssistManager> mAssistManagerLazy;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 3f29a4e..6d4099b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -43,7 +43,6 @@
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.PluginDependencyProvider;
-import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.CommandQueue;
@@ -175,7 +174,6 @@
             DozeScrimController dozeScrimController,
             VolumeComponent volumeComponent,
             CommandQueue commandQueue,
-            Optional<Recents> recentsOptional,
             Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
             PluginManager pluginManager,
             Optional<SplitScreen> splitScreenOptional,
@@ -254,7 +252,6 @@
                 dozeScrimController,
                 volumeComponent,
                 commandQueue,
-                recentsOptional,
                 statusBarComponentBuilder,
                 pluginManager,
                 splitScreenOptional,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java
index 7a78c15..0bd3624 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java
@@ -58,6 +58,10 @@
         if (!mNotificationHandlerPackage.isEmpty()) {
             startNotificationHandlerActivity(
                     new Intent(NotificationManager.ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL));
+        } else {
+            Log.w(TAG,
+                    "Not toggling notification panel: config_notificationHandlerPackage is "
+                            + "empty");
         }
     }
 
@@ -66,6 +70,10 @@
         if (!mNotificationHandlerPackage.isEmpty()) {
             startNotificationHandlerActivity(
                     new Intent(NotificationManager.ACTION_OPEN_NOTIFICATION_HANDLER_PANEL));
+        } else {
+            Log.w(TAG,
+                    "Not expanding notification panel: config_notificationHandlerPackage is "
+                            + "empty");
         }
     }
 
@@ -77,6 +85,9 @@
                     NotificationManager.ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL);
             closeNotificationIntent.setPackage(mNotificationHandlerPackage);
             mContext.sendBroadcastAsUser(closeNotificationIntent, UserHandle.CURRENT);
+        } else {
+            Log.w(TAG,
+                    "Not closing notification panel: config_notificationHandlerPackage is empty");
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
index a50de45..1e6a9e8 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -32,6 +32,8 @@
 import com.android.wm.shell.splitscreen.SplitScreen;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 
+import java.util.concurrent.Executor;
+
 import dagger.Module;
 import dagger.Provides;
 
@@ -45,9 +47,10 @@
     @SysUISingleton
     @Provides
     static DisplayImeController provideDisplayImeController(IWindowManager wmService,
-            DisplayController displayController, @Main Handler mainHandler,
+            DisplayController displayController, @Main Executor mainExecutor,
             TransactionPool transactionPool) {
-        return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
+        return new DisplayImeController(wmService, displayController, mainExecutor,
+                transactionPool);
     }
 
     static SplitScreen provideSplitScreen(Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 3142c1e..b4852b2 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -45,6 +45,7 @@
 import com.android.wm.shell.splitscreen.SplitScreenController;
 
 import java.util.Optional;
+import java.util.concurrent.Executor;
 
 import dagger.Module;
 import dagger.Provides;
@@ -59,9 +60,10 @@
     @SysUISingleton
     @Provides
     static DisplayImeController provideDisplayImeController(IWindowManager wmService,
-            DisplayController displayController, @Main Handler mainHandler,
+            DisplayController displayController, @Main Executor mainExecutor,
             TransactionPool transactionPool) {
-        return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
+        return new DisplayImeController(wmService, displayController, mainExecutor,
+                transactionPool);
     }
 
     @SysUISingleton
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 9b9f840..7df9f1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.biometrics;
 
+import static junit.framework.Assert.assertEquals;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.eq;
@@ -25,7 +27,9 @@
 
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.hardware.biometrics.SensorProperties;
 import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorProperties;
 import android.hardware.fingerprint.IUdfpsOverlayController;
 import android.os.PowerManager;
 import android.os.RemoteException;
@@ -54,11 +58,18 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 public class UdfpsControllerTest extends SysuiTestCase {
 
+    // Use this for inputs going into SystemUI. Use UdfpsController.mUdfpsSensorId for things
+    // leaving SystemUI.
+    private static final int TEST_UDFPS_SENSOR_ID = 1;
+
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();
 
@@ -98,6 +109,13 @@
     public void setUp() {
         setUpResources();
         when(mLayoutInflater.inflate(R.layout.udfps_view, null, false)).thenReturn(mUdfpsView);
+        final List<FingerprintSensorProperties> props = new ArrayList<>();
+        props.add(new FingerprintSensorProperties(TEST_UDFPS_SENSOR_ID,
+                SensorProperties.STRENGTH_STRONG,
+                5 /* maxEnrollmentsPerUser */,
+                FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
+                true /* resetLockoutRequiresHardwareAuthToken */));
+        when(mFingerprintManager.getSensorProperties()).thenReturn(props);
         mSystemSettings = new FakeSettings();
         mFgExecutor = new FakeExecutor(new FakeSystemClock());
         mUdfpsController = new UdfpsController(
@@ -112,6 +130,8 @@
                 mFgExecutor);
         verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
         mOverlayController = mOverlayCaptor.getValue();
+
+        assertEquals(TEST_UDFPS_SENSOR_ID, mUdfpsController.mUdfpsSensorId);
     }
 
     private void setUpResources() {
@@ -138,15 +158,15 @@
 
     @Test
     public void showUdfpsOverlay_addsViewToWindow() throws RemoteException {
-        mOverlayController.showUdfpsOverlay();
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
         mFgExecutor.runAllReady();
         verify(mWindowManager).addView(eq(mUdfpsView), any());
     }
 
     @Test
     public void hideUdfpsOverlay_removesViewFromWindow() throws RemoteException {
-        mOverlayController.showUdfpsOverlay();
-        mOverlayController.hideUdfpsOverlay();
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
+        mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
         mFgExecutor.runAllReady();
         verify(mWindowManager).removeView(eq(mUdfpsView));
     }
@@ -156,7 +176,7 @@
         // GIVEN that the bouncer is showing
         mUdfpsController.setBouncerVisibility(/* isShowing */ true);
         // WHEN a request to show the overlay is received
-        mOverlayController.showUdfpsOverlay();
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
         mFgExecutor.runAllReady();
         // THEN the overlay is not attached
         verify(mWindowManager, never()).addView(eq(mUdfpsView), any());
@@ -165,7 +185,7 @@
     @Test
     public void setBouncerVisibility_overlayDetached() throws RemoteException {
         // GIVEN that the overlay has been requested
-        mOverlayController.showUdfpsOverlay();
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
         // WHEN the bouncer becomes visible
         mUdfpsController.setBouncerVisibility(/* isShowing */ true);
         mFgExecutor.runAllReady();
@@ -178,7 +198,7 @@
         // GIVEN that the bouncer is visible
         mUdfpsController.setBouncerVisibility(/* isShowing */ true);
         // AND the overlay has been requested
-        mOverlayController.showUdfpsOverlay();
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
         // WHEN the bouncer is closed
         mUdfpsController.setBouncerVisibility(/* isShowing */ false);
         mFgExecutor.runAllReady();
@@ -193,7 +213,7 @@
         when(mUdfpsView.isValidTouch(anyFloat(), anyFloat(), anyFloat())).thenReturn(true);
 
         // GIVEN that the overlay is showing
-        mOverlayController.showUdfpsOverlay();
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
         mFgExecutor.runAllReady();
         // WHEN ACTION_DOWN is received
         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
@@ -201,7 +221,8 @@
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
         event.recycle();
         // THEN the event is passed to the FingerprintManager
-        verify(mFingerprintManager).onFingerDown(eq(0), eq(0), eq(0f), eq(0f));
+        verify(mFingerprintManager).onFingerDown(eq(mUdfpsController.mUdfpsSensorId), eq(0), eq(0),
+                eq(0f), eq(0f));
         // AND the scrim and dot is shown
         verify(mUdfpsView).showScrimAndDot();
     }
@@ -209,12 +230,13 @@
     @Test
     public void aodInterrupt() throws RemoteException {
         // GIVEN that the overlay is showing
-        mOverlayController.showUdfpsOverlay();
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
         mFgExecutor.runAllReady();
         // WHEN fingerprint is requested because of AOD interrupt
         mUdfpsController.onAodInterrupt(0, 0);
         // THEN the event is passed to the FingerprintManager
-        verify(mFingerprintManager).onFingerDown(eq(0), eq(0), anyFloat(), anyFloat());
+        verify(mFingerprintManager).onFingerDown(eq(mUdfpsController.mUdfpsSensorId), eq(0), eq(0),
+                anyFloat(), anyFloat());
         // AND the scrim and dot is shown
         verify(mUdfpsView).showScrimAndDot();
     }
@@ -222,7 +244,7 @@
     @Test
     public void cancelAodInterrupt() throws RemoteException {
         // GIVEN AOD interrupt
-        mOverlayController.showUdfpsOverlay();
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
         mFgExecutor.runAllReady();
         mUdfpsController.onAodInterrupt(0, 0);
         // WHEN it is cancelled
@@ -234,7 +256,7 @@
     @Test
     public void aodInterruptTimeout() throws RemoteException {
         // GIVEN AOD interrupt
-        mOverlayController.showUdfpsOverlay();
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
         mFgExecutor.runAllReady();
         mUdfpsController.onAodInterrupt(0, 0);
         // WHEN it times out
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 23b12d4..a6ea9966a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -93,7 +93,6 @@
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.PluginDependencyProvider;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.CommandQueue;
@@ -232,7 +231,6 @@
     @Mock private KeyguardLiftController mKeyguardLiftController;
     @Mock private VolumeComponent mVolumeComponent;
     @Mock private CommandQueue mCommandQueue;
-    @Mock private Recents mRecents;
     @Mock private Provider<StatusBarComponent.Builder> mStatusBarComponentBuilderProvider;
     @Mock private StatusBarComponent.Builder mStatusBarComponentBuilder;
     @Mock private StatusBarComponent mStatusBarComponent;
@@ -392,7 +390,6 @@
                 mDozeScrimController,
                 mVolumeComponent,
                 mCommandQueue,
-                Optional.of(mRecents),
                 mStatusBarComponentBuilderProvider,
                 mPluginManager,
                 Optional.of(mSplitScreen),
diff --git a/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java b/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
index 73fc833..084743d 100644
--- a/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
+++ b/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
@@ -25,7 +25,6 @@
 import static android.system.OsConstants.SOCK_RAW;
 
 import android.net.util.InterfaceParams;
-import android.net.util.PacketReader;
 import android.net.util.SocketUtils;
 import android.net.util.TetheringUtils;
 import android.os.Handler;
@@ -33,6 +32,8 @@
 import android.system.Os;
 import android.util.Log;
 
+import com.android.net.module.util.PacketReader;
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.net.Inet6Address;
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 7dd5290..64d5025 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -2104,7 +2104,7 @@
     }
 
     private boolean hasCallingPermission(@NonNull String permission) {
-        return mContext.checkCallingPermission(permission) == PERMISSION_GRANTED;
+        return mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED;
     }
 
     /** Unregister tethering event callback */
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 8a1baf2..da5d1c2 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -136,8 +136,6 @@
 import android.net.metrics.NetworkEvent;
 import android.net.netlink.InetDiagMessage;
 import android.net.shared.PrivateDnsConfig;
-import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult;
-import android.net.util.LinkPropertiesUtils.CompareResult;
 import android.net.util.MultinetworkPolicyTracker;
 import android.net.util.NetdService;
 import android.os.Binder;
@@ -195,6 +193,8 @@
 import com.android.internal.util.LocationPermissionChecker;
 import com.android.internal.util.MessageUtils;
 import com.android.internal.util.XmlUtils;
+import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
+import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.connectivity.AutodestructReference;
 import com.android.server.connectivity.DataConnectionStats;
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index 4a1820a..d907505 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -25,7 +25,6 @@
 import android.net.nsd.INsdManager;
 import android.net.nsd.NsdManager;
 import android.net.nsd.NsdServiceInfo;
-import android.net.util.nsd.DnsSdTxtRecord;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
@@ -42,6 +41,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
+import com.android.net.module.util.DnsSdTxtRecord;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4f056df..ffdcd15 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17334,4 +17334,18 @@
             throw new SecurityException("Caller uid " + callerUid + " cannot set freezer state ");
         }
     }
+
+    /**
+     * Holds the AM lock for the specified amount of milliseconds.
+     * Intended for use by the tests that need to imitate lock contention.
+     * Requires permission identity of the shell UID.
+     */
+    @Override
+    public void holdLock(int durationMs) {
+        enforceCallingPermission(Manifest.permission.INJECT_EVENTS, "holdLock");
+
+        synchronized (this) {
+            SystemClock.sleep(durationMs);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 1bf62a0..58ac2dc 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -733,10 +733,6 @@
             uidRec.reset();
         }
 
-        if (mService.mAtmInternal != null) {
-            mService.mAtmInternal.rankTaskLayersIfNeeded();
-        }
-
         mAdjSeq++;
         if (fullUpdate) {
             mNewNumServiceProcs = 0;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 2dced8d..ebc5b59 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1909,8 +1909,8 @@
         }
         callback.initialize(this, adj, foregroundActivities, procState, schedGroup, appUid, logUid,
                 processCurTop);
-        final int minLayer = getWindowProcessController().computeOomAdjFromActivities(
-                ProcessList.VISIBLE_APP_LAYER_MAX, callback);
+        final int minLayer = Math.min(ProcessList.VISIBLE_APP_LAYER_MAX,
+                getWindowProcessController().computeOomAdjFromActivities(callback));
 
         mCachedAdj = callback.adj;
         mCachedForegroundActivities = callback.foregroundActivities;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 2903b9970..cc94079 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -46,6 +46,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.EventLog;
+import android.util.Pair;
 import android.util.Slog;
 import android.view.Surface;
 
@@ -79,7 +80,7 @@
     private final LockoutResetDispatcher mLockoutResetDispatcher;
     private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
     private final LockPatternUtils mLockPatternUtils;
-    private Fingerprint21 mFingerprint21;
+    @NonNull private List<ServiceProvider> mServiceProviders;
 
     /**
      * Receives the incoming binder calls from FingerprintManager.
@@ -88,11 +89,8 @@
         @Override // Binder call
         public List<FingerprintSensorProperties> getSensorProperties(String opPackageName) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
-            final List<FingerprintSensorProperties> properties = new ArrayList<>();
-
-            if (mFingerprint21 != null) {
-                properties.add(mFingerprint21.getFingerprintSensorProperties());
-            }
+            final List<FingerprintSensorProperties> properties =
+                    FingerprintService.this.getSensorProperties();
 
             Slog.d(TAG, "Retrieved sensor properties for: " + opPackageName
                     + ", sensors: " + properties.size());
@@ -104,18 +102,26 @@
                 IFingerprintServiceReceiver receiver, String opPackageName) {
             Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
 
-            if (sensorId == mFingerprint21.getFingerprintSensorProperties().sensorId) {
-                mFingerprint21.scheduleGenerateChallenge(token, receiver, opPackageName);
+            final ServiceProvider provider = getProviderForSensor(sensorId);
+            if (provider == null) {
+                Slog.w(TAG, "No matching sensor for generateChallenge, sensorId: " + sensorId);
                 return;
             }
 
-            Slog.w(TAG, "No matching sensor for generateChallenge, sensorId: " + sensorId);
+            provider.scheduleGenerateChallenge(sensorId, token, receiver, opPackageName);
         }
 
         @Override // Binder call
-        public void revokeChallenge(IBinder token, String owner) {
+        public void revokeChallenge(IBinder token, String opPackageName) {
             Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
-            mFingerprint21.scheduleRevokeChallenge(token, owner);
+
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for revokeChallenge");
+                return;
+            }
+
+            provider.second.scheduleRevokeChallenge(provider.first, token, opPackageName);
         }
 
         @Override // Binder call
@@ -123,14 +129,28 @@
                 final IFingerprintServiceReceiver receiver, final String opPackageName,
                 Surface surface) {
             Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
-            mFingerprint21.scheduleEnroll(token, hardwareAuthToken, userId, receiver, opPackageName,
-                    surface);
+
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for enroll");
+                return;
+            }
+
+            provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId,
+                    receiver, opPackageName, surface);
         }
 
         @Override // Binder call
         public void cancelEnrollment(final IBinder token) {
             Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
-            mFingerprint21.cancelEnrollment(token);
+
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for cancelEnrollment");
+                return;
+            }
+
+            provider.second.cancelEnrollment(provider.first, token);
         }
 
         @Override // Binder call
@@ -169,8 +189,15 @@
                     != PackageManager.PERMISSION_GRANTED;
             final int statsClient = isKeyguard ? BiometricsProtoEnums.CLIENT_KEYGUARD
                     : BiometricsProtoEnums.CLIENT_FINGERPRINT_MANAGER;
-            mFingerprint21.scheduleAuthenticate(token, operationId, userId, 0 /* cookie */,
-                    new ClientMonitorCallbackConverter(receiver), opPackageName,
+
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for authenticate");
+                return;
+            }
+
+            provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
+                    0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName,
                     restricted, statsClient, isKeyguard);
         }
 
@@ -191,7 +218,13 @@
                 return;
             }
 
-            mFingerprint21.scheduleFingerDetect(token, userId,
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for detectFingerprint");
+                return;
+            }
+
+            provider.second.scheduleFingerDetect(provider.first, token, userId,
                     new ClientMonitorCallbackConverter(receiver), opPackageName, surface,
                     BiometricsProtoEnums.CLIENT_KEYGUARD);
         }
@@ -203,8 +236,14 @@
                 Surface surface) {
             Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
 
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for prepareForAuthentication");
+                return;
+            }
+
             final boolean restricted = true; // BiometricPrompt is always restricted
-            mFingerprint21.scheduleAuthenticate(token, operationId, userId, cookie,
+            provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, cookie,
                     new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
                     BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, false /* isKeyguard */);
         }
@@ -212,7 +251,14 @@
         @Override // Binder call
         public void startPreparedClient(int cookie) {
             Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
-            mFingerprint21.startPreparedClient(cookie);
+
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for startPreparedClient");
+                return;
+            }
+
+            provider.second.startPreparedClient(provider.first, cookie);
         }
 
 
@@ -228,7 +274,13 @@
                 return;
             }
 
-            mFingerprint21.cancelAuthentication(token);
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for cancelAuthentication");
+                return;
+            }
+
+            provider.second.cancelAuthentication(provider.first, token);
         }
 
         @Override // Binder call
@@ -242,21 +294,41 @@
 
             // For IBiometricsFingerprint2.1, cancelling fingerprint detect is the same as
             // cancelling authentication.
-            mFingerprint21.cancelAuthentication(token);
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for cancelFingerprintDetect");
+                return;
+            }
+
+            provider.second.cancelAuthentication(provider.first, token);
         }
 
         @Override // Binder call
         public void cancelAuthenticationFromService(final IBinder token, final String opPackageName,
                 int callingUid, int callingPid, int callingUserId) {
             Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
-            mFingerprint21.cancelAuthentication(token);
+
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for cancelAuthenticationFromService");
+                return;
+            }
+
+            provider.second.cancelAuthentication(provider.first, token);
         }
 
         @Override // Binder call
         public void remove(final IBinder token, final int fingerId, final int userId,
                 final IFingerprintServiceReceiver receiver, final String opPackageName) {
             Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
-            mFingerprint21.scheduleRemove(token, receiver, fingerId, userId, opPackageName);
+
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for remove");
+                return;
+            }
+            provider.second.scheduleRemove(provider.first, token, receiver, fingerId, userId,
+                    opPackageName);
         }
 
         @Override
@@ -274,10 +346,14 @@
 
             final long ident = Binder.clearCallingIdentity();
             try {
-                if (args.length > 0 && "--proto".equals(args[0])) {
-                    mFingerprint21.dumpProto(fd);
-                } else {
-                    mFingerprint21.dumpInternal(pw);
+                for (ServiceProvider provider : mServiceProviders) {
+                    for (FingerprintSensorProperties props : provider.getSensorProperties()) {
+                        if (args.length > 0 && "--proto".equals(args[0])) {
+                            provider.dumpProto(props.sensorId, fd);
+                        } else {
+                            provider.dumpInternal(props.sensorId, pw);
+                        }
+                    }
                 }
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -294,11 +370,12 @@
 
             final long token = Binder.clearCallingIdentity();
             try {
-                if (mFingerprint21 == null) {
-                    Slog.e(TAG, "No HAL, caller: " + opPackageName);
+                final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+                if (provider == null) {
+                    Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName);
                     return false;
                 }
-                return mFingerprint21.isHardwareDetected();
+                return provider.second.isHardwareDetected(provider.first);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -311,7 +388,13 @@
                 return;
             }
 
-            mFingerprint21.rename(fingerId, userId, name);
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for rename");
+                return;
+            }
+
+            provider.second.rename(provider.first, fingerId, userId, name);
         }
 
         @Override // Binder call
@@ -325,7 +408,8 @@
             if (userId != UserHandle.getCallingUserId()) {
                 Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
             }
-            return mFingerprint21.getEnrolledFingerprints(userId);
+
+            return FingerprintService.this.getEnrolledFingerprints(userId, opPackageName);
         }
 
         @Override // Binder call
@@ -339,19 +423,32 @@
             if (userId != UserHandle.getCallingUserId()) {
                 Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
             }
-            return mFingerprint21.getEnrolledFingerprints(userId).size() > 0;
+            return !FingerprintService.this.getEnrolledFingerprints(userId, opPackageName)
+                    .isEmpty();
         }
 
         @Override // Binder call
         public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
-            return mFingerprint21.getLockoutModeForUser(userId);
+
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for getLockoutModeForUser");
+                return LockoutTracker.LOCKOUT_NONE;
+            }
+            return provider.second.getLockoutModeForUser(provider.first, userId);
         }
 
         @Override // Binder call
         public long getAuthenticatorId(int userId) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
-            return mFingerprint21.getAuthenticatorId(userId);
+
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for getAuthenticatorId");
+                return 0;
+            }
+            return provider.second.getAuthenticatorId(provider.first, userId);
         }
 
         @Override // Binder call
@@ -359,12 +456,13 @@
                 @Nullable byte [] hardwareAuthToken, String opPackageName) {
             Utils.checkPermission(getContext(), RESET_FINGERPRINT_LOCKOUT);
 
-            if (sensorId == mFingerprint21.getFingerprintSensorProperties().sensorId) {
-                mFingerprint21.scheduleResetLockout(userId);
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for resetLockout, caller: " + opPackageName);
                 return;
             }
 
-            Slog.w(TAG, "No matching sensor for resetLockout, sensorId: " + sensorId);
+            provider.second.scheduleResetLockout(sensorId, userId, hardwareAuthToken);
         }
 
         @Override
@@ -389,35 +487,52 @@
         public void initializeConfiguration(int sensorId, int strength) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
+            final Fingerprint21 fingerprint21;
             if ((Build.IS_USERDEBUG || Build.IS_ENG)
                     && getContext().getResources().getBoolean(R.bool.allow_test_udfps)
                     && Settings.Secure.getIntForUser(getContext().getContentResolver(),
                     Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
                     UserHandle.USER_CURRENT) != 0) {
-                mFingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), sensorId,
+                fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), sensorId,
                         strength, mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
             } else {
-                mFingerprint21 = Fingerprint21.newInstance(getContext(), sensorId, strength,
+                fingerprint21 = Fingerprint21.newInstance(getContext(), sensorId, strength,
                         mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
             }
+            mServiceProviders.add(fingerprint21);
         }
 
         @Override
-        public void onFingerDown(int x, int y, float minor, float major) {
+        public void onFingerDown(int sensorId, int x, int y, float minor, float major) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
-            mFingerprint21.onFingerDown(x, y, minor, major);
+
+            final ServiceProvider provider = getProviderForSensor(sensorId);
+            if (provider == null) {
+                Slog.w(TAG, "No matching provider for onFingerDown, sensorId: " + sensorId);
+                return;
+            }
+            provider.onFingerDown(sensorId, x, y, minor, major);
         }
 
         @Override
-        public void onFingerUp() {
+        public void onFingerUp(int sensorId) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
-            mFingerprint21.onFingerUp();
+
+            final ServiceProvider provider = getProviderForSensor(sensorId);
+            if (provider == null) {
+                Slog.w(TAG, "No matching provider for onFingerUp, sensorId: " + sensorId);
+                return;
+            }
+            provider.onFingerUp(sensorId);
         }
 
         @Override
-        public void setUdfpsOverlayController(IUdfpsOverlayController controller) {
+        public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
-            mFingerprint21.setUdfpsOverlayController(controller);
+
+            for (ServiceProvider provider : mServiceProviders) {
+                provider.setUdfpsOverlayController(controller);
+            }
         }
     }
 
@@ -427,6 +542,7 @@
         mGestureAvailabilityDispatcher = new GestureAvailabilityDispatcher();
         mLockoutResetDispatcher = new LockoutResetDispatcher(context);
         mLockPatternUtils = new LockPatternUtils(context);
+        mServiceProviders = new ArrayList<>();
     }
 
     @Override
@@ -434,6 +550,61 @@
         publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
     }
 
+    @Nullable
+    private ServiceProvider getProviderForSensor(int sensorId) {
+        for (ServiceProvider provider : mServiceProviders) {
+            if (provider.containsSensor(sensorId)) {
+                return provider;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * For devices with only a single provider, returns that provider. If no providers, or multiple
+     * providers exist, returns null.
+     */
+    @Nullable
+    private Pair<Integer, ServiceProvider> getSingleProvider() {
+        final List<FingerprintSensorProperties> properties = getSensorProperties();
+        if (properties.size() != 1) {
+            return null;
+        }
+
+        // Theoretically we can just return the first provider, but maybe this is easier to
+        // understand.
+        final int sensorId = properties.get(0).sensorId;
+        for (ServiceProvider provider : mServiceProviders) {
+            if (provider.containsSensor(sensorId)) {
+                return new Pair<>(sensorId, provider);
+            }
+        }
+
+        Slog.e(TAG, "Single sensor, but provider not found");
+        return null;
+    }
+
+    @NonNull
+    private List<FingerprintSensorProperties> getSensorProperties() {
+        final List<FingerprintSensorProperties> properties = new ArrayList<>();
+
+        for (ServiceProvider provider : mServiceProviders) {
+            properties.addAll(provider.getSensorProperties());
+        }
+        return properties;
+    }
+
+    @NonNull
+    private List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
+        final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+        if (provider == null) {
+            Slog.w(TAG, "Null provider for getEnrolledFingerprints, caller: " + opPackageName);
+            return Collections.emptyList();
+        }
+
+        return provider.second.getEnrolledFingerprints(provider.first, userId);
+    }
+
     /**
      * Checks for public API invocations to ensure that permissions, etc are granted/correct.
      */
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
new file mode 100644
index 0000000..1fcc58c
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -0,0 +1,114 @@
+/*
+ * 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.server.biometrics.sensors.fingerprint;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.os.IBinder;
+import android.view.Surface;
+
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.LockoutTracker;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Superset of features/functionalities that HALs provide to the rest of the framework. This is
+ * more or less mapped to the public and private APIs that {@link FingerprintManager} provide, and
+ * is used at the system server layer to provide easy mapping between request and provider.
+ *
+ * Note that providers support both single-sensor and multi-sensor HALs. In either case,
+ * {@link FingerprintService} must ensure that providers are only requested to perform operations
+ * on sensors that they own.
+ *
+ * For methods other than {@link #containsSensor(int)}, the caller must ensure that the sensorId
+ * passed in is supported by the provider. For example,
+ * if (serviceProvider.containsSensor(sensorId)) {
+ *     serviceProvider.operation(sensorId, ...);
+ * }
+ *
+ * For operations that are supported by some providers but not others, clients are required
+ * to check (e.g. via {@link FingerprintManager#getSensorProperties()}) to ensure that the code
+ * path isn't taken. ServiceProviders will provide a no-op for unsupported operations to
+ * fail safely.
+ */
+@SuppressWarnings("deprecation")
+public interface ServiceProvider {
+    /**
+     * Checks if the specified sensor is owned by this provider.
+     */
+    boolean containsSensor(int sensorId);
+
+    @NonNull List<FingerprintSensorProperties> getSensorProperties();
+
+    void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken);
+
+    void scheduleGenerateChallenge(int sensorId, @NonNull IBinder token,
+            @NonNull IFingerprintServiceReceiver receiver, String opPackageName);
+
+    void scheduleRevokeChallenge(int sensorId, @NonNull IBinder token,
+            @NonNull String opPackageName);
+
+    void scheduleEnroll(int sensorId, @NonNull IBinder token, byte[] hardwareAuthToken, int userId,
+            @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
+            @Nullable Surface surface);
+
+    void cancelEnrollment(int sensorId, @NonNull IBinder token);
+
+    void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
+            @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
+            @Nullable Surface surface, int statsClient);
+
+    void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
+            int cookie, @NonNull ClientMonitorCallbackConverter callback,
+            @NonNull String opPackageName, boolean restricted, int statsClient, boolean isKeyguard);
+
+    void startPreparedClient(int sensorId, int cookie);
+
+    void cancelAuthentication(int sensorId, @NonNull IBinder token);
+
+    void scheduleRemove(int sensorId, @NonNull IBinder token,
+            @NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId,
+            @NonNull String opPackageName);
+
+    boolean isHardwareDetected(int sensorId);
+
+    void rename(int sensorId, int fingerId, int userId, @NonNull String name);
+
+    @NonNull List<Fingerprint> getEnrolledFingerprints(int sensorId, int userId);
+
+    @LockoutTracker.LockoutMode int getLockoutModeForUser(int sensorId, int userId);
+
+    long getAuthenticatorId(int sensorId, int userId);
+
+    void onFingerDown(int sensorId, int x, int y, float minor, float major);
+
+    void onFingerUp(int sensorId);
+
+    void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller);
+
+    void dumpProto(int sensorId, @NonNull FileDescriptor fd);
+
+    void dumpInternal(int sensorId, @NonNull PrintWriter pw);
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index c87bfec..30cbf40 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -66,6 +66,7 @@
 import com.android.server.biometrics.sensors.RemovalConsumer;
 import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
 import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
+import com.android.server.biometrics.sensors.fingerprint.ServiceProvider;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -83,14 +84,14 @@
  * Supports a single instance of the {@link android.hardware.biometrics.fingerprint.V2_1} or
  * its extended minor versions.
  */
-public class Fingerprint21 implements IHwBinder.DeathRecipient {
+public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider {
 
     private static final String TAG = "Fingerprint21";
     private static final int ENROLL_TIMEOUT_SEC = 60;
 
     final Context mContext;
     private final IActivityTaskManager mActivityTaskManager;
-    private final FingerprintSensorProperties mSensorProperties;
+    @NonNull private final FingerprintSensorProperties mSensorProperties;
     private final BiometricScheduler mScheduler;
     private final Handler mHandler;
     private final LockoutResetDispatcher mLockoutResetDispatcher;
@@ -435,9 +436,6 @@
     @Nullable IUdfpsOverlayController getUdfpsOverlayController() {
         return mUdfpsOverlayController;
     }
-    @LockoutTracker.LockoutMode public int getLockoutModeForUser(int userId) {
-        return mLockoutTracker.getLockoutModeForUser(userId);
-    }
 
     private void scheduleLoadAuthenticatorIds() {
         // Note that this can be performed on the scheduler (as opposed to being done immediately
@@ -466,7 +464,8 @@
      * correct.
      */
     private void scheduleUpdateActiveUserWithoutHandler(int targetUserId) {
-        final boolean hasEnrolled = !getEnrolledFingerprints(targetUserId).isEmpty();
+        final boolean hasEnrolled =
+                !getEnrolledFingerprints(mSensorProperties.sensorId, targetUserId).isEmpty();
         final FingerprintUpdateActiveUserClient client =
                 new FingerprintUpdateActiveUserClient(mContext, mLazyDaemon, targetUserId,
                         mContext.getOpPackageName(), mSensorProperties.sensorId, mCurrentUserId,
@@ -481,7 +480,21 @@
         });
     }
 
-    public void scheduleResetLockout(int userId) {
+    @Override
+    public boolean containsSensor(int sensorId) {
+        return mSensorProperties.sensorId == sensorId;
+    }
+
+    @Override
+    @NonNull
+    public List<FingerprintSensorProperties> getSensorProperties() {
+        final List<FingerprintSensorProperties> properties = new ArrayList<>();
+        properties.add(mSensorProperties);
+        return properties;
+    }
+
+    @Override
+    public void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken) {
         // Fingerprint2.1 keeps track of lockout in the framework. Let's just do it on the handler
         // thread.
         mHandler.post(() -> {
@@ -489,7 +502,8 @@
         });
     }
 
-    public void scheduleGenerateChallenge(@NonNull IBinder token,
+    @Override
+    public void scheduleGenerateChallenge(int sensorId, @NonNull IBinder token,
             @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName) {
         mHandler.post(() -> {
             final FingerprintGenerateChallengeClient client =
@@ -500,7 +514,9 @@
         });
     }
 
-    public void scheduleRevokeChallenge(@NonNull IBinder token, @NonNull String opPackageName) {
+    @Override
+    public void scheduleRevokeChallenge(int sensorId, @NonNull IBinder token,
+            @NonNull String opPackageName) {
         mHandler.post(() -> {
             final FingerprintRevokeChallengeClient client = new FingerprintRevokeChallengeClient(
                     mContext, mLazyDaemon, token, opPackageName, mSensorProperties.sensorId);
@@ -508,7 +524,9 @@
         });
     }
 
-    public void scheduleEnroll(@NonNull IBinder token, @NonNull byte[] hardwareAuthToken, int userId,
+    @Override
+    public void scheduleEnroll(int sensorId, @NonNull IBinder token,
+            @NonNull byte[] hardwareAuthToken, int userId,
             @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
             @Nullable Surface surface) {
         mHandler.post(() -> {
@@ -531,13 +549,15 @@
         });
     }
 
-    public void cancelEnrollment(@NonNull IBinder token) {
+    @Override
+    public void cancelEnrollment(int sensorId, @NonNull IBinder token) {
         mHandler.post(() -> {
             mScheduler.cancelEnrollment(token);
         });
     }
 
-    public void scheduleFingerDetect(@NonNull IBinder token, int userId,
+    @Override
+    public void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
             @NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName,
             @Nullable Surface surface, int statsClient) {
         mHandler.post(() -> {
@@ -552,8 +572,9 @@
         });
     }
 
-    public void scheduleAuthenticate(@NonNull IBinder token, long operationId, int userId,
-            int cookie, @NonNull ClientMonitorCallbackConverter listener,
+    @Override
+    public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
+            int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,
             @NonNull String opPackageName, boolean restricted, int statsClient,
             boolean isKeyguard) {
         mHandler.post(() -> {
@@ -569,19 +590,22 @@
         });
     }
 
-    public void startPreparedClient(int cookie) {
+    @Override
+    public void startPreparedClient(int sensorId, int cookie) {
         mHandler.post(() -> {
             mScheduler.startPreparedClient(cookie);
         });
     }
 
-    public void cancelAuthentication(@NonNull IBinder token) {
+    @Override
+    public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
         mHandler.post(() -> {
             mScheduler.cancelAuthentication(token);
         });
     }
 
-    public void scheduleRemove(@NonNull IBinder token,
+    @Override
+    public void scheduleRemove(int sensorId, @NonNull IBinder token,
             @NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId,
             @NonNull String opPackageName) {
         mHandler.post(() -> {
@@ -599,7 +623,8 @@
         mHandler.post(() -> {
             scheduleUpdateActiveUserWithoutHandler(userId);
 
-            final List<Fingerprint> enrolledList = getEnrolledFingerprints(userId);
+            final List<Fingerprint> enrolledList = getEnrolledFingerprints(
+                    mSensorProperties.sensorId, userId);
             final FingerprintInternalCleanupClient client = new FingerprintInternalCleanupClient(
                     mContext, mLazyDaemon, userId, mContext.getOpPackageName(),
                     mSensorProperties.sensorId, enrolledList, FingerprintUtils.getInstance(),
@@ -608,30 +633,37 @@
         });
     }
 
-    public boolean isHardwareDetected() {
+    @Override
+    public boolean isHardwareDetected(int sensorId) {
         final IBiometricsFingerprint daemon = getDaemon();
         return daemon != null;
     }
 
-    @NonNull public FingerprintSensorProperties getFingerprintSensorProperties() {
-        return mSensorProperties;
-    }
-
-    public void rename(int fingerId, int userId, String name) {
+    @Override
+    public void rename(int sensorId, int fingerId, int userId, @NonNull String name) {
         mHandler.post(() -> {
             FingerprintUtils.getInstance().renameBiometricForUser(mContext, userId, fingerId, name);
         });
     }
 
-    public List<Fingerprint> getEnrolledFingerprints(int userId) {
+    @Override
+    @NonNull
+    public List<Fingerprint> getEnrolledFingerprints(int sensorId, int userId) {
         return FingerprintUtils.getInstance().getBiometricsForUser(mContext, userId);
     }
 
-    public long getAuthenticatorId(int userId) {
+    @Override
+    @LockoutTracker.LockoutMode public int getLockoutModeForUser(int sensorId, int userId) {
+        return mLockoutTracker.getLockoutModeForUser(userId);
+    }
+
+    @Override
+    public long getAuthenticatorId(int sensorId, int userId) {
         return mAuthenticatorIds.get(userId);
     }
 
-    public void onFingerDown(int x, int y, float minor, float major) {
+    @Override
+    public void onFingerDown(int sensorId, int x, int y, float minor, float major) {
         final ClientMonitor<?> client = mScheduler.getCurrentClient();
         if (!(client instanceof Udfps)) {
             Slog.w(TAG, "onFingerDown received during client: " + client);
@@ -641,7 +673,8 @@
         udfps.onFingerDown(x, y, minor, major);
     }
 
-    public void onFingerUp() {
+    @Override
+    public void onFingerUp(int sensorId) {
         final ClientMonitor<?> client = mScheduler.getCurrentClient();
         if (!(client instanceof Udfps)) {
             Slog.w(TAG, "onFingerDown received during client: " + client);
@@ -651,11 +684,13 @@
         udfps.onFingerUp();
     }
 
-    public void setUdfpsOverlayController(IUdfpsOverlayController controller) {
+    @Override
+    public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) {
         mUdfpsOverlayController = controller;
     }
 
-    public void dumpProto(FileDescriptor fd) {
+    @Override
+    public void dumpProto(int sensorId, FileDescriptor fd) {
         PerformanceTracker tracker =
                 PerformanceTracker.getInstanceForSensorId(mSensorProperties.sensorId);
 
@@ -695,7 +730,8 @@
         tracker.clear();
     }
 
-    public void dumpInternal(@NonNull PrintWriter pw) {
+    @Override
+    public void dumpInternal(int sensorId, @NonNull PrintWriter pw) {
         PerformanceTracker performanceTracker =
                 PerformanceTracker.getInstanceForSensorId(mSensorProperties.sensorId);
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index 6d8f241..d68671b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -46,6 +46,7 @@
 import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Random;
 
 /**
@@ -397,8 +398,9 @@
 
             // Schedule this only after we invoke onClientFinished for the previous client, so that
             // internal preemption logic is not run.
-            mFingerprint21.scheduleAuthenticate(token, operationId, user, cookie,
-                    listener, opPackageName, restricted, statsClient, isKeyguard);
+            mFingerprint21.scheduleAuthenticate(mFingerprint21.mSensorProperties.sensorId, token,
+                    operationId, user, cookie, listener, opPackageName, restricted, statsClient,
+                    isKeyguard);
         }
     }
 
@@ -451,12 +453,14 @@
 
     @Override
     @NonNull
-    public FingerprintSensorProperties getFingerprintSensorProperties() {
-        return mSensorProperties;
+    public List<FingerprintSensorProperties> getSensorProperties() {
+        final List<FingerprintSensorProperties> properties = new ArrayList<>();
+        properties.add(mSensorProperties);
+        return properties;
     }
 
     @Override
-    public void onFingerDown(int x, int y, float minor, float major) {
+    public void onFingerDown(int sensorId, int x, int y, float minor, float major) {
         mHandler.post(() -> {
             Slog.d(TAG, "onFingerDown");
             final AuthenticationConsumer lastAuthenticatedConsumer =
@@ -503,7 +507,7 @@
     }
 
     @Override
-    public void onFingerUp() {
+    public void onFingerUp(int sensorId) {
         mHandler.post(() -> {
             Slog.d(TAG, "onFingerUp");
 
@@ -558,7 +562,7 @@
             // Things can happen before SysUI loads and sets the controller.
             if (controller != null) {
                 Slog.d(TAG, "setDebugMessage: " + message);
-                controller.setDebugMessage(message);
+                controller.setDebugMessage(mSensorProperties.sensorId, message);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "Remote exception when sending message: " + message, e);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 8087e15..0658f95 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -79,7 +79,7 @@
 
         if (authenticated) {
             resetFailedAttempts(getTargetUserId());
-            UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+            UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
             mCallback.onClientFinished(this, true /* success */);
         } else {
             final @LockoutTracker.LockoutMode int lockoutMode =
@@ -92,7 +92,7 @@
                 // Send the error, but do not invoke the FinishCallback yet. Since lockout is not
                 // controlled by the HAL, the framework must stop the sensor before finishing the
                 // client.
-                UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+                UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
                 onErrorInternal(errorCode, 0 /* vendorCode */, false /* finish */);
                 cancel();
             }
@@ -111,7 +111,7 @@
 
     @Override
     protected void startHalOperation() {
-        UdfpsHelper.showUdfpsOverlay(mUdfpsOverlayController);
+        UdfpsHelper.showUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
         try {
             // GroupId was never used. In fact, groupId is always the same as userId.
             getFreshDaemon().authenticate(mOperationId, getTargetUserId());
@@ -119,14 +119,14 @@
             Slog.e(TAG, "Remote exception when requesting auth", e);
             onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
                     0 /* vendorCode */);
-            UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+            UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
             mCallback.onClientFinished(this, false /* success */);
         }
     }
 
     @Override
     protected void stopHalOperation() {
-        UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+        UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
         try {
             getFreshDaemon().cancel();
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index 5865617..cad2214 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -61,7 +61,7 @@
 
     @Override
     protected void stopHalOperation() {
-        UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+        UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
         try {
             getFreshDaemon().cancel();
         } catch (RemoteException e) {
@@ -80,14 +80,14 @@
 
     @Override
     protected void startHalOperation() {
-        UdfpsHelper.showUdfpsOverlay(mUdfpsOverlayController);
+        UdfpsHelper.showUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
         try {
             getFreshDaemon().authenticate(0 /* operationId */, getTargetUserId());
         } catch (RemoteException e) {
             Slog.e(TAG, "Remote exception when requesting auth", e);
             onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
                     0 /* vendorCode */);
-            UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+            UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
             mCallback.onClientFinished(this, false /* success */);
         }
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index 1b9fae9..b1030bf 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -70,7 +70,7 @@
 
     @Override
     protected void startHalOperation() {
-        UdfpsHelper.showUdfpsOverlay(mUdfpsOverlayController);
+        UdfpsHelper.showUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
         try {
             // GroupId was never used. In fact, groupId is always the same as userId.
             getFreshDaemon().enroll(mHardwareAuthToken, getTargetUserId(), mTimeoutSec);
@@ -78,14 +78,14 @@
             Slog.e(TAG, "Remote exception when requesting enroll", e);
             onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
                     0 /* vendorCode */);
-            UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+            UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
             mCallback.onClientFinished(this, false /* success */);
         }
     }
 
     @Override
     protected void stopHalOperation() {
-        UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+        UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
         try {
             getFreshDaemon().cancel();
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/UdfpsHelper.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/UdfpsHelper.java
index c71ecbf..0f1d6b4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/UdfpsHelper.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/UdfpsHelper.java
@@ -62,23 +62,25 @@
         }
     }
 
-    static void showUdfpsOverlay(@Nullable IUdfpsOverlayController udfpsOverlayController) {
+    static void showUdfpsOverlay(int sensorId,
+            @Nullable IUdfpsOverlayController udfpsOverlayController) {
         if (udfpsOverlayController == null) {
             return;
         }
         try {
-            udfpsOverlayController.showUdfpsOverlay();
+            udfpsOverlayController.showUdfpsOverlay(sensorId);
         } catch (RemoteException e) {
             Slog.e(TAG, "Remote exception when showing the UDFPS overlay", e);
         }
     }
 
-    static void hideUdfpsOverlay(@Nullable IUdfpsOverlayController udfpsOverlayController) {
+    static void hideUdfpsOverlay(int sensorId,
+            @Nullable IUdfpsOverlayController udfpsOverlayController) {
         if (udfpsOverlayController == null) {
             return;
         }
         try {
-            udfpsOverlayController.hideUdfpsOverlay();
+            udfpsOverlayController.hideUdfpsOverlay(sensorId);
         } catch (RemoteException e) {
             Slog.e(TAG, "Remote exception when hiding the UDFPS overlay", e);
         }
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index 62630300..fa03e59 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -60,12 +60,12 @@
 import android.net.ipsec.ike.TunnelModeChildSessionParams;
 import android.net.ipsec.ike.exceptions.IkeException;
 import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.net.util.IpRange;
 import android.system.OsConstants;
 import android.util.Log;
 
 import com.android.internal.net.VpnProfile;
 import com.android.internal.util.HexDump;
+import com.android.net.module.util.IpRange;
 
 import java.net.Inet4Address;
 import java.net.Inet6Address;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index f2f6dbe..6e6d848 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -58,11 +58,6 @@
     // If true, turn off TV upon standby. False by default.
     private boolean mAutoTvOff;
 
-    // Local active port number used for Routing Control.
-    // Default 0 means HOME is the current active path. Temp solution only.
-    // TODO(amyjojo): adding system constants for input ports to TIF mapping.
-    private int mLocalActivePath = 0;
-
     // Determines what action should be taken upon receiving Routing Control messages.
     @VisibleForTesting
     protected HdmiProperties.playback_device_action_on_routing_control_values
@@ -438,16 +433,6 @@
         checkIfPendingActionsCleared();
     }
 
-    private void routeToPort(int portId) {
-        // TODO(AMYJOJO): route to specific input of the port
-        mLocalActivePath = portId;
-    }
-
-    @VisibleForTesting
-    protected int getLocalActivePath() {
-        return mLocalActivePath;
-    }
-
     @Override
     protected void dump(final IndentingPrintWriter pw) {
         super.dump(pw);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 7c98c6c..4a4c39d 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -233,7 +233,7 @@
     private static native void nativeToggleCapsLock(long ptr, int deviceId);
     private static native void nativeDisplayRemoved(long ptr, int displayId);
     private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
-    private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
+    private static native void nativeSetSystemUiLightsOut(long ptr, boolean lightsOut);
     private static native void nativeSetFocusedApplication(long ptr,
             int displayId, InputApplicationHandle application);
     private static native void nativeSetFocusedDisplay(long ptr, int displayId);
@@ -1560,8 +1560,8 @@
         nativeSetInputDispatchMode(mPtr, enabled, frozen);
     }
 
-    public void setSystemUiVisibility(int visibility) {
-        nativeSetSystemUiVisibility(mPtr, visibility);
+    public void setSystemUiLightsOut(boolean lightsOut) {
+        nativeSetSystemUiLightsOut(mPtr, lightsOut);
     }
 
     /**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index a44fabbe..2eccaf1 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -17,6 +17,9 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.CLIENTS;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ELAPSED_REALTIME_NANOS;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorTraceFileProto.ENTRY;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -96,12 +99,15 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
+import android.util.Log;
 import android.util.LruCache;
 import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.imetracing.ImeTracing;
+import android.util.proto.ProtoOutputStream;
 import android.view.ContextThemeWrapper;
 import android.view.DisplayInfo;
 import android.view.IWindowManager;
@@ -4032,6 +4038,55 @@
         mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE_FROM_WINDOW, windowToken).sendToTarget();
     }
 
+    /**
+     * Starting point for dumping the IME tracing information in proto format.
+     *
+     * @param clientProtoDump dump information from the IME client side
+     */
+    @BinderThread
+    @Override
+    public void startProtoDump(byte[] clientProtoDump) {
+        if (!ImeTracing.getInstance().isAvailable() || !ImeTracing.getInstance().isEnabled()) {
+            return;
+        }
+        if (clientProtoDump == null && mCurClient == null) {
+            return;
+        }
+
+        ProtoOutputStream proto = new ProtoOutputStream();
+        final long token = proto.start(ENTRY);
+        proto.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
+        // TODO: get server side dump
+        if (clientProtoDump != null) {
+            proto.write(CLIENTS, clientProtoDump);
+        } else {
+            IBinder client = null;
+
+            synchronized (mMethodMap) {
+                if (mCurClient != null && mCurClient.client != null) {
+                    client = mCurClient.client.asBinder();
+                }
+            }
+
+            if (client != null) {
+                try {
+                    proto.write(CLIENTS,
+                            TransferPipe.dumpAsync(client, ImeTracing.PROTO_ARG));
+                } catch (IOException | RemoteException e) {
+                    Log.e(TAG, "Exception while collecting client side ime dump", e);
+                }
+            }
+        }
+        proto.end(token);
+        ImeTracing.getInstance().addToBuffer(proto);
+    }
+
+    @BinderThread
+    @Override
+    public boolean isImeTraceEnabled() {
+        return ImeTracing.getInstance().isEnabled();
+    }
+
     @BinderThread
     private void notifyUserAction(@NonNull IBinder token) {
         if (DEBUG) {
@@ -5426,6 +5481,21 @@
                         return mService.handleShellCommandSetInputMethod(this);
                     case "reset":
                         return mService.handleShellCommandResetInputMethod(this);
+                    case "tracing":
+                        int result = ImeTracing.getInstance().onShellCommand(this);
+                        boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled();
+                        for (ClientState state : mService.mClients.values()) {
+                            if (state != null) {
+                                try {
+                                    state.client.setImeTraceEnabled(isImeTraceEnabled);
+                                } catch (RemoteException e) {
+                                    Log.e(TAG,
+                                            "Error while trying to enable/disable ime "
+                                                    + "trace on client window", e);
+                                }
+                            }
+                        }
+                        return result;
                     default:
                         getOutPrintWriter().println("Unknown command: " + imeCommand);
                         return ShellCommandResult.FAILURE;
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index b518eb1..a6ca25b 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1805,5 +1805,16 @@
                 mUserDataMap.dump(fd, ipw, args);
             }
         }
+
+        @BinderThread
+        @Override
+        public void startProtoDump(byte[] clientProtoDump) throws RemoteException {
+        }
+
+        @BinderThread
+        @Override
+        public boolean isImeTraceEnabled() throws RemoteException {
+            return false;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/media/MediaShellCommand.java b/services/core/java/com/android/server/media/MediaShellCommand.java
index 20df271..69c57a9 100644
--- a/services/core/java/com/android/server/media/MediaShellCommand.java
+++ b/services/core/java/com/android/server/media/MediaShellCommand.java
@@ -38,6 +38,7 @@
 
 import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.util.List;
@@ -53,11 +54,13 @@
     private ISessionManager mSessionService;
     private PrintWriter mWriter;
     private PrintWriter mErrorWriter;
+    private InputStream mInput;
 
     @Override
     public int onCommand(String cmd) {
         mWriter = getOutPrintWriter();
         mErrorWriter = getErrPrintWriter();
+        mInput = getRawInputStream();
 
         if (TextUtils.isEmpty(cmd)) {
             return handleDefaultCommands(cmd);
@@ -189,6 +192,10 @@
                 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
     }
 
+    void log(String code, String msg) {
+        mWriter.println(code + " " + msg);
+    }
+
     void showError(String errMsg) {
         onHelp();
         mErrorWriter.println(errMsg);
@@ -273,11 +280,14 @@
             cbThread.start();
 
             try {
-                InputStreamReader converter = new InputStreamReader(System.in);
+                InputStreamReader converter = new InputStreamReader(mInput);
                 BufferedReader in = new BufferedReader(converter);
                 String line;
 
-                while ((line = in.readLine()) != null) {
+                while (true) {
+                    mWriter.flush();
+                    mErrorWriter.flush();
+                    if ((line = in.readLine()) == null) break;
                     boolean addNewline = true;
                     if (line.length() <= 0) {
                         addNewline = false;
@@ -297,7 +307,7 @@
 
                     synchronized (this) {
                         if (addNewline) {
-                            System.out.println("");
+                            mWriter.println("");
                         }
                         printUsageMessage();
                     }
diff --git a/services/core/java/com/android/server/media/VolumeCtrl.java b/services/core/java/com/android/server/media/VolumeCtrl.java
index 7a26665..d516d96 100644
--- a/services/core/java/com/android/server/media/VolumeCtrl.java
+++ b/services/core/java/com/android/server/media/VolumeCtrl.java
@@ -32,6 +32,8 @@
 public class VolumeCtrl {
 
     private static final String TAG = "VolumeCtrl";
+    private static final String LOG_V = "[V]";
+    private static final String LOG_E = "[E]";
 
     // --stream affects --set, --adj or --get options.
     // --show affects --set and --adj options.
@@ -80,21 +82,22 @@
                     break;
                 case "--get":
                     doGet = true;
-                    log(LOG_V, "will get volume");
+                    cmd.log(LOG_V, "will get volume");
                     break;
                 case "--stream":
                     stream = Integer.decode(cmd.getNextArgRequired()).intValue();
-                    log(LOG_V, "will control stream=" + stream + " (" + streamName(stream) + ")");
+                    cmd.log(LOG_V,
+                            "will control stream=" + stream + " (" + streamName(stream) + ")");
                     break;
                 case "--set":
                     volIndex = Integer.decode(cmd.getNextArgRequired()).intValue();
                     mode = VOLUME_CONTROL_MODE_SET;
-                    log(LOG_V, "will set volume to index=" + volIndex);
+                    cmd.log(LOG_V, "will set volume to index=" + volIndex);
                     break;
                 case "--adj":
                     mode = VOLUME_CONTROL_MODE_ADJUST;
                     adjustment = cmd.getNextArgRequired();
-                    log(LOG_V, "will adjust volume");
+                    cmd.log(LOG_V, "will adjust volume");
                     break;
                 default:
                     throw new IllegalArgumentException("Unknown argument " + option);
@@ -122,11 +125,11 @@
 
         //----------------------------------------
         // Test initialization
-        log(LOG_V, "Connecting to AudioService");
+        cmd.log(LOG_V, "Connecting to AudioService");
         IAudioService audioService = IAudioService.Stub.asInterface(ServiceManager.checkService(
                 Context.AUDIO_SERVICE));
         if (audioService == null) {
-            System.err.println(BaseCommand.NO_SYSTEM_ERROR_CODE);
+            cmd.log(LOG_E, BaseCommand.NO_SYSTEM_ERROR_CODE);
             throw new AndroidException(
                     "Can't connect to audio service; is the system running?");
         }
@@ -152,23 +155,12 @@
             audioService.adjustStreamVolume(stream, adjDir, flag, pack);
         }
         if (doGet) {
-            log(LOG_V, "volume is " + audioService.getStreamVolume(stream)
+            cmd.log(LOG_V, "volume is " + audioService.getStreamVolume(stream)
                     + " in range [" + audioService.getStreamMinVolume(stream)
                     + ".." + audioService.getStreamMaxVolume(stream) + "]");
         }
     }
 
-    //--------------------------------------------
-    // Utilities
-
-    static final String LOG_V = "[v]";
-    static final String LOG_W = "[w]";
-    static final String LOG_OK = "[ok]";
-
-    static void log(String code, String msg) {
-        System.out.println(code + " " + msg);
-    }
-
     static String streamName(int stream) {
         try {
             return AudioSystem.STREAM_NAMES[stream];
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 60737bf..949dcb25 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2081,7 +2081,14 @@
 
         mRelinquished = true;
 
-        return mPm.new VerificationParams(user, stageDir, localObserver, params,
+        // TODO(b/169375643): Remove this workaround once b/161121612 is fixed.
+        PackageInstaller.SessionParams copiedParams = params.copy();
+        if (params.isStaged) {
+            // This is called by the pre-reboot verification. Don't enable rollback here since
+            // it has been enabled when pre-reboot verification starts.
+            copiedParams.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
+        }
+        return mPm.new VerificationParams(user, stageDir, localObserver, copiedParams,
                 mInstallSource, mInstallerUid, mSigningDetails, sessionId);
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3e7304b..4450f9a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -25949,6 +25949,15 @@
         mPermissionManager.writeStateToPackageSettingsTEMP();
         mSettings.writeLPr();
     }
+
+    @Override
+    public void holdLock(int durationMs) {
+        mContext.enforceCallingPermission(
+                Manifest.permission.INJECT_EVENTS, "holdLock requires shell identity");
+        synchronized (mLock) {
+            SystemClock.sleep(durationMs);
+        }
+    }
 }
 
 interface PackageSender {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 35b1449..df283e2 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1552,6 +1552,17 @@
         startActivityAsUser(intent, UserHandle.CURRENT);
     }
 
+    private void toggleNotificationPanel() {
+        IStatusBarService statusBarService = getStatusBarService();
+        if (statusBarService != null) {
+            try {
+                statusBarService.togglePanel();
+            } catch (RemoteException e) {
+                // do nothing.
+            }
+        }
+    }
+
     private void showPictureInPictureMenu(KeyEvent event) {
         if (DEBUG_INPUT) Log.d(TAG, "showPictureInPictureMenu event=" + event);
         mHandler.removeMessages(MSG_SHOW_PICTURE_IN_PICTURE_MENU);
@@ -1696,14 +1707,7 @@
                     launchAssistAction(null, deviceId);
                     break;
                 case LONG_PRESS_HOME_NOTIFICATION_PANEL:
-                    IStatusBarService statusBarService = getStatusBarService();
-                    if (statusBarService != null) {
-                        try {
-                            statusBarService.togglePanel();
-                        } catch (RemoteException e) {
-                            // do nothing.
-                        }
-                    }
+                    toggleNotificationPanel();
                     break;
                 default:
                     Log.w(TAG, "Undefined long press on home behavior: "
@@ -2807,6 +2811,11 @@
                 msg.sendToTarget();
             }
             return -1;
+        } else if (keyCode == KeyEvent.KEYCODE_NOTIFICATION) {
+            if (!down) {
+                toggleNotificationPanel();
+            }
+            return -1;
         }
 
         // Toggle Caps Lock on META-ALT.
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 6044ee1..60da8e5 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -5408,6 +5408,22 @@
         }
 
         @Override // Binder call
+        public boolean isAmbientDisplaySuppressedForTokenByApp(@NonNull String token, int appUid) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.READ_DREAM_STATE, null);
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.READ_DREAM_SUPPRESSION, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return isAmbientDisplayAvailable()
+                        && mAmbientDisplaySuppressionController.isSuppressed(token, appUid);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
         public boolean isAmbientDisplaySuppressed() {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.READ_DREAM_STATE, null);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6792430..42fb133 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4465,6 +4465,9 @@
             }
             detachChildren();
         }
+        if (app != null) {
+            app.invalidateOomScoreReferenceState(false /* computeNow */);
+        }
 
         switch (state) {
             case RESUMED:
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 2dc22ec..e65be41 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -499,9 +499,6 @@
     /** @return the process for the top-most resumed activity in the system. */
     public abstract WindowProcessController getTopApp();
 
-    /** Generate oom-score-adjustment rank for all tasks in the system based on z-order. */
-    public abstract void rankTaskLayersIfNeeded();
-
     /** Destroy all activities. */
     public abstract void scheduleDestroyAllActivities(String reason);
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 15669cb..bd5ab1b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -7187,16 +7187,6 @@
             }
         }
 
-        @HotPath(caller = HotPath.OOM_ADJUSTMENT)
-        @Override
-        public void rankTaskLayersIfNeeded() {
-            synchronized (mGlobalLockWithoutBoost) {
-                if (mRootWindowContainer != null) {
-                    mRootWindowContainer.rankTaskLayersIfNeeded();
-                }
-            }
-        }
-
         @Override
         public void scheduleDestroyAllActivities(String reason) {
             synchronized (mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b3e69d4..1153c46 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -193,7 +193,6 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.SurfaceSession;
-import android.view.View;
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
@@ -552,11 +551,6 @@
     private SurfaceControl mParentSurfaceControl;
     private InputWindowHandle mPortalWindowHandle;
 
-    // Last systemUiVisibility we received from status bar.
-    private int mLastStatusBarVisibility = 0;
-    // Last systemUiVisibility we dispatched to windows.
-    private int mLastDispatchedSystemUiVisibility = 0;
-
     /** Corner radius that windows should have in order to match the display. */
     private final float mWindowCornerRadius;
 
@@ -2907,10 +2901,6 @@
             pw.print("  mLastFocus="); pw.println(mLastFocus);
         }
         pw.print("  mFocusedApp="); pw.println(mFocusedApp);
-        if (mLastStatusBarVisibility != 0) {
-            pw.print("  mLastStatusBarVisibility=0x");
-            pw.println(Integer.toHexString(mLastStatusBarVisibility));
-        }
         if (mFixedRotationLaunchingApp != null) {
             pw.println("  mFixedRotationLaunchingApp=" + mFixedRotationLaunchingApp);
         }
@@ -3770,50 +3760,6 @@
         return win != null;
     }
 
-    void hideTransientBars() {
-        // TODO(b/118118435): Remove this after migration
-        final int transientFlags = View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
-        statusBarVisibilityChanged(mLastStatusBarVisibility & ~transientFlags);
-
-        getInsetsPolicy().hideTransient();
-    }
-
-    void statusBarVisibilityChanged(int visibility) {
-        mLastStatusBarVisibility = visibility;
-        updateStatusBarVisibilityLocked(visibility);
-    }
-
-    private boolean updateStatusBarVisibilityLocked(int visibility) {
-        if (mLastDispatchedSystemUiVisibility == visibility) {
-            return false;
-        }
-        final int globalDiff = (visibility ^ mLastDispatchedSystemUiVisibility)
-                // We are only interested in differences of one of the
-                // clearable flags...
-                & View.SYSTEM_UI_CLEARABLE_FLAGS
-                // ...if it has actually been cleared.
-                & ~visibility;
-
-        mLastDispatchedSystemUiVisibility = visibility;
-        if (isDefaultDisplay) {
-            mWmService.mInputManager.setSystemUiVisibility(visibility);
-        }
-        updateSystemUiVisibility(visibility, globalDiff);
-        return true;
-    }
-
-    void updateSystemUiVisibility(int visibility, int globalDiff) {
-        forAllWindows(w -> {
-            final int curValue = w.mSystemUiVisibility;
-            final int diff = (curValue ^ visibility) & globalDiff;
-            final int newValue = (curValue & ~diff) | (visibility & diff);
-            if (newValue != curValue) {
-                w.mSeq++;
-                w.mSystemUiVisibility = newValue;
-            }
-        }, true /* traverseTopToBottom */);
-    }
-
     void onWindowFreezeTimeout() {
         Slog.w(TAG_WM, "Window freeze timeout expired.");
         mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index e54da9e..dce798e 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -43,6 +43,7 @@
 import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
@@ -156,6 +157,7 @@
 import android.view.PointerIcon;
 import android.view.Surface;
 import android.view.View;
+import android.view.ViewDebug;
 import android.view.WindowInsets.Side;
 import android.view.WindowInsets.Side.InsetsSide;
 import android.view.WindowInsets.Type;
@@ -1445,9 +1447,9 @@
     boolean getLayoutHint(LayoutParams attrs, WindowToken windowToken, Rect outFrame,
             Rect outContentInsets, Rect outStableInsets,
             DisplayCutout.ParcelableWrapper outDisplayCutout) {
-        final int fl = PolicyControl.getWindowFlags(null, attrs);
+        final int fl = attrs.flags;
         final int pfl = attrs.privateFlags;
-        final int sysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
+        final int sysUiVis = attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility;
 
         final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
         final boolean layoutInScreenAndInsetDecor = layoutInScreen
@@ -2001,7 +2003,7 @@
         final WindowManager.LayoutParams attrs = win.getAttrs();
 
         final int type = attrs.type;
-        final int fl = PolicyControl.getWindowFlags(win, attrs);
+        final int fl = attrs.flags;
         final int pfl = attrs.privateFlags;
         final int sim = attrs.softInputMode;
 
@@ -2243,7 +2245,7 @@
         final boolean affectsSystemUi = win.canAffectSystemUiFlags();
         if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
         mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);
-        final int fl = PolicyControl.getWindowFlags(win, attrs);
+        final int fl = attrs.flags;
         if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
                 && attrs.type == TYPE_INPUT_METHOD) {
             mForcingShowNavBar = true;
@@ -2418,8 +2420,7 @@
             return false;
         }
         final LayoutParams attrs = mTopFullscreenOpaqueWindowState.getAttrs();
-        final int fl = PolicyControl.getWindowFlags(null, attrs);
-        final int sysui = PolicyControl.getSystemUiVisibility(null, attrs);
+        final int fl = attrs.flags;
         final InsetsSource request = mTopFullscreenOpaqueWindowState.getRequestedInsetsState()
                 .peekSource(ITYPE_STATUS_BAR);
         if (WindowManagerDebugConfig.DEBUG) {
@@ -2952,9 +2953,9 @@
 
         mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
 
-        final int fullscreenAppearance = updateLightStatusBarLw(0 /* vis */,
+        final int fullscreenAppearance = updateLightStatusBarLw(0 /* appearance */,
                 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
-        final int dockedAppearance = updateLightStatusBarLw(0 /* vis */,
+        final int dockedAppearance = updateLightStatusBarLw(0 /* appearance */,
                 mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
         final boolean inSplitScreen =
                 mService.mRoot.getDefaultTaskDisplayArea().isSplitScreenModeActivated();
@@ -3025,6 +3026,10 @@
 
             }
         });
+        if (mDisplayContent.isDefaultDisplay) {
+            mService.mInputManager.setSystemUiLightsOut(
+                    isFullscreen || (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0);
+        }
         return true;
     }
 
@@ -3037,9 +3042,7 @@
                 // If the top fullscreen-or-dimming window is also the top fullscreen, respect
                 // its light flag.
                 appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
-                final int legacyAppearance = InsetsFlags.getAppearance(
-                        PolicyControl.getSystemUiVisibility(statusColorWin, null));
-                appearance |= (statusColorWin.mAttrs.insetsFlags.appearance | legacyAppearance)
+                appearance |= statusColorWin.mAttrs.insetsFlags.appearance
                         & APPEARANCE_LIGHT_STATUS_BARS;
             } else if (statusColorWin.isDimming()) {
                 // Otherwise if it's dimming, clear the light flag.
@@ -3062,8 +3065,8 @@
         final boolean imeWindowCanNavColorWindow = imeWindow != null
                 && imeWindow.isVisibleLw()
                 && navBarPosition == NAV_BAR_BOTTOM
-                && (PolicyControl.getWindowFlags(imeWindow, null)
-                & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
+                && (imeWindow.mAttrs.flags
+                        & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
 
         if (opaque != null && opaqueOrDimming == opaque) {
             // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
@@ -3085,7 +3088,7 @@
 
         // The IME window and the dimming window are competing.  Check if the dimming window can be
         // IME target or not.
-        if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
+        if (LayoutParams.mayUseInputMethod(opaqueOrDimming.mAttrs.flags)) {
             // The IME window is above the dimming window.
             return imeWindow;
         } else {
@@ -3359,22 +3362,30 @@
         pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
         if (mLastDisableFlags != 0) {
             pw.print(prefix); pw.print("mLastDisableFlags=0x");
-            pw.print(Integer.toHexString(mLastDisableFlags));
+            pw.println(Integer.toHexString(mLastDisableFlags));
+        }
+        if (mLastAppearance != 0) {
+            pw.print(prefix); pw.print("mLastAppearance=");
+            pw.println(ViewDebug.flagsToString(InsetsFlags.class, "appearance", mLastAppearance));
+        }
+        if (mLastBehavior != 0) {
+            pw.print(prefix); pw.print("mLastBehavior=");
+            pw.println(ViewDebug.flagsToString(InsetsFlags.class, "behavior", mLastBehavior));
         }
         pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
-        pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
+        pw.print(" mDreamingLockscreen="); pw.println(mDreamingLockscreen);
         if (mStatusBar != null) {
-            pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
+            pw.print(prefix); pw.print("mStatusBar="); pw.println(mStatusBar);
         }
         if (mStatusBarAlt != null) {
-            pw.print(prefix); pw.print("mStatusBarAlt="); pw.print(mStatusBarAlt);
+            pw.print(prefix); pw.print("mStatusBarAlt="); pw.println(mStatusBarAlt);
             pw.print(prefix); pw.print("mStatusBarAltPosition=");
             pw.println(mStatusBarAltPosition);
         }
         if (mNotificationShade != null) {
-            pw.print(prefix); pw.print("mExpandedPanel="); pw.print(mNotificationShade);
+            pw.print(prefix); pw.print("mExpandedPanel="); pw.println(mNotificationShade);
         }
-        pw.print(" isKeyguardShowing="); pw.println(isKeyguardShowing());
+        pw.print(prefix); pw.print("isKeyguardShowing="); pw.println(isKeyguardShowing());
         if (mNavigationBar != null) {
             pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
             pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode);
@@ -3415,9 +3426,9 @@
         }
         pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen);
         pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
-        pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars");
-        pw.print(mDisplayContent.getInsetsPolicy().getRemoteInsetsControllerControlsSystemBars());
         pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
+        pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars=");
+        pw.println(mDisplayContent.getInsetsPolicy().getRemoteInsetsControllerControlsSystemBars());
 
         pw.print(prefix); pw.println("Looper state:");
         mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + "  ");
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index f0f3385..1d8cdf7 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -138,8 +138,9 @@
                         && dcTarget.getParentWindow() == mImeTargetFromIme
                         && dcTarget.mSubLayer > mImeTargetFromIme.getWindow().mSubLayer)
                 || mImeTargetFromIme == mDisplayContent.getImeFallback()
+                || mImeTargetFromIme == mDisplayContent.mInputMethodInputTarget
                 || controlTarget == mImeTargetFromIme
-                        && (mImeTargetFromIme.getWindow() == null 
+                        && (mImeTargetFromIme.getWindow() == null
                                 || !mImeTargetFromIme.getWindow().isClosing());
     }
 
diff --git a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
index 8b1a0c9..02dad39 100644
--- a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
@@ -28,6 +28,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.graphics.Insets;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Binder;
@@ -46,6 +47,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
 import android.view.WindowInsets.Type;
 import android.view.WindowManager;
 import android.view.animation.Animation;
@@ -134,11 +136,8 @@
             boolean userSetupComplete, boolean navBarEmpty) {
         mHandler.removeMessages(H.SHOW);
         if (isImmersiveMode) {
-            final boolean disabled = PolicyControl.disableImmersiveConfirmation(pkg);
-            if (DEBUG) Slog.d(TAG, String.format("immersiveModeChanged() disabled=%s sConfirmed=%s",
-                    disabled, sConfirmed));
-            if (!disabled
-                    && (DEBUG_SHOW_EVERY_TIME || !sConfirmed)
+            if (DEBUG) Slog.d(TAG, "immersiveModeChanged() sConfirmed=" +  sConfirmed);
+            if ((DEBUG_SHOW_EVERY_TIME || !sConfirmed)
                     && userSetupComplete
                     && !mVrModeEnabled
                     && !navBarEmpty
@@ -339,6 +338,13 @@
         public boolean onTouchEvent(MotionEvent motion) {
             return true;
         }
+
+        @Override
+        public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+            // we will be hiding the nav bar, so layout as if it's already hidden
+            return new WindowInsets.Builder(insets).setInsets(
+                    Type.systemBars(), Insets.NONE).build();
+        }
     }
 
     /**
@@ -359,10 +365,6 @@
 
         mClingWindow = new ClingWindowView(mContext, mConfirm);
 
-        // we will be hiding the nav bar, so layout as if it's already hidden
-        mClingWindow.setSystemUiVisibility(
-                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
-
         // show the confirmation
         WindowManager.LayoutParams lp = getClingWindowLayoutParams();
         getWindowManager().addView(mClingWindow, lp);
diff --git a/services/core/java/com/android/server/wm/PolicyControl.java b/services/core/java/com/android/server/wm/PolicyControl.java
deleted file mode 100644
index 61b6e0b..0000000
--- a/services/core/java/com/android/server/wm/PolicyControl.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.ArraySet;
-import android.util.Slog;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-/**
- * Runtime adjustments applied to the global window policy.
- *
- * This includes forcing immersive mode behavior for one or both system bars (based on a package
- * list) and permanently disabling immersive mode confirmations for specific packages.
- *
- * Control by setting {@link Settings.Global#POLICY_CONTROL} to one or more name-value pairs.
- * e.g.
- *   to force immersive mode everywhere:
- *     "immersive.full=*"
- *   to force transient status for all apps except a specific package:
- *     "immersive.status=apps,-com.package"
- *   to disable the immersive mode confirmations for specific packages:
- *     "immersive.preconfirms=com.package.one,com.package.two"
- *
- * Separate multiple name-value pairs with ':'
- *   e.g. "immersive.status=apps:immersive.preconfirms=*"
- */
-class PolicyControl {
-    private static final String TAG = "PolicyControl";
-    private static final boolean DEBUG = false;
-
-    @VisibleForTesting
-    static final String NAME_IMMERSIVE_FULL = "immersive.full";
-    private static final String NAME_IMMERSIVE_STATUS = "immersive.status";
-    private static final String NAME_IMMERSIVE_NAVIGATION = "immersive.navigation";
-    private static final String NAME_IMMERSIVE_PRECONFIRMATIONS = "immersive.preconfirms";
-
-    private static String sSettingValue;
-    private static Filter sImmersivePreconfirmationsFilter;
-    private static Filter sImmersiveStatusFilter;
-    private static Filter sImmersiveNavigationFilter;
-
-    static int getSystemUiVisibility(WindowState win, LayoutParams attrs) {
-        attrs = attrs != null ? attrs : win.getAttrs();
-        int vis = win != null ? win.getSystemUiVisibility()
-                : (attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility);
-        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
-            vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
-                    | View.SYSTEM_UI_FLAG_FULLSCREEN;
-            if (attrs.isFullscreen()) {
-                vis |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-            }
-            vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-                    | View.STATUS_BAR_TRANSLUCENT);
-        }
-        if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
-            vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
-                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
-            if (attrs.isFullscreen()) {
-                vis |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
-            }
-            vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-                    | View.NAVIGATION_BAR_TRANSLUCENT);
-        }
-        return vis;
-    }
-
-    static int getWindowFlags(WindowState win, LayoutParams attrs) {
-        attrs = attrs != null ? attrs : win.getAttrs();
-        int flags = attrs.flags;
-        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
-            flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
-            flags &= ~(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
-                    | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
-        }
-        if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
-            flags &= ~WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
-        }
-        return flags;
-    }
-
-    static int adjustClearableFlags(WindowState win, int clearableFlags) {
-        final LayoutParams attrs = win != null ? win.getAttrs() : null;
-        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
-            clearableFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
-        }
-        return clearableFlags;
-    }
-
-    static boolean disableImmersiveConfirmation(String pkg) {
-        return (sImmersivePreconfirmationsFilter != null
-                && sImmersivePreconfirmationsFilter.matches(pkg))
-                || ActivityManager.isRunningInTestHarness();
-    }
-
-    static boolean reloadFromSetting(Context context) {
-        if (DEBUG) Slog.d(TAG, "reloadFromSetting()");
-        String value = null;
-        try {
-            value = Settings.Global.getStringForUser(context.getContentResolver(),
-                    Settings.Global.POLICY_CONTROL,
-                    UserHandle.USER_CURRENT);
-            if (sSettingValue == value || sSettingValue != null && sSettingValue.equals(value)) {
-                return false;
-            }
-            setFilters(value);
-            sSettingValue = value;
-        } catch (Throwable t) {
-            Slog.w(TAG, "Error loading policy control, value=" + value, t);
-            return false;
-        }
-        return true;
-    }
-
-    static void dump(String prefix, PrintWriter pw) {
-        dump("sImmersiveStatusFilter", sImmersiveStatusFilter, prefix, pw);
-        dump("sImmersiveNavigationFilter", sImmersiveNavigationFilter, prefix, pw);
-        dump("sImmersivePreconfirmationsFilter", sImmersivePreconfirmationsFilter, prefix, pw);
-    }
-
-    private static void dump(String name, Filter filter, String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("PolicyControl."); pw.print(name); pw.print('=');
-        if (filter == null) {
-            pw.println("null");
-        } else {
-            filter.dump(pw); pw.println();
-        }
-    }
-
-    @VisibleForTesting
-    static void setFilters(String value) {
-        if (DEBUG) Slog.d(TAG, "setFilters: " + value);
-        sImmersiveStatusFilter = null;
-        sImmersiveNavigationFilter = null;
-        sImmersivePreconfirmationsFilter = null;
-        if (value != null) {
-            String[] nvps = value.split(":");
-            for (String nvp : nvps) {
-                int i = nvp.indexOf('=');
-                if (i == -1) continue;
-                String n = nvp.substring(0, i);
-                String v = nvp.substring(i + 1);
-                if (n.equals(NAME_IMMERSIVE_FULL)) {
-                    Filter f = Filter.parse(v);
-                    sImmersiveStatusFilter = sImmersiveNavigationFilter = f;
-                    if (sImmersivePreconfirmationsFilter == null) {
-                        sImmersivePreconfirmationsFilter = f;
-                    }
-                } else if (n.equals(NAME_IMMERSIVE_STATUS)) {
-                    Filter f = Filter.parse(v);
-                    sImmersiveStatusFilter = f;
-                } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) {
-                    Filter f = Filter.parse(v);
-                    sImmersiveNavigationFilter = f;
-                    if (sImmersivePreconfirmationsFilter == null) {
-                        sImmersivePreconfirmationsFilter = f;
-                    }
-                } else if (n.equals(NAME_IMMERSIVE_PRECONFIRMATIONS)) {
-                    Filter f = Filter.parse(v);
-                    sImmersivePreconfirmationsFilter = f;
-                }
-            }
-        }
-        if (DEBUG) {
-            Slog.d(TAG, "immersiveStatusFilter: " + sImmersiveStatusFilter);
-            Slog.d(TAG, "immersiveNavigationFilter: " + sImmersiveNavigationFilter);
-            Slog.d(TAG, "immersivePreconfirmationsFilter: " + sImmersivePreconfirmationsFilter);
-        }
-    }
-
-    private static class Filter {
-        private static final String ALL = "*";
-        private static final String APPS = "apps";
-
-        private final ArraySet<String> mAllowlist;
-        private final ArraySet<String> mDenylist;
-
-        private Filter(ArraySet<String> allowlist, ArraySet<String> denylist) {
-            mAllowlist = allowlist;
-            mDenylist = denylist;
-        }
-
-        boolean matches(LayoutParams attrs) {
-            if (attrs == null) return false;
-            boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
-                    && attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-            if (isApp && mDenylist.contains(APPS)) return false;
-            if (onDenylist(attrs.packageName)) return false;
-            if (isApp && mAllowlist.contains(APPS)) return true;
-            return onAllowlist(attrs.packageName);
-        }
-
-        boolean matches(String packageName) {
-            return !onDenylist(packageName) && onAllowlist(packageName);
-        }
-
-        private boolean onDenylist(String packageName) {
-            return mDenylist.contains(packageName) || mDenylist.contains(ALL);
-        }
-
-        private boolean onAllowlist(String packageName) {
-            return mAllowlist.contains(ALL) || mAllowlist.contains(packageName);
-        }
-
-        void dump(PrintWriter pw) {
-            pw.print("Filter[");
-            dump("allowlist", mAllowlist, pw); pw.print(',');
-            dump("denylist", mDenylist, pw); pw.print(']');
-        }
-
-        private void dump(String name, ArraySet<String> set, PrintWriter pw) {
-            pw.print(name); pw.print("=(");
-            final int n = set.size();
-            for (int i = 0; i < n; i++) {
-                if (i > 0) pw.print(',');
-                pw.print(set.valueAt(i));
-            }
-            pw.print(')');
-        }
-
-        @Override
-        public String toString() {
-            StringWriter sw = new StringWriter();
-            dump(new PrintWriter(sw, true));
-            return sw.toString();
-        }
-
-        // value = comma-delimited list of tokens, where token = (package name|apps|*)
-        // e.g. "com.package1", or "apps, com.android.keyguard" or "*"
-        static Filter parse(String value) {
-            if (value == null) return null;
-            ArraySet<String> allowlist = new ArraySet<String>();
-            ArraySet<String> denylist = new ArraySet<String>();
-            for (String token : value.split(",")) {
-                token = token.trim();
-                if (token.startsWith("-") && token.length() > 1) {
-                    token = token.substring(1);
-                    denylist.add(token);
-                } else {
-                    allowlist.add(token);
-                }
-            }
-            return new Filter(allowlist, denylist);
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 71ecf72..8b52b58 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -276,6 +276,8 @@
     // Whether tasks have moved and we need to rank the tasks before next OOM scoring
     private boolean mTaskLayersChanged = true;
     private int mTmpTaskLayerRank;
+    private final ArraySet<WindowProcessController> mTmpTaskLayerChangedProcs = new ArraySet<>();
+    private final LockedScheduler mRankTaskLayersScheduler;
 
     private boolean mTmpBoolean;
     private RemoteException mTmpRemoteException;
@@ -450,6 +452,12 @@
         mStackSupervisor = mService.mStackSupervisor;
         mStackSupervisor.mRootWindowContainer = this;
         mDisplayOffTokenAcquirer = mService.new SleepTokenAcquirerImpl("Display-off");
+        mRankTaskLayersScheduler = new LockedScheduler(mService) {
+            @Override
+            public void execute() {
+                rankTaskLayersIfNeeded();
+            }
+        };
     }
 
     boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
@@ -2698,27 +2706,39 @@
 
     void invalidateTaskLayers() {
         mTaskLayersChanged = true;
+        mRankTaskLayersScheduler.scheduleIfNeeded();
     }
 
+    /** Generate oom-score-adjustment rank for all tasks in the system based on z-order. */
     void rankTaskLayersIfNeeded() {
         if (!mTaskLayersChanged) {
             return;
         }
         mTaskLayersChanged = false;
         mTmpTaskLayerRank = 0;
-        final PooledConsumer c = PooledLambda.obtainConsumer(
-                RootWindowContainer::rankTaskLayerForActivity, this,
-                PooledLambda.__(ActivityRecord.class));
-        forAllActivities(c);
-        c.recycle();
-    }
+        // Only rank for leaf tasks because the score of activity is based on immediate parent.
+        forAllLeafTasks(task -> {
+            final int oldRank = task.mLayerRank;
+            final ActivityRecord r = task.topRunningActivityLocked();
+            if (r != null && r.mVisibleRequested) {
+                task.mLayerRank = ++mTmpTaskLayerRank;
+            } else {
+                task.mLayerRank = Task.LAYER_RANK_INVISIBLE;
+            }
+            if (task.mLayerRank != oldRank) {
+                task.forAllActivities(activity -> {
+                    if (activity.hasProcess()) {
+                        mTmpTaskLayerChangedProcs.add(activity.app);
+                    }
+                });
+            }
+        }, true /* traverseTopToBottom */);
 
-    private void rankTaskLayerForActivity(ActivityRecord r) {
-        if (r.canBeTopRunning() && r.mVisibleRequested) {
-            r.getTask().mLayerRank = ++mTmpTaskLayerRank;
-        } else {
-            r.getTask().mLayerRank = -1;
+        for (int i = mTmpTaskLayerChangedProcs.size() - 1; i >= 0; i--) {
+            mTmpTaskLayerChangedProcs.valueAt(i).invalidateOomScoreReferenceState(
+                    true /* computeNow */);
         }
+        mTmpTaskLayerChangedProcs.clear();
     }
 
     void clearOtherAppTimeTrackers(AppTimeTracker except) {
@@ -3680,4 +3700,34 @@
                     + ", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}";
         }
     }
+
+    /**
+     * Helper class to schedule the runnable if it hasn't scheduled on display thread inside window
+     * manager lock.
+     */
+    abstract static class LockedScheduler implements Runnable {
+        private final ActivityTaskManagerService mService;
+        private boolean mScheduled;
+
+        LockedScheduler(ActivityTaskManagerService service) {
+            mService = service;
+        }
+
+        @Override
+        public void run() {
+            synchronized (mService.mGlobalLock) {
+                mScheduled = false;
+                execute();
+            }
+        }
+
+        abstract void execute();
+
+        void scheduleIfNeeded() {
+            if (!mScheduled) {
+                mService.mH.post(this);
+                mScheduled = true;
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 5f2113a..9ff99f5 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -157,33 +157,33 @@
     }
 
     @Override
-    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
+    public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
             int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
             Rect outStableInsets,
             DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
             InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
-        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
+        return mService.addWindow(this, window, attrs, viewVisibility, displayId, outFrame,
                 outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
                 outInsetsState, outActiveControls, UserHandle.getUserId(mUid));
     }
 
 
     @Override
-    public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs,
+    public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
             int viewVisibility, int displayId, int userId, Rect outFrame,
             Rect outContentInsets, Rect outStableInsets,
             DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
             InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
-        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
+        return mService.addWindow(this, window, attrs, viewVisibility, displayId, outFrame,
                 outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
                 outInsetsState, outActiveControls, userId);
     }
 
     @Override
-    public int addToDisplayWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs,
+    public int addToDisplayWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs,
             int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
             InsetsState outInsetsState) {
-        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
+        return mService.addWindow(this, window, attrs, viewVisibility, displayId,
                 new Rect() /* outFrame */, outContentInsets, outStableInsets,
                 new DisplayCutout.ParcelableWrapper() /* cutout */, null /* outInputChannel */,
                 outInsetsState, mDummyControls, UserHandle.getUserId(mUid));
@@ -200,7 +200,7 @@
     }
 
     @Override
-    public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
+    public int relayout(IWindow window, WindowManager.LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
             ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState,
@@ -209,7 +209,7 @@
         if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
                 + Binder.getCallingPid());
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
-        int res = mService.relayoutWindow(this, window, seq, attrs,
+        int res = mService.relayoutWindow(this, window, attrs,
                 requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
                 outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
                 outActiveControls, outSurfaceSize, outBLASTSurfaceControl);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ce602de..9be4ace 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -464,9 +464,10 @@
     int mMinWidth;
     int mMinHeight;
 
+    static final int LAYER_RANK_INVISIBLE = -1;
     // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
     // This number will be assigned when we evaluate OOM scores for all visible tasks.
-    int mLayerRank = -1;
+    int mLayerRank = LAYER_RANK_INVISIBLE;
 
     /** Helper object used for updating override configuration. */
     private Configuration mTmpConfig = new Configuration();
@@ -1539,7 +1540,6 @@
         if (isPersistable) {
             mLastTimeMoved = System.currentTimeMillis();
         }
-        mRootWindowContainer.invalidateTaskLayers();
     }
 
     // Close up recents linked list.
@@ -7452,6 +7452,10 @@
         if (!mChildren.contains(child)) {
             return;
         }
+        if (child.asTask() != null) {
+            // Non-root task position changed.
+            mRootWindowContainer.invalidateTaskLayers();
+        }
 
         final boolean isTop = getTopChild() == child;
         if (isTop) {
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 76bd6ce..55e6a78 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -441,6 +441,12 @@
     }
 
     @Override
+    void onChildPositionChanged(WindowContainer child) {
+        super.onChildPositionChanged(child);
+        mRootWindowContainer.invalidateTaskLayers();
+    }
+
+    @Override
     boolean forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean> callback,
             boolean traverseTopToBottom) {
         return callback.apply(this);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index cccda3a..6904740 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -241,7 +241,7 @@
             mergeInsetsSources(insetsState, topFullscreenOpaqueWindow.getRequestedInsetsState());
         }
         try {
-            final int res = session.addToDisplay(window, window.mSeq, layoutParams,
+            final int res = session.addToDisplay(window, layoutParams,
                     View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrames.frame,
                     tmpFrames.contentInsets, tmpFrames.stableInsets, tmpFrames.displayCutout,
                     null /* outInputChannel */, mTmpInsetsState, mTempControls);
@@ -258,7 +258,7 @@
                 insetsState);
         window.setOuter(snapshotSurface);
         try {
-            session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
+            session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
                     tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
                     mTempControls, sTmpSurfaceSize, sTmpSurfaceControl);
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d9c574c..fa64036 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -411,7 +411,7 @@
      * @see #DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY
      */
     static boolean sDisableCustomTaskAnimationProperty =
-            SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, false);
+            SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, true);
 
     private static final String DISABLE_TRIPLE_BUFFERING_PROPERTY =
             "ro.sf.disable_triple_buffer";
@@ -864,8 +864,7 @@
         void updateSystemUiSettings() {
             boolean changed;
             synchronized (mGlobalLock) {
-                changed = ImmersiveModeConfirmation.loadSetting(mCurrentUserId, mContext)
-                        || PolicyControl.reloadFromSetting(mContext);
+                changed = ImmersiveModeConfirmation.loadSetting(mCurrentUserId, mContext);
             }
             if (changed) {
                 updateRotation(false /* alwaysSendConfiguration */, false /* forceRelayout */);
@@ -1374,9 +1373,8 @@
         return false;
     }
 
-    public int addWindow(Session session, IWindow client, int seq,
-            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
-            Rect outContentInsets, Rect outStableInsets,
+    public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
+            int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets,
             DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
             InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
             int requestUserId) {
@@ -1557,7 +1555,7 @@
             }
 
             final WindowState win = new WindowState(this, session, client, token, parentWindow,
-                    appOp[0], seq, attrs, viewVisibility, session.mUid, userId,
+                    appOp[0], attrs, viewVisibility, session.mUid, userId,
                     session.mCanAddInternalSystemWindow);
             if (win.mDeathRecipient == null) {
                 // Client has apparently died, so there is no reason to
@@ -2099,7 +2097,7 @@
                         == PackageManager.PERMISSION_GRANTED;
     }
 
-    public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
+    public int relayoutWindow(Session session, IWindow client, LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewVisibility, int flags,
             long frameNumber, ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState,
@@ -2141,17 +2139,15 @@
             if (attrs != null) {
                 displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid);
                 win.mToken.adjustWindowParams(win, attrs);
-                // if they don't have the permission, mask out the status bar bits
-                if (seq == win.mSeq) {
-                    int systemUiVisibility = attrs.systemUiVisibility
-                            | attrs.subtreeSystemUiVisibility;
-                    if ((systemUiVisibility & DISABLE_MASK) != 0) {
-                        if (!hasStatusBarPermission(pid, uid)) {
-                            systemUiVisibility &= ~DISABLE_MASK;
-                        }
+                int systemUiVisibility = attrs.systemUiVisibility
+                        | attrs.subtreeSystemUiVisibility;
+                if ((systemUiVisibility & DISABLE_MASK) != 0) {
+                    // if they don't have the permission, mask out the status bar bits
+                    if (!hasStatusBarPermission(pid, uid)) {
+                        systemUiVisibility &= ~DISABLE_MASK;
                     }
-                    win.mSystemUiVisibility = systemUiVisibility;
                 }
+                win.mSystemUiVisibility = systemUiVisibility;
                 if (win.mAttrs.type != attrs.type) {
                     throw new IllegalArgumentException(
                             "Window type can not be changed after the window is added.");
@@ -5731,31 +5727,13 @@
     }
 
     @Override
-    public void statusBarVisibilityChanged(int displayId, int visibility) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Caller does not hold permission "
-                    + android.Manifest.permission.STATUS_BAR);
-        }
-
-        synchronized (mGlobalLock) {
-            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
-            if (displayContent != null) {
-                displayContent.statusBarVisibilityChanged(visibility);
-            } else {
-                Slog.w(TAG, "statusBarVisibilityChanged with invalid displayId=" + displayId);
-            }
-        }
-    }
-
-    @Override
     public void hideTransientBars(int displayId) {
         mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.STATUS_BAR,
                 "hideTransientBars()");
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null) {
-                displayContent.hideTransientBars();
+                displayContent.getInsetsPolicy().hideTransient();
             } else {
                 Slog.w(TAG, "hideTransientBars with invalid displayId=" + displayId);
             }
@@ -6112,7 +6090,7 @@
             }
             if (inputMethodControlTarget != null) {
                 pw.print("  inputMethodControlTarget in display# "); pw.print(displayId);
-                pw.print(' '); pw.println(inputMethodControlTarget.getWindow());
+                pw.print(' '); pw.println(inputMethodControlTarget);
             }
         });
         pw.print("  mInTouchMode="); pw.println(mInTouchMode);
@@ -6164,7 +6142,6 @@
                 pw.print("  mRecentsAnimationController="); pw.println(mRecentsAnimationController);
                 mRecentsAnimationController.dump(pw, "    ");
             }
-            PolicyControl.dump("  ", pw);
         }
     }
 
@@ -8270,4 +8247,14 @@
                     embeddedWindow.getName(), grantFocus);
         }
     }
+
+    @Override
+    public void holdLock(int durationMs) {
+        mContext.enforceCallingPermission(
+                Manifest.permission.INJECT_EVENTS, "holdLock requires shell identity");
+
+        synchronized (mGlobalLock) {
+            SystemClock.sleep(durationMs);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 268281b..4b8a398 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -221,6 +221,9 @@
     @Nullable
     private BackgroundActivityStartCallback mBackgroundActivityStartCallback;
 
+    /** The state for oom-adjustment calculation. */
+    private final OomScoreReferenceState mOomRefState;
+
     public WindowProcessController(@NonNull ActivityTaskManagerService atm, ApplicationInfo info,
             String name, int uid, int userId, Object owner, WindowProcessListener listener) {
         mInfo = info;
@@ -232,6 +235,7 @@
         mAtm = atm;
         mDisplayId = INVALID_DISPLAY;
         mBackgroundActivityStartCallback = mAtm.getBackgroundActivityStartCallback();
+        mOomRefState = new OomScoreReferenceState(this);
 
         boolean isSysUiPackage = info.packageName.equals(
                 mAtm.getSysUiServiceComponentLocked().getPackageName());
@@ -688,15 +692,7 @@
 
     @HotPath(caller = HotPath.OOM_ADJUSTMENT)
     public boolean hasVisibleActivities() {
-        synchronized (mAtm.mGlobalLockWithoutBoost) {
-            for (int i = mActivities.size() - 1; i >= 0; --i) {
-                final ActivityRecord r = mActivities.get(i);
-                if (r.mVisibleRequested) {
-                    return true;
-                }
-            }
-        }
-        return false;
+        return (mOomRefState.mActivityStateFlags & OomScoreReferenceState.FLAG_IS_VISIBLE) != 0;
     }
 
     @HotPath(caller = HotPath.LRU_UPDATE)
@@ -991,6 +987,34 @@
         mHostActivities.remove(r);
     }
 
+    private static class OomScoreReferenceState extends RootWindowContainer.LockedScheduler {
+        private static final int FLAG_IS_VISIBLE = 0x10000000;
+        private static final int FLAG_IS_PAUSING = 0x20000000;
+        private static final int FLAG_IS_STOPPING = 0x40000000;
+        private static final int FLAG_IS_STOPPING_FINISHING = 0x80000000;
+        /** @see Task#mLayerRank */
+        private static final int MASK_MIN_TASK_LAYER = 0x0000ffff;
+
+        private final WindowProcessController mOwner;
+        boolean mChanged;
+
+        /**
+         * The higher 16 bits are the activity states, and the lower 16 bits are the task layer
+         * rank. This field is written by window manager and read by activity manager.
+         */
+        volatile int mActivityStateFlags = MASK_MIN_TASK_LAYER;
+
+        OomScoreReferenceState(WindowProcessController owner) {
+            super(owner.mAtm);
+            mOwner = owner;
+        }
+
+        @Override
+        public void execute() {
+            mOwner.computeOomScoreReferenceStateIfNeeded();
+        }
+    }
+
     public interface ComputeOomAdjCallback {
         void onVisibleActivity();
         void onPausedActivity();
@@ -998,64 +1022,102 @@
         void onOtherActivity();
     }
 
+    /**
+     * Returns the minimum task layer rank. It should only be called if {@link #hasActivities}
+     * returns {@code true}.
+     */
     @HotPath(caller = HotPath.OOM_ADJUSTMENT)
-    public int computeOomAdjFromActivities(int minTaskLayer, ComputeOomAdjCallback callback) {
+    public int computeOomAdjFromActivities(ComputeOomAdjCallback callback) {
+        final int flags = mOomRefState.mActivityStateFlags;
+        if ((flags & OomScoreReferenceState.FLAG_IS_VISIBLE) != 0) {
+            callback.onVisibleActivity();
+        } else if ((flags & OomScoreReferenceState.FLAG_IS_PAUSING) != 0) {
+            callback.onPausedActivity();
+        } else if ((flags & OomScoreReferenceState.FLAG_IS_STOPPING) != 0) {
+            callback.onStoppingActivity(
+                    (flags & OomScoreReferenceState.FLAG_IS_STOPPING_FINISHING) != 0);
+        } else {
+            callback.onOtherActivity();
+        }
+        return flags & OomScoreReferenceState.MASK_MIN_TASK_LAYER;
+    }
+
+    void computeOomScoreReferenceStateIfNeeded() {
+        if (!mOomRefState.mChanged) {
+            return;
+        }
+        mOomRefState.mChanged = false;
+
         // Since there could be more than one activities in a process record, we don't need to
         // compute the OomAdj with each of them, just need to find out the activity with the
         // "best" state, the order would be visible, pausing, stopping...
         Task.ActivityState best = DESTROYED;
         boolean finishing = true;
         boolean visible = false;
-        synchronized (mAtm.mGlobalLockWithoutBoost) {
-            final int activitiesSize = mActivities.size();
-            for (int j = 0; j < activitiesSize; j++) {
-                final ActivityRecord r = mActivities.get(j);
-                if (r.app != this) {
-                    Log.e(TAG, "Found activity " + r + " in proc activity list using " + r.app
-                            + " instead of expected " + this);
-                    if (r.app == null || (r.app.mUid == mUid)) {
-                        // Only fix things up when they look sane
-                        r.setProcess(this);
-                    } else {
-                        continue;
-                    }
-                }
-                if (r.mVisibleRequested) {
-                    final Task task = r.getTask();
-                    if (task != null && minTaskLayer > 0) {
-                        final int layer = task.mLayerRank;
-                        if (layer >= 0 && minTaskLayer > layer) {
-                            minTaskLayer = layer;
-                        }
-                    }
-                    visible = true;
-                    // continue the loop, in case there are multiple visible activities in
-                    // this process, we'd find out the one with the minimal layer, thus it'll
-                    // get a higher adj score.
+        int minTaskLayer = Integer.MAX_VALUE;
+        for (int i = mActivities.size() - 1; i >= 0; i--) {
+            final ActivityRecord r = mActivities.get(i);
+            if (r.app != this) {
+                Slog.e(TAG, "Found activity " + r + " in proc activity list using " + r.app
+                        + " instead of expected " + this);
+                if (r.app == null || (r.app.mUid == mUid)) {
+                    // Only fix things up when they look valid.
+                    r.setProcess(this);
                 } else {
-                    if (best != PAUSING && best != PAUSED) {
-                        if (r.isState(PAUSING, PAUSED)) {
-                            best = PAUSING;
-                        } else if (r.isState(STOPPING)) {
-                            best = STOPPING;
-                            // Not "finishing" if any of activity isn't finishing.
-                            finishing &= r.finishing;
-                        }
-                    }
+                    continue;
                 }
             }
-        }
-        if (visible) {
-            callback.onVisibleActivity();
-        } else if (best == PAUSING) {
-            callback.onPausedActivity();
-        } else if (best == STOPPING) {
-            callback.onStoppingActivity(finishing);
-        } else {
-            callback.onOtherActivity();
-        }
+            if (r.mVisibleRequested) {
+                final Task task = r.getTask();
+                if (task != null && minTaskLayer > 0) {
+                    final int layer = task.mLayerRank;
+                    if (layer >= 0 && minTaskLayer > layer) {
+                        minTaskLayer = layer;
+                    }
+                }
+                visible = true;
+                // continue the loop, in case there are multiple visible activities in
+                // this process, we'd find out the one with the minimal layer, thus it'll
+                // get a higher adj score.
+            } else if (best != PAUSING && best != PAUSED) {
+                if (r.isState(PAUSING, PAUSED)) {
+                    best = PAUSING;
+                } else if (r.isState(STOPPING)) {
+                    best = STOPPING;
+                    // Not "finishing" if any of activity isn't finishing.
+                    finishing &= r.finishing;
+                }
+            }
 
-        return minTaskLayer;
+            int stateFlags = minTaskLayer & OomScoreReferenceState.MASK_MIN_TASK_LAYER;
+            if (visible) {
+                stateFlags |= OomScoreReferenceState.FLAG_IS_VISIBLE;
+            } else if (best == PAUSING) {
+                stateFlags |= OomScoreReferenceState.FLAG_IS_PAUSING;
+            } else if (best == STOPPING) {
+                stateFlags |= OomScoreReferenceState.FLAG_IS_STOPPING;
+                if (finishing) {
+                    stateFlags |= OomScoreReferenceState.FLAG_IS_STOPPING_FINISHING;
+                }
+            }
+            mOomRefState.mActivityStateFlags = stateFlags;
+        }
+    }
+
+    void invalidateOomScoreReferenceState(boolean computeNow) {
+        mOomRefState.mChanged = true;
+        if (computeNow) {
+            computeOomScoreReferenceStateIfNeeded();
+            return;
+        }
+        mOomRefState.scheduleIfNeeded();
+    }
+
+    /** Called when the process has some oom related changes and it is going to update oom-adj. */
+    private void prepareOomAdjustment() {
+        mAtm.mRootWindowContainer.rankTaskLayersIfNeeded();
+        // The task layer may not change but the activity state in the same task may change.
+        computeOomScoreReferenceStateIfNeeded();
     }
 
     public int computeRelaunchReason() {
@@ -1097,6 +1159,9 @@
         if (addPendingTopUid) {
             mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
         }
+        if (updateOomAdj) {
+            prepareOomAdjustment();
+        }
         // Posting on handler so WM lock isn't held when we call into AM.
         final Message m = PooledLambda.obtainMessage(WindowProcessListener::updateProcessInfo,
                 mListener, updateServiceConnectionActivities, activityChange, updateOomAdj);
@@ -1158,6 +1223,7 @@
         if (topProcessState == ActivityManager.PROCESS_STATE_TOP) {
             mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
         }
+        prepareOomAdjustment();
         // Posting the message at the front of queue so WM lock isn't held when we call into AM,
         // and the process state of starting activity can be updated quicker which will give it a
         // higher scheduling group.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1f7457c..422e6f2 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -302,7 +302,6 @@
     final boolean mIsImWindow;
     final boolean mIsWallpaper;
     private final boolean mIsFloatingLayer;
-    int mSeq;
     int mViewVisibility;
     int mSystemUiVisibility;
 
@@ -834,10 +833,9 @@
     }
 
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
-            WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
-            int viewVisibility, int ownerId, int showUserId,
-            boolean ownerCanAddInternalSystemWindow) {
-        this(service, s, c, token, parentWindow, appOp, seq, a, viewVisibility, ownerId, showUserId,
+            WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
+            int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow) {
+        this(service, s, c, token, parentWindow, appOp, a, viewVisibility, ownerId, showUserId,
                 ownerCanAddInternalSystemWindow, new PowerManagerWrapper() {
                     @Override
                     public void wakeUp(long time, @WakeReason int reason, String details) {
@@ -852,9 +850,9 @@
     }
 
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
-            WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
-            int viewVisibility, int ownerId, int showUserId,
-            boolean ownerCanAddInternalSystemWindow, PowerManagerWrapper powerManagerWrapper) {
+            WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
+            int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow,
+            PowerManagerWrapper powerManagerWrapper) {
         super(service);
         mSession = s;
         mClient = c;
@@ -871,7 +869,6 @@
         mPolicy = mWmService.mPolicy;
         mContext = mWmService.mContext;
         DeathRecipient deathRecipient = new DeathRecipient();
-        mSeq = seq;
         mPowerManagerWrapper = powerManagerWrapper;
         mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
         if (DEBUG) {
@@ -4031,7 +4028,7 @@
             pw.println(prefix + "mViewVisibility=0x" + Integer.toHexString(mViewVisibility)
                     + " mHaveFrame=" + mHaveFrame
                     + " mObscured=" + mObscured);
-            pw.println(prefix + "mSeq=" + mSeq
+            pw.println(prefix
                     + " mSystemUiVisibility=0x" + Integer.toHexString(mSystemUiVisibility));
         }
         if (!isVisibleByPolicy() || !mLegacyPolicyVisibilityAfterAnim || !mAppOpVisibility
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 17a05f3..e39a3d1 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -218,7 +218,7 @@
     void setFocusedApplication(JNIEnv* env, int32_t displayId, jobject applicationHandleObj);
     void setFocusedDisplay(JNIEnv* env, int32_t displayId);
     void setInputDispatchMode(bool enabled, bool frozen);
-    void setSystemUiVisibility(int32_t visibility);
+    void setSystemUiLightsOut(bool lightsOut);
     void setPointerSpeed(int32_t speed);
     void setInputDeviceEnabled(uint32_t deviceId, bool enabled);
     void setShowTouches(bool enabled);
@@ -286,8 +286,8 @@
         // Display size information.
         std::vector<DisplayViewport> viewports;
 
-        // System UI visibility.
-        int32_t systemUiVisibility;
+        // True if System UI is less noticeable.
+        bool systemUiLightsOut;
 
         // Pointer speed.
         int32_t pointerSpeed;
@@ -339,7 +339,7 @@
 
     {
         AutoMutex _l(mLock);
-        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
+        mLocked.systemUiLightsOut = false;
         mLocked.pointerSpeed = 0;
         mLocked.pointerGesturesEnabled = true;
         mLocked.showTouches = false;
@@ -366,8 +366,8 @@
     }
     {
         AutoMutex _l(mLock);
-        dump += StringPrintf(INDENT "System UI Visibility: 0x%0" PRIx32 "\n",
-                mLocked.systemUiVisibility);
+        dump += StringPrintf(INDENT "System UI Lights Out: %s\n",
+                             toString(mLocked.systemUiLightsOut));
         dump += StringPrintf(INDENT "Pointer Speed: %" PRId32 "\n", mLocked.pointerSpeed);
         dump += StringPrintf(INDENT "Pointer Gestures Enabled: %s\n",
                 toString(mLocked.pointerGesturesEnabled));
@@ -811,11 +811,11 @@
     mInputManager->getDispatcher()->setInputDispatchMode(enabled, frozen);
 }
 
-void NativeInputManager::setSystemUiVisibility(int32_t visibility) {
+void NativeInputManager::setSystemUiLightsOut(bool lightsOut) {
     AutoMutex _l(mLock);
 
-    if (mLocked.systemUiVisibility != visibility) {
-        mLocked.systemUiVisibility = visibility;
+    if (mLocked.systemUiLightsOut != lightsOut) {
+        mLocked.systemUiLightsOut = lightsOut;
         updateInactivityTimeoutLocked();
     }
 }
@@ -826,9 +826,8 @@
         return;
     }
 
-    bool lightsOut = mLocked.systemUiVisibility & ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN;
-    controller->setInactivityTimeout(lightsOut ? InactivityTimeout::SHORT
-                                               : InactivityTimeout::NORMAL);
+    controller->setInactivityTimeout(mLocked.systemUiLightsOut ? InactivityTimeout::SHORT
+                                                               : InactivityTimeout::NORMAL);
 }
 
 void NativeInputManager::setPointerSpeed(int32_t speed) {
@@ -1578,11 +1577,11 @@
     im->setInputDispatchMode(enabled, frozen);
 }
 
-static void nativeSetSystemUiVisibility(JNIEnv* /* env */,
-        jclass /* clazz */, jlong ptr, jint visibility) {
+static void nativeSetSystemUiLightsOut(JNIEnv* /* env */, jclass /* clazz */, jlong ptr,
+                                       jboolean lightsOut) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
-    im->setSystemUiVisibility(visibility);
+    im->setSystemUiLightsOut(lightsOut);
 }
 
 static jboolean nativeTransferTouchFocus(JNIEnv* env,
@@ -1802,7 +1801,7 @@
         {"nativeSetFocusedDisplay", "(JI)V", (void*)nativeSetFocusedDisplay},
         {"nativeSetPointerCapture", "(JZ)V", (void*)nativeSetPointerCapture},
         {"nativeSetInputDispatchMode", "(JZZ)V", (void*)nativeSetInputDispatchMode},
-        {"nativeSetSystemUiVisibility", "(JI)V", (void*)nativeSetSystemUiVisibility},
+        {"nativeSetSystemUiLightsOut", "(JZ)V", (void*)nativeSetSystemUiLightsOut},
         {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)Z",
          (void*)nativeTransferTouchFocus},
         {"nativeSetPointerSpeed", "(JI)V", (void*)nativeSetPointerSpeed},
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 33317a3..8b1e9c5 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -40,7 +40,6 @@
 import com.android.server.SystemService;
 import com.android.server.people.data.DataManager;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
@@ -95,28 +94,57 @@
      * @throws SecurityException if the caller is not system or root
      */
     private static void enforceSystemOrRoot(String message) {
-        int uid = Binder.getCallingUid();
-        if (!UserHandle.isSameApp(uid, Process.SYSTEM_UID) && uid != Process.ROOT_UID) {
+        if (!isSystemOrRoot()) {
             throw new SecurityException("Only system may " + message);
         }
     }
 
+    private static boolean isSystemOrRoot() {
+        final int uid = Binder.getCallingUid();
+        return UserHandle.isSameApp(uid, Process.SYSTEM_UID) || uid == Process.ROOT_UID;
+    }
+
+
+    /**
+     * Enforces that only the system, root UID or SystemUI can make certain calls.
+     *
+     * @param message used as message if SecurityException is thrown
+     * @throws SecurityException if the caller is not system or root
+     */
+    private static void enforceSystemRootOrSystemUI(Context context, String message) {
+        if (isSystemOrRoot()) return;
+        context.enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
+                message);
+    }
+
     private final class BinderService extends IPeopleManager.Stub {
 
         @Override
         public ParceledListSlice<ConversationChannel> getRecentConversations() {
             enforceSystemOrRoot("get recent conversations");
-            return new ParceledListSlice<>(new ArrayList<>());
+            return new ParceledListSlice<>(
+                    mDataManager.getRecentConversations(
+                            Binder.getCallingUserHandle().getIdentifier()));
         }
 
         @Override
         public void removeRecentConversation(String packageName, int userId, String shortcutId) {
             enforceSystemOrRoot("remove a recent conversation");
+            mDataManager.removeRecentConversation(packageName, userId, shortcutId,
+                    Binder.getCallingUserHandle().getIdentifier());
         }
 
         @Override
         public void removeAllRecentConversations() {
             enforceSystemOrRoot("remove all recent conversations");
+            mDataManager.removeAllRecentConversations(
+                    Binder.getCallingUserHandle().getIdentifier());
+        }
+
+        @Override
+        public long getLastInteraction(String packageName, int userId, String shortcutId) {
+            enforceSystemRootOrSystemUI(getContext(), "get last interaction");
+            return mDataManager.getLastInteraction(packageName, userId, shortcutId);
         }
     }
 
diff --git a/services/people/java/com/android/server/people/data/ConversationInfo.java b/services/people/java/com/android/server/people/data/ConversationInfo.java
index 1737828..45f389c 100644
--- a/services/people/java/com/android/server/people/data/ConversationInfo.java
+++ b/services/people/java/com/android/server/people/data/ConversationInfo.java
@@ -90,6 +90,11 @@
     @Nullable
     private String mNotificationChannelId;
 
+    @Nullable
+    private String mParentNotificationChannelId;
+
+    private long mLastEventTimestamp;
+
     @ShortcutFlags
     private int mShortcutFlags;
 
@@ -102,6 +107,8 @@
         mContactUri = builder.mContactUri;
         mContactPhoneNumber = builder.mContactPhoneNumber;
         mNotificationChannelId = builder.mNotificationChannelId;
+        mParentNotificationChannelId = builder.mParentNotificationChannelId;
+        mLastEventTimestamp = builder.mLastEventTimestamp;
         mShortcutFlags = builder.mShortcutFlags;
         mConversationFlags = builder.mConversationFlags;
     }
@@ -129,14 +136,32 @@
     }
 
     /**
-     * ID of the {@link android.app.NotificationChannel} where the notifications for this
-     * conversation are posted.
+     * ID of the conversation-specific {@link android.app.NotificationChannel} where the
+     * notifications for this conversation are posted.
      */
     @Nullable
     String getNotificationChannelId() {
         return mNotificationChannelId;
     }
 
+    /**
+     * ID of the parent {@link android.app.NotificationChannel} for this conversation. This is the
+     * notification channel where the notifications are posted before this conversation is
+     * customized by the user.
+     */
+    @Nullable
+    String getParentNotificationChannelId() {
+        return mParentNotificationChannelId;
+    }
+
+    /**
+     * Timestamp of the last event, {@code 0L} if there are no events. This timestamp is for
+     * identifying and sorting the recent conversations. It may only count a subset of event types.
+     */
+    long getLastEventTimestamp() {
+        return mLastEventTimestamp;
+    }
+
     /** Whether the shortcut for this conversation is set long-lived by the app. */
     public boolean isShortcutLongLived() {
         return hasShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED);
@@ -202,6 +227,8 @@
                 && Objects.equals(mContactUri, other.mContactUri)
                 && Objects.equals(mContactPhoneNumber, other.mContactPhoneNumber)
                 && Objects.equals(mNotificationChannelId, other.mNotificationChannelId)
+                && Objects.equals(mParentNotificationChannelId, other.mParentNotificationChannelId)
+                && Objects.equals(mLastEventTimestamp, other.mLastEventTimestamp)
                 && mShortcutFlags == other.mShortcutFlags
                 && mConversationFlags == other.mConversationFlags;
     }
@@ -209,7 +236,8 @@
     @Override
     public int hashCode() {
         return Objects.hash(mShortcutId, mLocusId, mContactUri, mContactPhoneNumber,
-                mNotificationChannelId, mShortcutFlags, mConversationFlags);
+                mNotificationChannelId, mParentNotificationChannelId, mLastEventTimestamp,
+                mShortcutFlags, mConversationFlags);
     }
 
     @Override
@@ -221,6 +249,8 @@
         sb.append(", contactUri=").append(mContactUri);
         sb.append(", phoneNumber=").append(mContactPhoneNumber);
         sb.append(", notificationChannelId=").append(mNotificationChannelId);
+        sb.append(", parentNotificationChannelId=").append(mParentNotificationChannelId);
+        sb.append(", lastEventTimestamp=").append(mLastEventTimestamp);
         sb.append(", shortcutFlags=0x").append(Integer.toHexString(mShortcutFlags));
         sb.append(" [");
         if (isShortcutLongLived()) {
@@ -280,6 +310,11 @@
             protoOutputStream.write(ConversationInfoProto.NOTIFICATION_CHANNEL_ID,
                     mNotificationChannelId);
         }
+        if (mParentNotificationChannelId != null) {
+            protoOutputStream.write(ConversationInfoProto.PARENT_NOTIFICATION_CHANNEL_ID,
+                    mParentNotificationChannelId);
+        }
+        protoOutputStream.write(ConversationInfoProto.LAST_EVENT_TIMESTAMP, mLastEventTimestamp);
         protoOutputStream.write(ConversationInfoProto.SHORTCUT_FLAGS, mShortcutFlags);
         protoOutputStream.write(ConversationInfoProto.CONVERSATION_FLAGS, mConversationFlags);
         if (mContactPhoneNumber != null) {
@@ -300,6 +335,8 @@
             out.writeInt(mShortcutFlags);
             out.writeInt(mConversationFlags);
             out.writeUTF(mContactPhoneNumber != null ? mContactPhoneNumber : "");
+            out.writeUTF(mParentNotificationChannelId != null ? mParentNotificationChannelId : "");
+            out.writeLong(mLastEventTimestamp);
         } catch (IOException e) {
             Slog.e(TAG, "Failed to write fields to backup payload.", e);
             return null;
@@ -338,6 +375,14 @@
                     builder.setNotificationChannelId(protoInputStream.readString(
                             ConversationInfoProto.NOTIFICATION_CHANNEL_ID));
                     break;
+                case (int) ConversationInfoProto.PARENT_NOTIFICATION_CHANNEL_ID:
+                    builder.setParentNotificationChannelId(protoInputStream.readString(
+                            ConversationInfoProto.PARENT_NOTIFICATION_CHANNEL_ID));
+                    break;
+                case (int) ConversationInfoProto.LAST_EVENT_TIMESTAMP:
+                    builder.setLastEventTimestamp(protoInputStream.readLong(
+                            ConversationInfoProto.LAST_EVENT_TIMESTAMP));
+                    break;
                 case (int) ConversationInfoProto.SHORTCUT_FLAGS:
                     builder.setShortcutFlags(protoInputStream.readInt(
                             ConversationInfoProto.SHORTCUT_FLAGS));
@@ -382,6 +427,11 @@
             if (!TextUtils.isEmpty(contactPhoneNumber)) {
                 builder.setContactPhoneNumber(contactPhoneNumber);
             }
+            String parentNotificationChannelId = in.readUTF();
+            if (!TextUtils.isEmpty(parentNotificationChannelId)) {
+                builder.setParentNotificationChannelId(parentNotificationChannelId);
+            }
+            builder.setLastEventTimestamp(in.readLong());
         } catch (IOException e) {
             Slog.e(TAG, "Failed to read conversation info fields from backup payload.", e);
             return null;
@@ -408,6 +458,11 @@
         @Nullable
         private String mNotificationChannelId;
 
+        @Nullable
+        private String mParentNotificationChannelId;
+
+        private long mLastEventTimestamp;
+
         @ShortcutFlags
         private int mShortcutFlags;
 
@@ -427,6 +482,8 @@
             mContactUri = conversationInfo.mContactUri;
             mContactPhoneNumber = conversationInfo.mContactPhoneNumber;
             mNotificationChannelId = conversationInfo.mNotificationChannelId;
+            mParentNotificationChannelId = conversationInfo.mParentNotificationChannelId;
+            mLastEventTimestamp = conversationInfo.mLastEventTimestamp;
             mShortcutFlags = conversationInfo.mShortcutFlags;
             mConversationFlags = conversationInfo.mConversationFlags;
         }
@@ -456,6 +513,16 @@
             return this;
         }
 
+        Builder setParentNotificationChannelId(String parentNotificationChannelId) {
+            mParentNotificationChannelId = parentNotificationChannelId;
+            return this;
+        }
+
+        Builder setLastEventTimestamp(long lastEventTimestamp) {
+            mLastEventTimestamp = lastEventTimestamp;
+            return this;
+        }
+
         Builder setShortcutFlags(@ShortcutFlags int shortcutFlags) {
             mShortcutFlags = shortcutFlags;
             return this;
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 52fec33..87f2c58 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -24,6 +24,7 @@
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.Person;
+import android.app.people.ConversationChannel;
 import android.app.prediction.AppTarget;
 import android.app.prediction.AppTargetEvent;
 import android.app.usage.UsageEvents;
@@ -74,9 +75,11 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.PriorityQueue;
 import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
@@ -97,6 +100,7 @@
 
     private static final long QUERY_EVENTS_MAX_AGE_MS = 5L * DateUtils.MINUTE_IN_MILLIS;
     private static final long USAGE_STATS_QUERY_INTERVAL_SEC = 120L;
+    @VisibleForTesting static final int MAX_CACHED_RECENT_SHORTCUTS = 30;
 
     private final Context mContext;
     private final Injector mInjector;
@@ -209,6 +213,83 @@
                 mContext.getPackageName(), intentFilter, callingUserId);
     }
 
+    /** Returns the cached non-customized recent conversations. */
+    public List<ConversationChannel> getRecentConversations(@UserIdInt int callingUserId) {
+        List<ConversationChannel> conversationChannels = new ArrayList<>();
+        forPackagesInProfile(callingUserId, packageData -> {
+            String packageName = packageData.getPackageName();
+            int userId = packageData.getUserId();
+            packageData.forAllConversations(conversationInfo -> {
+                if (!isCachedRecentConversation(conversationInfo)) {
+                    return;
+                }
+                String shortcutId = conversationInfo.getShortcutId();
+                ShortcutInfo shortcutInfo = getShortcut(packageName, userId, shortcutId);
+                int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
+                NotificationChannel parentChannel =
+                        mNotificationManagerInternal.getNotificationChannel(packageName, uid,
+                                conversationInfo.getParentNotificationChannelId());
+                if (shortcutInfo == null || parentChannel == null) {
+                    return;
+                }
+                conversationChannels.add(
+                        new ConversationChannel(shortcutInfo, parentChannel,
+                                conversationInfo.getLastEventTimestamp(),
+                                hasActiveNotifications(packageName, userId, shortcutId)));
+            });
+        });
+        return conversationChannels;
+    }
+
+    /**
+     * Uncaches the shortcut that's associated with the specified conversation so this conversation
+     * will not show up in the recent conversations list.
+     */
+    public void removeRecentConversation(String packageName, int userId, String shortcutId,
+            @UserIdInt int callingUserId) {
+        if (!hasActiveNotifications(packageName, userId, shortcutId)) {
+            mShortcutServiceInternal.uncacheShortcuts(callingUserId, mContext.getPackageName(),
+                    packageName, Collections.singletonList(shortcutId), userId,
+                    ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+        }
+    }
+
+    /**
+     * Uncaches the shortcuts for all the recent conversations that they don't have active
+     * notifications.
+     */
+    public void removeAllRecentConversations(@UserIdInt int callingUserId) {
+        forPackagesInProfile(callingUserId, packageData -> {
+            String packageName = packageData.getPackageName();
+            int userId = packageData.getUserId();
+            List<String> idsToUncache = new ArrayList<>();
+            packageData.forAllConversations(conversationInfo -> {
+                String shortcutId = conversationInfo.getShortcutId();
+                if (isCachedRecentConversation(conversationInfo)
+                        && !hasActiveNotifications(packageName, userId, shortcutId)) {
+                    idsToUncache.add(shortcutId);
+                }
+            });
+            mShortcutServiceInternal.uncacheShortcuts(callingUserId, mContext.getPackageName(),
+                    packageName, idsToUncache, userId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+        });
+    }
+
+    /**
+     * Returns the last notification interaction with the specified conversation. If the
+     * conversation can't be found or no interactions have been recorded, returns 0L.
+     */
+    public long getLastInteraction(String packageName, int userId, String shortcutId) {
+        final PackageData packageData = getPackage(packageName, userId);
+        if (packageData != null) {
+            final ConversationInfo conversationInfo = packageData.getConversationInfo(shortcutId);
+            if (conversationInfo != null) {
+                return conversationInfo.getLastEventTimestamp();
+            }
+        }
+        return 0L;
+    }
+
     /** Reports the sharing related {@link AppTargetEvent} from App Prediction Manager. */
     public void reportShareTargetEvent(@NonNull AppTargetEvent event,
             @NonNull IntentFilter intentFilter) {
@@ -278,7 +359,6 @@
         }
         pruneUninstalledPackageData(userData);
 
-        final NotificationListener notificationListener = mNotificationListeners.get(userId);
         userData.forAllPackages(packageData -> {
             if (signal.isCanceled()) {
                 return;
@@ -291,20 +371,7 @@
                 packageData.getEventStore().deleteEventHistories(EventStore.CATEGORY_SMS);
             }
             packageData.pruneOrphanEvents();
-            if (notificationListener != null) {
-                String packageName = packageData.getPackageName();
-                packageData.forAllConversations(conversationInfo -> {
-                    if (conversationInfo.isShortcutCachedForNotification()
-                            && conversationInfo.getNotificationChannelId() == null
-                            && !notificationListener.hasActiveNotifications(
-                                    packageName, conversationInfo.getShortcutId())) {
-                        mShortcutServiceInternal.uncacheShortcuts(userId,
-                                mContext.getPackageName(), packageName,
-                                Collections.singletonList(conversationInfo.getShortcutId()),
-                                userId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
-                    }
-                });
-            }
+            cleanupCachedShortcuts(userId, MAX_CACHED_RECENT_SHORTCUTS);
         });
     }
 
@@ -467,7 +534,8 @@
             @NonNull String packageName, @UserIdInt int userId,
             @Nullable List<String> shortcutIds) {
         @ShortcutQuery.QueryFlags int queryFlags = ShortcutQuery.FLAG_MATCH_DYNAMIC
-                | ShortcutQuery.FLAG_MATCH_PINNED | ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
+                | ShortcutQuery.FLAG_MATCH_PINNED | ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
+                | ShortcutQuery.FLAG_MATCH_CACHED;
         return mShortcutServiceInternal.getShortcuts(
                 UserHandle.USER_SYSTEM, mContext.getPackageName(),
                 /*changedSince=*/ 0, packageName, shortcutIds, /*locusIds=*/ null,
@@ -527,6 +595,68 @@
         return packageData;
     }
 
+    private boolean isCachedRecentConversation(ConversationInfo conversationInfo) {
+        return conversationInfo.isShortcutCachedForNotification()
+                && conversationInfo.getNotificationChannelId() == null
+                && conversationInfo.getParentNotificationChannelId() != null
+                && conversationInfo.getLastEventTimestamp() > 0L;
+    }
+
+    private boolean hasActiveNotifications(String packageName, @UserIdInt int userId,
+            String shortcutId) {
+        NotificationListener notificationListener = mNotificationListeners.get(userId);
+        return notificationListener != null
+                && notificationListener.hasActiveNotifications(packageName, shortcutId);
+    }
+
+    /**
+     * Cleans up the oldest cached shortcuts that don't have active notifications for the recent
+     * conversations. After the cleanup, normally, the total number of cached shortcuts will be
+     * less than or equal to the target count. However, there are exception cases: e.g. when all
+     * the existing cached shortcuts have active notifications.
+     */
+    private void cleanupCachedShortcuts(@UserIdInt int userId, int targetCachedCount) {
+        UserData userData = getUnlockedUserData(userId);
+        if (userData == null) {
+            return;
+        }
+        // pair of <package name, conversation info>
+        List<Pair<String, ConversationInfo>> cachedConvos = new ArrayList<>();
+        userData.forAllPackages(packageData ->
+                packageData.forAllConversations(conversationInfo -> {
+                    if (isCachedRecentConversation(conversationInfo)) {
+                        cachedConvos.add(
+                                Pair.create(packageData.getPackageName(), conversationInfo));
+                    }
+                })
+        );
+        if (cachedConvos.size() <= targetCachedCount) {
+            return;
+        }
+        int numToUncache = cachedConvos.size() - targetCachedCount;
+        // Max heap keeps the oldest cached conversations.
+        PriorityQueue<Pair<String, ConversationInfo>> maxHeap = new PriorityQueue<>(
+                numToUncache + 1,
+                Comparator.comparingLong((Pair<String, ConversationInfo> pair) ->
+                        pair.second.getLastEventTimestamp()).reversed());
+        for (Pair<String, ConversationInfo> cached : cachedConvos) {
+            if (hasActiveNotifications(cached.first, userId, cached.second.getShortcutId())) {
+                continue;
+            }
+            maxHeap.offer(cached);
+            if (maxHeap.size() > numToUncache) {
+                maxHeap.poll();
+            }
+        }
+        while (!maxHeap.isEmpty()) {
+            Pair<String, ConversationInfo> toUncache = maxHeap.poll();
+            mShortcutServiceInternal.uncacheShortcuts(userId,
+                    mContext.getPackageName(), toUncache.first,
+                    Collections.singletonList(toUncache.second.getShortcutId()),
+                    userId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+        }
+    }
+
     @VisibleForTesting
     @WorkerThread
     void addOrUpdateConversationInfo(@NonNull ShortcutInfo shortcutInfo) {
@@ -737,9 +867,21 @@
         public void onShortcutsAddedOrUpdated(@NonNull String packageName,
                 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
             mInjector.getBackgroundExecutor().execute(() -> {
+                PackageData packageData = getPackage(packageName, user.getIdentifier());
                 for (ShortcutInfo shortcut : shortcuts) {
                     if (ShortcutHelper.isConversationShortcut(
                             shortcut, mShortcutServiceInternal, user.getIdentifier())) {
+                        if (shortcut.isCached()) {
+                            ConversationInfo conversationInfo = packageData != null
+                                    ? packageData.getConversationInfo(shortcut.getId()) : null;
+                            if (conversationInfo == null
+                                    || !conversationInfo.isShortcutCachedForNotification()) {
+                                // This is a newly cached shortcut. Clean up the existing cached
+                                // shortcuts to ensure the cache size is under the limit.
+                                cleanupCachedShortcuts(user.getIdentifier(),
+                                        MAX_CACHED_RECENT_SHORTCUTS - 1);
+                            }
+                        }
                         addOrUpdateConversationInfo(shortcut);
                     }
                 }
@@ -800,6 +942,16 @@
             });
 
             if (packageData != null) {
+                ConversationInfo conversationInfo = packageData.getConversationInfo(shortcutId);
+                if (conversationInfo == null) {
+                    return;
+                }
+                ConversationInfo updated = new ConversationInfo.Builder(conversationInfo)
+                        .setLastEventTimestamp(sbn.getPostTime())
+                        .setParentNotificationChannelId(sbn.getNotification().getChannelId())
+                        .build();
+                packageData.getConversationStore().addOrUpdate(updated);
+
                 EventHistoryImpl eventHistory = packageData.getEventStore().getOrCreateEventHistory(
                         EventStore.CATEGORY_SHORTCUT_BASED, shortcutId);
                 eventHistory.addEvent(new Event(sbn.getPostTime(), Event.TYPE_NOTIFICATION_POSTED));
@@ -820,16 +972,7 @@
                     int count = mActiveNotifCounts.getOrDefault(conversationKey, 0) - 1;
                     if (count <= 0) {
                         mActiveNotifCounts.remove(conversationKey);
-                        // The shortcut was cached by Notification Manager synchronously when the
-                        // associated notification was posted. Uncache it here when all the
-                        // associated notifications are removed.
-                        if (conversationInfo.isShortcutCachedForNotification()
-                                && conversationInfo.getNotificationChannelId() == null) {
-                            mShortcutServiceInternal.uncacheShortcuts(mUserId,
-                                    mContext.getPackageName(), sbn.getPackageName(),
-                                    Collections.singletonList(conversationInfo.getShortcutId()),
-                                    mUserId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
-                        }
+                        cleanupCachedShortcuts(mUserId, MAX_CACHED_RECENT_SHORTCUTS);
                     } else {
                         mActiveNotifCounts.put(conversationKey, count);
                     }
@@ -885,24 +1028,6 @@
             conversationStore.addOrUpdate(builder.build());
         }
 
-        synchronized void cleanupCachedShortcuts() {
-            for (Pair<String, String> conversationKey : mActiveNotifCounts.keySet()) {
-                String packageName = conversationKey.first;
-                String shortcutId = conversationKey.second;
-                PackageData packageData = getPackage(packageName, mUserId);
-                ConversationInfo conversationInfo =
-                        packageData != null ? packageData.getConversationInfo(shortcutId) : null;
-                if (conversationInfo != null
-                        && conversationInfo.isShortcutCachedForNotification()
-                        && conversationInfo.getNotificationChannelId() == null) {
-                    mShortcutServiceInternal.uncacheShortcuts(mUserId,
-                            mContext.getPackageName(), packageName,
-                            Collections.singletonList(shortcutId),
-                            mUserId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
-                }
-            }
-        }
-
         synchronized boolean hasActiveNotifications(String packageName, String shortcutId) {
             return mActiveNotifCounts.containsKey(Pair.create(packageName, shortcutId));
         }
@@ -975,16 +1100,7 @@
 
         @Override
         public void onReceive(Context context, Intent intent) {
-            forAllUnlockedUsers(userData -> {
-                NotificationListener listener = mNotificationListeners.get(userData.getUserId());
-                // Clean up the cached shortcuts because all the notifications are cleared after
-                // system shutdown. The associated shortcuts need to be uncached to keep in sync
-                // unless the settings are changed by the user.
-                if (listener != null) {
-                    listener.cleanupCachedShortcuts();
-                }
-                userData.forAllPackages(PackageData::saveToDisk);
-            });
+            forAllUnlockedUsers(userData -> userData.forAllPackages(PackageData::saveToDisk));
         }
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 5d8f662..a250c21 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -351,7 +351,7 @@
         doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController();
         WindowProcessController wpc = app.getWindowProcessController();
         doReturn(true).when(wpc).hasActivities();
-        doAnswer(answer((minTaskLayer, callback) -> {
+        doAnswer(answer(callback -> {
             Field field = callback.getClass().getDeclaredField("adj");
             field.set(callback, VISIBLE_APP_ADJ);
             field = callback.getClass().getDeclaredField("foregroundActivities");
@@ -361,7 +361,7 @@
             field = callback.getClass().getDeclaredField("schedGroup");
             field.set(callback, SCHED_GROUP_TOP_APP);
             return 0;
-        })).when(wpc).computeOomAdjFromActivities(anyInt(),
+        })).when(wpc).computeOomAdjFromActivities(
                 any(WindowProcessController.ComputeOomAdjCallback.class));
         sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
         sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 90e1cfc..79936ce 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -77,6 +77,7 @@
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
     <uses-permission android:name="android.permission.DUMP"/>
     <uses-permission android:name="android.permission.READ_DREAM_STATE"/>
+    <uses-permission android:name="android.permission.READ_DREAM_SUPPRESSION"/>
     <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
     <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
index 08f558e..1385376 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -54,8 +54,6 @@
 
     private Context mContextSpy;
     private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
-    private HdmiCecController mHdmiCecController;
-    private HdmiControlService mHdmiControlService;
     private FakeNativeWrapper mNativeWrapper;
     private ArcInitiationActionFromAvr mAction;
 
@@ -78,7 +76,7 @@
         when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        mHdmiControlService =
+        HdmiControlService hdmiControlService =
                 new HdmiControlService(mContextSpy) {
                     @Override
                     boolean isPowerStandby() {
@@ -110,7 +108,7 @@
                     }
                 };
 
-        mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService) {
+        mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
             @Override
             protected void setPreferredAddress(int addr) {
             }
@@ -118,18 +116,18 @@
 
         mHdmiCecLocalDeviceAudioSystem.init();
         Looper looper = mTestLooper.getLooper();
-        mHdmiControlService.setIoLooper(looper);
+        hdmiControlService.setIoLooper(looper);
         mNativeWrapper = new FakeNativeWrapper();
-        mHdmiCecController = HdmiCecController.createWithNativeWrapper(
-                this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
-        mHdmiControlService.setCecController(mHdmiCecController);
-        mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
-        mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
-        mHdmiControlService.initPortInfo();
+        HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
+                hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter());
+        hdmiControlService.setCecController(hdmiCecController);
+        hdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(hdmiControlService));
+        hdmiControlService.setMessageValidator(new HdmiCecMessageValidator(hdmiControlService));
+        hdmiControlService.initPortInfo();
         mAction = new ArcInitiationActionFromAvr(mHdmiCecLocalDeviceAudioSystem);
 
         mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
-        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        hdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mTestLooper.dispatchAll();
     }
 
@@ -142,7 +140,7 @@
 
         assertThat(mNativeWrapper.getResultMessages()).contains(initiateArc);
 
-        mHdmiControlService.sendCecCommand(
+        mNativeWrapper.onCecMessage(
                 HdmiCecMessageBuilder.buildReportArcInitiated(
                         Constants.ADDR_TV,
                         Constants.ADDR_AUDIO_SYSTEM));
@@ -174,7 +172,7 @@
 
         assertThat(mNativeWrapper.getResultMessages()).contains(initiateArc);
 
-        mHdmiControlService.handleCecCommand(HdmiCecMessageBuilder.buildReportArcTerminated(
+        mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildReportArcTerminated(
                 Constants.ADDR_TV,
                 Constants.ADDR_AUDIO_SYSTEM));
         mTestLooper.dispatchAll();
@@ -192,7 +190,7 @@
 
         assertThat(mNativeWrapper.getResultMessages()).contains(initiateArc);
 
-        mHdmiControlService.handleCecCommand(
+        mNativeWrapper.onCecMessage(
                 HdmiCecMessageBuilder.buildFeatureAbortCommand(
                         Constants.ADDR_TV,
                         Constants.ADDR_AUDIO_SYSTEM, Constants.MESSAGE_INITIATE_ARC,
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
index 4afbbf7..169f885 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
@@ -56,8 +56,6 @@
     private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
     private ArcTerminationActionFromAvr mAction;
 
-    private HdmiCecController mHdmiCecController;
-    private HdmiControlService mHdmiControlService;
     private FakeNativeWrapper mNativeWrapper;
 
     private TestLooper mTestLooper = new TestLooper();
@@ -79,7 +77,7 @@
         when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        mHdmiControlService =
+        HdmiControlService hdmiControlService =
                 new HdmiControlService(mContextSpy) {
                     @Override
                     void wakeUp() {
@@ -112,16 +110,16 @@
                 };
 
         Looper looper = mTestLooper.getLooper();
-        mHdmiControlService.setIoLooper(looper);
+        hdmiControlService.setIoLooper(looper);
         mNativeWrapper = new FakeNativeWrapper();
-        mHdmiCecController = HdmiCecController.createWithNativeWrapper(
-                this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
-        mHdmiControlService.setCecController(mHdmiCecController);
-        mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
-        mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
-        mHdmiControlService.initPortInfo();
+        HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
+                hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter());
+        hdmiControlService.setCecController(hdmiCecController);
+        hdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(hdmiControlService));
+        hdmiControlService.setMessageValidator(new HdmiCecMessageValidator(hdmiControlService));
+        hdmiControlService.initPortInfo();
 
-        mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService) {
+        mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
             @Override
             protected void setPreferredAddress(int addr) {
             }
@@ -130,7 +128,7 @@
         mAction = new ArcTerminationActionFromAvr(mHdmiCecLocalDeviceAudioSystem);
 
         mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
-        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        hdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mHdmiCecLocalDeviceAudioSystem.setArcStatus(true);
         mTestLooper.dispatchAll();
     }
@@ -173,7 +171,7 @@
         HdmiCecMessage arcTerminatedResponse = HdmiCecMessageBuilder.buildReportArcTerminated(
                 Constants.ADDR_TV, Constants.ADDR_AUDIO_SYSTEM);
 
-        mHdmiControlService.handleCecCommand(arcTerminatedResponse);
+        mNativeWrapper.onCecMessage(arcTerminatedResponse);
         mTestLooper.dispatchAll();
 
         assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
index 01f0a3d..2c42791 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
@@ -16,7 +16,11 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.tv.cec.V1_0.CecMessage;
+import android.hardware.tv.cec.V1_0.HotplugEvent;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
+import android.os.RemoteException;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.hdmi.HdmiCecController.NativeWrapper;
@@ -29,6 +33,8 @@
 
 /** Fake {@link NativeWrapper} useful for testing. */
 final class FakeNativeWrapper implements NativeWrapper {
+    private static final String TAG = "FakeNativeWrapper";
+
     private final int[] mPollAddressResponse =
             new int[] {
                 SendMessageResult.NACK,
@@ -52,6 +58,7 @@
     private final HashMap<Integer, Integer> mMessageSendResult = new HashMap<>();
     private int mMyPhysicalAddress = 0;
     private HdmiPortInfo[] mHdmiPortInfo = null;
+    private HdmiCecController.HdmiCecCallback mCallback = null;
 
     @Override
     public String nativeInit() {
@@ -59,7 +66,9 @@
     }
 
     @Override
-    public void setCallback(HdmiCecController.HdmiCecCallback callback) {}
+    public void setCallback(HdmiCecController.HdmiCecCallback callback) {
+        this.mCallback = callback;
+    }
 
     @Override
     public int nativeSendCecCommand(
@@ -119,6 +128,42 @@
         return false;
     }
 
+    public void onCecMessage(HdmiCecMessage hdmiCecMessage) {
+        if (mCallback == null) {
+            return;
+        }
+        CecMessage message = new CecMessage();
+        message.initiator = hdmiCecMessage.getSource();
+        message.destination = hdmiCecMessage.getDestination();
+        ArrayList<Byte> body = new ArrayList<>();
+        body.add((byte) hdmiCecMessage.getOpcode());
+        for (byte param : hdmiCecMessage.getParams()) {
+            body.add(param);
+        }
+        message.body = body;
+        try {
+            mCallback.onCecMessage(message);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending CEC message", e);
+        }
+    }
+
+    public void onHotplugEvent(int port, boolean connected) {
+        if (mCallback == null) {
+            return;
+        }
+
+        HotplugEvent hotplugEvent = new HotplugEvent();
+        hotplugEvent.portId = port;
+        hotplugEvent.connected = connected;
+
+        try {
+            mCallback.onHotplugEvent(hotplugEvent);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending hotplug event", e);
+        }
+    }
+
     public List<HdmiCecMessage> getResultMessages() {
         return new ArrayList<>(mResultMessages);
     }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
index c60d5fb..6e7ec2a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
@@ -70,7 +70,6 @@
         }
     }
 
-    private HdmiControlService mHdmiControlService;
     private HdmiCecController mHdmiCecController;
     private int mLogicalAddress = 16;
     private AllocateAddressCallback mCallback =
@@ -87,10 +86,11 @@
     public void SetUp() {
         mMyLooper = mTestLooper.getLooper();
         mMyLooper = mTestLooper.getLooper();
-        mHdmiControlService = new MyHdmiControlService(InstrumentationRegistry.getTargetContext());
+        HdmiControlService hdmiControlService = new MyHdmiControlService(
+                InstrumentationRegistry.getTargetContext());
         mNativeWrapper = new FakeNativeWrapper();
         mHdmiCecController = HdmiCecController.createWithNativeWrapper(
-                mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
+                hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter());
     }
 
     /** Tests for {@link HdmiCecController#allocateLogicalAddress} */
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index d160a3f..498ebf4 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -39,7 +39,6 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -370,16 +369,11 @@
         assertThat(mStandby).isFalse();
     }
 
-    // Playback device does not handle routing control related feature right now
-    @Ignore("b/120845532")
     @Test
-    public void handleSetStreamPath_underCurrentDevice() {
-        assertThat(mHdmiCecLocalDevicePlayback.getLocalActivePath()).isEqualTo(0);
+    public void handleSetStreamPath() {
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x2100);
         assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message)).isTrue();
-        // TODO(amyjojo): Move set and get LocalActivePath to Control Service.
-        assertThat(mHdmiCecLocalDevicePlayback.getLocalActivePath()).isEqualTo(1);
     }
 
     @Test
@@ -786,8 +780,8 @@
 
     @Test
     public void handleSetStreamPath_afterHotplug_broadcastsActiveSource() {
-        mHdmiControlService.onHotplug(1, false);
-        mHdmiControlService.onHotplug(1, true);
+        mNativeWrapper.onHotplugEvent(1, false);
+        mNativeWrapper.onHotplugEvent(1, true);
 
         HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV,
                 mPlaybackPhysicalAddress);
@@ -803,8 +797,8 @@
 
     @Test
     public void handleSetStreamPath_afterHotplug_hasCorrectActiveSource() {
-        mHdmiControlService.onHotplug(1, false);
-        mHdmiControlService.onHotplug(1, true);
+        mNativeWrapper.onHotplugEvent(1, false);
+        mNativeWrapper.onHotplugEvent(1, true);
 
         HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV,
                 mPlaybackPhysicalAddress);
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
index c5d9487..c6823eb 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
@@ -37,6 +37,7 @@
     private static final Uri CONTACT_URI = Uri.parse("tel:+1234567890");
     private static final String PHONE_NUMBER = "+1234567890";
     private static final String NOTIFICATION_CHANNEL_ID = "test : abc";
+    private static final String PARENT_NOTIFICATION_CHANNEL_ID = "test";
 
     @Test
     public void testBuild() {
@@ -46,6 +47,8 @@
                 .setContactUri(CONTACT_URI)
                 .setContactPhoneNumber(PHONE_NUMBER)
                 .setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
+                .setParentNotificationChannelId(PARENT_NOTIFICATION_CHANNEL_ID)
+                .setLastEventTimestamp(100L)
                 .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED
                         | ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)
                 .setImportant(true)
@@ -62,6 +65,9 @@
         assertEquals(CONTACT_URI, conversationInfo.getContactUri());
         assertEquals(PHONE_NUMBER, conversationInfo.getContactPhoneNumber());
         assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId());
+        assertEquals(PARENT_NOTIFICATION_CHANNEL_ID,
+                conversationInfo.getParentNotificationChannelId());
+        assertEquals(100L, conversationInfo.getLastEventTimestamp());
         assertTrue(conversationInfo.isShortcutLongLived());
         assertTrue(conversationInfo.isShortcutCachedForNotification());
         assertTrue(conversationInfo.isImportant());
@@ -84,6 +90,8 @@
         assertNull(conversationInfo.getContactUri());
         assertNull(conversationInfo.getContactPhoneNumber());
         assertNull(conversationInfo.getNotificationChannelId());
+        assertNull(conversationInfo.getParentNotificationChannelId());
+        assertEquals(0L, conversationInfo.getLastEventTimestamp());
         assertFalse(conversationInfo.isShortcutLongLived());
         assertFalse(conversationInfo.isShortcutCachedForNotification());
         assertFalse(conversationInfo.isImportant());
@@ -103,6 +111,8 @@
                 .setContactUri(CONTACT_URI)
                 .setContactPhoneNumber(PHONE_NUMBER)
                 .setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
+                .setParentNotificationChannelId(PARENT_NOTIFICATION_CHANNEL_ID)
+                .setLastEventTimestamp(100L)
                 .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED)
                 .setImportant(true)
                 .setNotificationSilenced(true)
@@ -122,6 +132,8 @@
         assertEquals(CONTACT_URI, destination.getContactUri());
         assertEquals(PHONE_NUMBER, destination.getContactPhoneNumber());
         assertEquals(NOTIFICATION_CHANNEL_ID, destination.getNotificationChannelId());
+        assertEquals(PARENT_NOTIFICATION_CHANNEL_ID, destination.getParentNotificationChannelId());
+        assertEquals(100L, destination.getLastEventTimestamp());
         assertTrue(destination.isShortcutLongLived());
         assertFalse(destination.isImportant());
         assertTrue(destination.isNotificationSilenced());
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 0a6cd51..f37054d 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -29,6 +29,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doAnswer;
@@ -45,6 +46,7 @@
 import android.app.NotificationManager;
 import android.app.Person;
 import android.app.job.JobScheduler;
+import android.app.people.ConversationChannel;
 import android.app.prediction.AppTarget;
 import android.app.prediction.AppTargetEvent;
 import android.app.prediction.AppTargetId;
@@ -112,6 +114,7 @@
     private static final String CONTACT_URI = "content://com.android.contacts/contacts/lookup/123";
     private static final String PHONE_NUMBER = "+1234567890";
     private static final String NOTIFICATION_CHANNEL_ID = "test : sc";
+    private static final String PARENT_NOTIFICATION_CHANNEL_ID = "test";
     private static final long MILLIS_PER_MINUTE = 1000L * 60L;
 
     @Mock private Context mContext;
@@ -133,10 +136,12 @@
 
     private ScheduledExecutorService mExecutorService;
     private NotificationChannel mNotificationChannel;
+    private NotificationChannel mParentNotificationChannel;
     private DataManager mDataManager;
     private CancellationSignal mCancellationSignal;
     private ShortcutChangeCallback mShortcutChangeCallback;
     private BroadcastReceiver mShutdownBroadcastReceiver;
+    private ShortcutInfo mShortcutInfo;
     private TestInjector mInjector;
 
     @Before
@@ -157,6 +162,11 @@
         }).when(mPackageManagerInternal).forEachInstalledPackage(any(Consumer.class), anyInt());
 
         addLocalServiceMock(NotificationManagerInternal.class, mNotificationManagerInternal);
+        mParentNotificationChannel = new NotificationChannel(
+                PARENT_NOTIFICATION_CHANNEL_ID, "test channel",
+                NotificationManager.IMPORTANCE_DEFAULT);
+        when(mNotificationManagerInternal.getNotificationChannel(anyString(), anyInt(),
+                anyString())).thenReturn(mParentNotificationChannel);
 
         when(mContext.getContentResolver()).thenReturn(mContentResolver);
         when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
@@ -199,6 +209,7 @@
         when(mStatusBarNotification.getUser()).thenReturn(UserHandle.of(USER_ID_PRIMARY));
         when(mStatusBarNotification.getPostTime()).thenReturn(System.currentTimeMillis());
         when(mNotification.getShortcutId()).thenReturn(TEST_SHORTCUT_ID);
+        when(mNotification.getChannelId()).thenReturn(PARENT_NOTIFICATION_CHANNEL_ID);
 
         mNotificationChannel = new NotificationChannel(
                 NOTIFICATION_CHANNEL_ID, "test channel", NotificationManager.IMPORTANCE_DEFAULT);
@@ -212,6 +223,13 @@
 
         when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
                 anyString(), anyInt(), any())).thenReturn(true);
+
+        mShortcutInfo = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+                buildPerson());
+        when(mShortcutServiceInternal.getShortcuts(
+                anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
+                anyInt(), anyInt(), anyInt(), anyInt()))
+                .thenReturn(Collections.singletonList(mShortcutInfo));
         verify(mShortcutServiceInternal).addShortcutChangeCallback(
                 mShortcutChangeCallbackCaptor.capture());
         mShortcutChangeCallback = mShortcutChangeCallbackCaptor.getValue();
@@ -417,29 +435,28 @@
         List<Range<Long>> activeNotificationOpenTimeSlots = getActiveSlotsForTestShortcut(
                 Event.NOTIFICATION_EVENT_TYPES);
         assertEquals(1, activeNotificationOpenTimeSlots.size());
-        verify(mShortcutServiceInternal).uncacheShortcuts(
-                anyInt(), any(), eq(TEST_PKG_NAME),
-                eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
-                eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
     }
 
     @Test
-    public void testNotificationDismissed() {
+    public void testUncacheShortcutsWhenNotificationsDismissed() {
         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
-
-        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
-                buildPerson());
-        mDataManager.addOrUpdateConversationInfo(shortcut);
-
         NotificationListenerService listenerService =
                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
 
-        // Post one notification.
-        shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
-        mDataManager.addOrUpdateConversationInfo(shortcut);
-        listenerService.onNotificationPosted(mStatusBarNotification);
+        // The cached conversations are above the limit because every conversation has active
+        // notifications. To uncache one of them, the notifications for that conversation need to
+        // be dismissed.
+        for (int i = 0; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
+            String shortcutId = TEST_SHORTCUT_ID + i;
+            ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
+                    buildPerson());
+            shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+            mDataManager.addOrUpdateConversationInfo(shortcut);
+            when(mNotification.getShortcutId()).thenReturn(shortcutId);
+            listenerService.onNotificationPosted(mStatusBarNotification);
+        }
 
-        // Post another notification.
+        // Post another notification for the last conversation.
         listenerService.onNotificationPosted(mStatusBarNotification);
 
         // Removing one of the two notifications does not un-cache the shortcut.
@@ -452,13 +469,12 @@
         listenerService.onNotificationRemoved(mStatusBarNotification, null,
                 NotificationListenerService.REASON_CANCEL_ALL);
         verify(mShortcutServiceInternal).uncacheShortcuts(
-                anyInt(), any(), eq(TEST_PKG_NAME),
-                eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
+                anyInt(), any(), eq(TEST_PKG_NAME), anyList(), eq(USER_ID_PRIMARY),
                 eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
     }
 
     @Test
-    public void testShortcutNotUncachedIfNotificationChannelCreated() {
+    public void testConversationIsNotRecentIfCustomized() {
         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
 
         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
@@ -472,15 +488,12 @@
         shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
         mDataManager.addOrUpdateConversationInfo(shortcut);
 
+        assertEquals(1, mDataManager.getRecentConversations(USER_ID_PRIMARY).size());
+
         listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
                 mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
 
-        listenerService.onNotificationRemoved(mStatusBarNotification, null,
-                NotificationListenerService.REASON_CANCEL_ALL);
-        verify(mShortcutServiceInternal, never()).uncacheShortcuts(
-                anyInt(), any(), eq(TEST_PKG_NAME),
-                eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
-                eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+        assertTrue(mDataManager.getRecentConversations(USER_ID_PRIMARY).isEmpty());
     }
 
     @Test
@@ -561,53 +574,6 @@
     }
 
     @Test
-    public void testUncacheShortcutWhenShutdown() {
-        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
-
-        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
-                buildPerson());
-        mDataManager.addOrUpdateConversationInfo(shortcut);
-
-        NotificationListenerService listenerService =
-                mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
-
-        listenerService.onNotificationPosted(mStatusBarNotification);
-        shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
-        mDataManager.addOrUpdateConversationInfo(shortcut);
-
-        mShutdownBroadcastReceiver.onReceive(mContext, new Intent());
-        verify(mShortcutServiceInternal).uncacheShortcuts(
-                anyInt(), any(), eq(TEST_PKG_NAME),
-                eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
-                eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
-    }
-
-    @Test
-    public void testDoNotUncacheShortcutWhenShutdownIfNotificationChannelCreated() {
-        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
-
-        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
-                buildPerson());
-        mDataManager.addOrUpdateConversationInfo(shortcut);
-
-        NotificationListenerService listenerService =
-                mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
-
-        listenerService.onNotificationPosted(mStatusBarNotification);
-        shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
-        mDataManager.addOrUpdateConversationInfo(shortcut);
-
-        listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
-                mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
-
-        mShutdownBroadcastReceiver.onReceive(mContext, new Intent());
-        verify(mShortcutServiceInternal, never()).uncacheShortcuts(
-                anyInt(), any(), eq(TEST_PKG_NAME),
-                eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
-                eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
-    }
-
-    @Test
     public void testShortcutAddedOrUpdated() {
         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
 
@@ -769,20 +735,57 @@
     }
 
     @Test
-    public void testPruneInactiveCachedShortcuts() {
+    public void testDoNotUncacheShortcutWithActiveNotifications() {
         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+        NotificationListenerService listenerService =
+                mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
 
-        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
-                buildPerson());
-        shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
-        mDataManager.addOrUpdateConversationInfo(shortcut);
+        for (int i = 0; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
+            String shortcutId = TEST_SHORTCUT_ID + i;
+            ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
+                    buildPerson());
+            shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+            mDataManager.addOrUpdateConversationInfo(shortcut);
+            when(mNotification.getShortcutId()).thenReturn(shortcutId);
+            listenerService.onNotificationPosted(mStatusBarNotification);
+        }
 
         mDataManager.pruneDataForUser(USER_ID_PRIMARY, mCancellationSignal);
 
+        verify(mShortcutServiceInternal, never()).uncacheShortcuts(
+                anyInt(), anyString(), anyString(), anyList(), anyInt(), anyInt());
+    }
+
+    @Test
+    public void testUncacheOldestCachedShortcut() {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+        NotificationListenerService listenerService =
+                mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+
+        for (int i = 0; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
+            String shortcutId = TEST_SHORTCUT_ID + i;
+            ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
+                    buildPerson());
+            shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+            mDataManager.addOrUpdateConversationInfo(shortcut);
+            when(mNotification.getShortcutId()).thenReturn(shortcutId);
+            when(mStatusBarNotification.getPostTime()).thenReturn(100L + i);
+            listenerService.onNotificationPosted(mStatusBarNotification);
+            listenerService.onNotificationRemoved(mStatusBarNotification, null,
+                    NotificationListenerService.REASON_CANCEL);
+        }
+
+        // Only the shortcut #0 is uncached, all the others are not.
         verify(mShortcutServiceInternal).uncacheShortcuts(
                 anyInt(), any(), eq(TEST_PKG_NAME),
-                eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
+                eq(Collections.singletonList(TEST_SHORTCUT_ID + 0)), eq(USER_ID_PRIMARY),
                 eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+        for (int i = 1; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
+            verify(mShortcutServiceInternal, never()).uncacheShortcuts(
+                    anyInt(), anyString(), anyString(),
+                    eq(Collections.singletonList(TEST_SHORTCUT_ID + i)), anyInt(),
+                    eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+        }
     }
 
     @Test
@@ -812,6 +815,148 @@
         assertEquals(conversationInfo.getShortcutId(), TEST_SHORTCUT_ID);
     }
 
+    @Test
+    public void testGetRecentConversations() {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+                buildPerson());
+        shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
+
+        NotificationListenerService listenerService =
+                mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+        listenerService.onNotificationPosted(mStatusBarNotification);
+
+        List<ConversationChannel> result = mDataManager.getRecentConversations(USER_ID_PRIMARY);
+        assertEquals(1, result.size());
+        assertEquals(shortcut.getId(), result.get(0).getShortcutInfo().getId());
+        assertEquals(mParentNotificationChannel.getId(),
+                result.get(0).getParentNotificationChannel().getId());
+        assertEquals(mStatusBarNotification.getPostTime(), result.get(0).getLastEventTimestamp());
+        assertTrue(result.get(0).hasActiveNotifications());
+    }
+
+    @Test
+    public void testGetLastInteraction() {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+                buildPerson());
+        mDataManager.addOrUpdateConversationInfo(shortcut);
+
+        NotificationListenerService listenerService =
+                mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+        listenerService.onNotificationPosted(mStatusBarNotification);
+
+        assertEquals(mStatusBarNotification.getPostTime(),
+                mDataManager.getLastInteraction(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID));
+        assertEquals(0L,
+                mDataManager.getLastInteraction("not_test_pkg", USER_ID_PRIMARY, TEST_SHORTCUT_ID));
+        assertEquals(0L,
+                mDataManager.getLastInteraction(TEST_PKG_NAME, USER_ID_PRIMARY_MANAGED,
+                        TEST_SHORTCUT_ID));
+        assertEquals(0L,
+                mDataManager.getLastInteraction(TEST_PKG_NAME, USER_ID_SECONDARY,
+                        TEST_SHORTCUT_ID));
+    }
+
+    @Test
+    public void testNonCachedShortcutNotInRecentList() {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY_MANAGED,
+                TEST_SHORTCUT_ID, buildPerson());
+        mDataManager.addOrUpdateConversationInfo(shortcut);
+
+        NotificationListenerService listenerService =
+                mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+        listenerService.onNotificationPosted(mStatusBarNotification);
+
+        List<ConversationChannel> result = mDataManager.getRecentConversations(USER_ID_PRIMARY);
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testCustomizedConversationNotInRecentList() {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+                buildPerson());
+        shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
+
+        // Post a notification and customize the notification settings.
+        NotificationListenerService listenerService =
+                mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+        listenerService.onNotificationPosted(mStatusBarNotification);
+        listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
+                mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
+
+        List<ConversationChannel> result = mDataManager.getRecentConversations(USER_ID_PRIMARY);
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testRemoveRecentConversation() {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+                buildPerson());
+        shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
+
+        NotificationListenerService listenerService =
+                mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+        listenerService.onNotificationPosted(mStatusBarNotification);
+        listenerService.onNotificationRemoved(mStatusBarNotification, null,
+                NotificationListenerService.REASON_CANCEL);
+        mDataManager.removeRecentConversation(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+                USER_ID_PRIMARY);
+
+        verify(mShortcutServiceInternal).uncacheShortcuts(
+                anyInt(), any(), eq(TEST_PKG_NAME), eq(Collections.singletonList(TEST_SHORTCUT_ID)),
+                eq(USER_ID_PRIMARY), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+    }
+
+    @Test
+    public void testRemoveAllRecentConversations() {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+        ShortcutInfo shortcut1 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "1",
+                buildPerson());
+        shortcut1.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+        mDataManager.addOrUpdateConversationInfo(shortcut1);
+
+        ShortcutInfo shortcut2 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "2",
+                buildPerson());
+        shortcut2.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+        mDataManager.addOrUpdateConversationInfo(shortcut2);
+
+        NotificationListenerService listenerService =
+                mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+
+        // Post a notification and then dismiss it for conversation #1.
+        when(mNotification.getShortcutId()).thenReturn("1");
+        listenerService.onNotificationPosted(mStatusBarNotification);
+        listenerService.onNotificationRemoved(mStatusBarNotification, null,
+                NotificationListenerService.REASON_CANCEL);
+
+        // Post a notification for conversation #2, but don't dismiss it. Its shortcut won't be
+        // uncached when removeAllRecentConversations() is called.
+        when(mNotification.getShortcutId()).thenReturn("2");
+        listenerService.onNotificationPosted(mStatusBarNotification);
+
+        mDataManager.removeAllRecentConversations(USER_ID_PRIMARY);
+
+        verify(mShortcutServiceInternal).uncacheShortcuts(
+                anyInt(), any(), eq(TEST_PKG_NAME), eq(Collections.singletonList("1")),
+                eq(USER_ID_PRIMARY), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+        verify(mShortcutServiceInternal, never()).uncacheShortcuts(
+                anyInt(), any(), eq(TEST_PKG_NAME), eq(Collections.singletonList("2")),
+                eq(USER_ID_PRIMARY), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+    }
+
     private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
         LocalServices.removeServiceForTest(clazz);
         LocalServices.addService(clazz, mock);
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 419fb14..6febae0 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -80,6 +80,7 @@
 import com.android.server.lights.LightsManager;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.power.PowerManagerService.BatteryReceiver;
+import com.android.server.power.PowerManagerService.BinderService;
 import com.android.server.power.PowerManagerService.Injector;
 import com.android.server.power.PowerManagerService.NativeWrapper;
 import com.android.server.power.PowerManagerService.UserSwitchedReceiver;
@@ -179,6 +180,7 @@
         when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(false);
         when(mDisplayManagerInternalMock.requestPowerState(any(), anyBoolean())).thenReturn(true);
         when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn("");
+        when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(true);
 
         mDisplayPowerRequest = new DisplayPowerRequest();
         addLocalServiceMock(LightsManager.class, mLightsManagerMock);
@@ -983,6 +985,74 @@
     }
 
     @Test
+    public void testIsAmbientDisplaySuppressedForTokenByApp_ambientDisplayUnavailable()
+            throws Exception {
+        createService();
+        when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(false);
+
+        BinderService service = mService.getBinderServiceInstance();
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+            .isFalse();
+    }
+
+    @Test
+    public void testIsAmbientDisplaySuppressedForTokenByApp_default()
+            throws Exception {
+        createService();
+
+        BinderService service = mService.getBinderServiceInstance();
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+            .isFalse();
+    }
+
+    @Test
+    public void testIsAmbientDisplaySuppressedForTokenByApp_suppressedByCallingApp()
+            throws Exception {
+        createService();
+        BinderService service = mService.getBinderServiceInstance();
+        service.suppressAmbientDisplay("test", true);
+
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+            .isTrue();
+        // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app.
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", /* appUid= */ 123))
+            .isFalse();
+    }
+
+    @Test
+    public void testIsAmbientDisplaySuppressedForTokenByApp_notSuppressedByCallingApp()
+            throws Exception {
+        createService();
+        BinderService service = mService.getBinderServiceInstance();
+        service.suppressAmbientDisplay("test", false);
+
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+            .isFalse();
+        // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app.
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", /* appUid= */ 123))
+            .isFalse();
+    }
+
+    @Test
+    public void testIsAmbientDisplaySuppressedForTokenByApp_multipleTokensSuppressedByCallingApp()
+            throws Exception {
+        createService();
+        BinderService service = mService.getBinderServiceInstance();
+        service.suppressAmbientDisplay("test1", true);
+        service.suppressAmbientDisplay("test2", true);
+
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test1", Binder.getCallingUid()))
+            .isTrue();
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test2", Binder.getCallingUid()))
+            .isTrue();
+        // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app.
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test1", /* appUid= */ 123))
+            .isFalse();
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test2", /* appUid= */ 123))
+            .isFalse();
+    }
+
+    @Test
     public void testSetPowerBoost_redirectsCallToNativeWrapper() {
         createService();
         mService.systemReady(null);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index f10cab8..3af873d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1522,7 +1522,7 @@
         try {
             // Return error to skip unnecessary operation.
             doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay(
-                    any() /* window */, anyInt() /* seq */, any() /* attrs */,
+                    any() /* window */,  any() /* attrs */,
                     anyInt() /* viewVisibility */, anyInt() /* displayId */, any() /* outFrame */,
                     any() /* outContentInsets */, any() /* outStableInsets */,
                     any() /* outDisplayCutout */, any() /* outInputChannel */,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
index ca739c0..91cfd4e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
@@ -56,4 +56,12 @@
         mImeProvider.scheduleShowImePostLayout(appWin);
         assertTrue(mImeProvider.isImeTargetFromDisplayContentAndImeSame());
     }
+
+    @Test
+    public void testInputMethodInputTargetCanShowIme() {
+        WindowState target = createWindow(null, TYPE_APPLICATION, "app");
+        mDisplayContent.mInputMethodTarget = target;
+        mImeProvider.scheduleShowImePostLayout(target);
+        assertTrue(mImeProvider.isImeTargetFromDisplayContentAndImeSame());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 3053fe6..cc8b2a1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -173,6 +173,35 @@
     }
 
     @Test
+    public void testTaskLayerRank() {
+        final Task rootTask = new TaskBuilder(mSupervisor).build();
+        final Task task1 = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+        new ActivityBuilder(mAtm).setStack(task1).build().mVisibleRequested = true;
+        // RootWindowContainer#invalidateTaskLayers should post to update.
+        waitHandlerIdle(mWm.mH);
+
+        assertEquals(1, task1.mLayerRank);
+        // Only tasks that directly contain activities have a ranking.
+        assertEquals(Task.LAYER_RANK_INVISIBLE, rootTask.mLayerRank);
+
+        final Task task2 = new TaskBuilder(mSupervisor).build();
+        new ActivityBuilder(mAtm).setStack(task2).build().mVisibleRequested = true;
+        waitHandlerIdle(mWm.mH);
+
+        // Note that ensureActivitiesVisible is disabled in SystemServicesTestRule, so both the
+        // activities have the visible rank.
+        assertEquals(2, task1.mLayerRank);
+        // The task2 is the top task, so it has a lower rank as a higher priority oom score.
+        assertEquals(1, task2.mLayerRank);
+
+        task2.moveToBack("test", null /* task */);
+        waitHandlerIdle(mWm.mH);
+
+        assertEquals(1, task1.mLayerRank);
+        assertEquals(2, task2.mLayerRank);
+    }
+
+    @Test
     public void testForceStopPackage() {
         final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
         final ActivityRecord activity = task.getTopMostActivity();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index d37f3f4..ea12233 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -94,11 +94,6 @@
     }
 
     @Override
-    public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, int localValue,
-            int localChanges) throws RemoteException {
-    }
-
-    @Override
     public void dispatchWindowShown() throws RemoteException {
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 38c7531..e50c009 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -277,6 +277,69 @@
                 mWpc.getConfiguration().seq, globalSeq);
     }
 
+    @Test
+    public void testComputeOomAdjFromActivities() {
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setCreateTask(true)
+                .setUseProcess(mWpc)
+                .build();
+        activity.mVisibleRequested = true;
+        final int[] callbackResult = { 0 };
+        final int visible = 1;
+        final int paused = 2;
+        final int stopping = 4;
+        final int other = 8;
+        final WindowProcessController.ComputeOomAdjCallback callback =
+                new WindowProcessController.ComputeOomAdjCallback() {
+            @Override
+            public void onVisibleActivity() {
+                callbackResult[0] |= visible;
+            }
+
+            @Override
+            public void onPausedActivity() {
+                callbackResult[0] |= paused;
+            }
+
+            @Override
+            public void onStoppingActivity(boolean finishing) {
+                callbackResult[0] |= stopping;
+            }
+
+            @Override
+            public void onOtherActivity() {
+                callbackResult[0] |= other;
+            }
+        };
+
+        // onStartActivity should refresh the state immediately.
+        mWpc.onStartActivity(0 /* topProcessState */, activity.info);
+        assertEquals(1 /* minTaskLayer */, mWpc.computeOomAdjFromActivities(callback));
+        assertEquals(visible, callbackResult[0]);
+
+        // The oom state will be updated in handler from activity state change.
+        callbackResult[0] = 0;
+        activity.mVisibleRequested = false;
+        activity.setState(Task.ActivityState.PAUSED, "test");
+        waitHandlerIdle(mAtm.mH);
+        mWpc.computeOomAdjFromActivities(callback);
+        assertEquals(paused, callbackResult[0]);
+
+        // updateProcessInfo with updateOomAdj=true should refresh the state immediately.
+        callbackResult[0] = 0;
+        activity.setState(Task.ActivityState.STOPPING, "test");
+        mWpc.updateProcessInfo(false /* updateServiceConnectionActivities */,
+                true /* activityChange */, true /* updateOomAdj */, false /* addPendingTopUid */);
+        mWpc.computeOomAdjFromActivities(callback);
+        assertEquals(stopping, callbackResult[0]);
+
+        callbackResult[0] = 0;
+        activity.setState(Task.ActivityState.STOPPED, "test");
+        waitHandlerIdle(mAtm.mH);
+        mWpc.computeOomAdjFromActivities(callback);
+        assertEquals(other, callbackResult[0]);
+    }
+
     private TestDisplayContent createTestDisplayContentInContainer() {
         return new TestDisplayContent.Builder(mAtm, 1000, 1500).build();
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 7daddd8..986807e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -360,7 +360,7 @@
         attrs.setTitle(name);
 
         final WindowState w = new WindowState(service, session, iWindow, token, parent,
-                OP_NONE, 0, attrs, VISIBLE, ownerId, userId,
+                OP_NONE, attrs, VISIBLE, ownerId, userId,
                 ownerCanAddInternalSystemWindow,
                 powerManagerWrapper);
         // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
@@ -1088,7 +1088,7 @@
 
         TestWindowState(WindowManagerService service, Session session, IWindow window,
                 WindowManager.LayoutParams attrs, WindowToken token) {
-            super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0, 0,
+            super(service, session, window, token, null, OP_NONE, attrs, 0, 0, 0,
                     false /* ownerCanAddInternalSystemWindow */);
         }
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 5b3da61..8261b53 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -79,6 +79,30 @@
      */
     public static final int SERVICE_CLASS_VOICE = ImsSsData.SERVICE_CLASS_VOICE;
 
+    /**
+     * Only send USSD over IMS while CS is out of service, otherwise send USSD over CS.
+     * {@link #KEY_CARRIER_USSD_METHOD_INT}
+     */
+    public static final int USSD_OVER_CS_PREFERRED   = 0;
+
+    /**
+     * Send USSD over IMS or CS while IMS is out of service or silent redial over CS if needed.
+     * {@link #KEY_CARRIER_USSD_METHOD_INT}
+     */
+    public static final int USSD_OVER_IMS_PREFERRED  = 1;
+
+    /**
+     * Only send USSD over CS.
+     * {@link #KEY_CARRIER_USSD_METHOD_INT}
+     */
+    public static final int USSD_OVER_CS_ONLY        = 2;
+
+    /**
+     * Only send USSD over IMS and disallow silent redial over CS.
+     * {@link #KEY_CARRIER_USSD_METHOD_INT}
+     */
+    public static final int USSD_OVER_IMS_ONLY       = 3;
+
     private final Context mContext;
 
     /**
@@ -584,6 +608,20 @@
     public static final String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
 
     /**
+     * Specify the method of selection for UE sending USSD requests. The default value is
+     * {@link #USSD_OVER_CS_PREFERRED}.
+     * <p> Available options:
+     * <ul>
+     *   <li>0: {@link #USSD_OVER_CS_PREFERRED} </li>
+     *   <li>1: {@link #USSD_OVER_IMS_PREFERRED} </li>
+     *   <li>2: {@link #USSD_OVER_CS_ONLY} </li>
+     *   <li>3: {@link #USSD_OVER_IMS_ONLY} </li>
+     * </ul>
+     */
+    public static final String KEY_CARRIER_USSD_METHOD_INT =
+            "carrier_ussd_method_int";
+
+    /**
      * Flag specifying whether to show an alert dialog for 5G disable when the user disables VoLTE.
      * By default this value is {@code false}.
      *
@@ -3963,6 +4001,7 @@
         sDefaults.putBoolean(KEY_CARRIER_SETTINGS_ENABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VT_AVAILABLE_BOOL, false);
+        sDefaults.putInt(KEY_CARRIER_USSD_METHOD_INT, USSD_OVER_CS_PREFERRED);
         sDefaults.putBoolean(KEY_VOLTE_5G_LIMITED_ALERT_DIALOG_BOOL, false);
         sDefaults.putBoolean(KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL, false);
         sDefaults.putBoolean(KEY_ALLOW_MERGING_RTT_CALLS_BOOL, false);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a82d988..11c1aa0 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2807,7 +2807,11 @@
     /** Current network is LTE_CA {@hide} */
     @UnsupportedAppUsage
     public static final int NETWORK_TYPE_LTE_CA = TelephonyProtoEnums.NETWORK_TYPE_LTE_CA; // = 19.
-    /** Current network is NR(New Radio) 5G. */
+    /**
+     * Current network is NR (New Radio) 5G.
+     * This will only be returned for 5G SA.
+     * For 5G NSA, the network type will be {@link #NETWORK_TYPE_LTE}.
+     */
     public static final int NETWORK_TYPE_NR = TelephonyProtoEnums.NETWORK_TYPE_NR; // 20.
 
     private static final @NetworkType int[] NETWORK_TYPES = {
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index 3c3076f..030ddd2 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -32,7 +32,6 @@
 import static org.junit.Assert.fail;
 
 import android.net.LinkProperties.ProvisioningChange;
-import android.net.util.LinkPropertiesUtils.CompareResult;
 import android.os.Build;
 import android.system.OsConstants;
 import android.util.ArraySet;
@@ -41,6 +40,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index 91c9a2a..6de31f6 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -22,11 +22,11 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.net.util.MacAddressUtils;
-
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.net.module.util.MacAddressUtils;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 391be35..0973d54 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -29,7 +29,6 @@
 import android.net.ProxyInfo;
 import android.net.StaticIpConfiguration;
 import android.net.Uri;
-import android.net.util.MacAddressUtils;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -41,6 +40,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.MacAddressUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
index dad431c1..e2f40cf 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
@@ -17,10 +17,11 @@
 package android.net.wifi.p2p.nsd;
 
 import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.nsd.DnsSdTxtRecord;
 import android.os.Build;
 import android.text.TextUtils;
 
+import com.android.net.module.util.DnsSdTxtRecord;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
diff --git a/wifi/java/android/net/wifi/util/SdkLevelUtil.java b/wifi/java/android/net/wifi/util/SdkLevelUtil.java
index 042634c7..d08d4fd 100644
--- a/wifi/java/android/net/wifi/util/SdkLevelUtil.java
+++ b/wifi/java/android/net/wifi/util/SdkLevelUtil.java
@@ -23,17 +23,17 @@
  *
  * This can be used to disable new Wifi APIs added in Mainline updates on older SDK versions.
  *
+ * Note: if certain functionality is gated with SdkLevelUtil, its corresponding unit tests should
+ * also be gated by the same condition. Then, those unit tests will only be exercised on a base
+ * system image satisfying that condition.
+ * Alternatively, it can be tested via static mocking.
+ *
  * @hide
  */
 public class SdkLevelUtil {
 
-    /** This class is instantiable to allow easy mocking. */
-    public SdkLevelUtil() { }
-
-    /** See {@link #isAtLeastS()}. This version is non-static to allow easy mocking. */
-    public boolean isAtLeastSMockable() {
-        return isAtLeastS();
-    }
+    /** This class is not instantiable. */
+    private SdkLevelUtil() {}
 
     /** Returns true if the Android platform SDK is at least "S", false otherwise. */
     public static boolean isAtLeastS() {
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 62220a6..d4b2051 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -33,13 +33,14 @@
 import static org.junit.Assert.assertTrue;
 
 import android.net.MacAddress;
-import android.net.util.MacAddressUtils;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
 import android.os.Parcel;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.net.module.util.MacAddressUtils;
+
 import org.junit.Before;
 import org.junit.Test;