Merge "wifi: Move SAP passphrase ascii encodable check to wifi-service"
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/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 0c6670d..453d6f6 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
@@ -16509,6 +16510,23 @@
 
 package android.graphics.text {
 
+  public class GlyphStyle {
+    ctor public GlyphStyle(@ColorInt int, @FloatRange(from=0) float, @FloatRange(from=0) float, @FloatRange(from=0) float, int);
+    ctor public GlyphStyle(@NonNull android.graphics.Paint);
+    method public void applyToPaint(@NonNull android.graphics.Paint);
+    method @ColorInt public int getColor();
+    method public int getFlags();
+    method @FloatRange(from=0) public float getFontSize();
+    method @FloatRange(from=0) public float getScaleX();
+    method @FloatRange(from=0) public float getSkewX();
+    method public void setColor(@ColorInt int);
+    method public void setFlags(int);
+    method public void setFontSize(@FloatRange(from=0) float);
+    method public void setFromPaint(@NonNull android.graphics.Paint);
+    method public void setScaleX(@FloatRange(from=0) float);
+    method public void setSkewX(@FloatRange(from=0) float);
+  }
+
   public class LineBreaker {
     method @NonNull public android.graphics.text.LineBreaker.Result computeLineBreaks(@NonNull android.graphics.text.MeasuredText, @NonNull android.graphics.text.LineBreaker.ParagraphConstraints, @IntRange(from=0) int);
     field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
@@ -16569,6 +16587,25 @@
     method @NonNull public android.graphics.text.MeasuredText.Builder setComputeLayout(boolean);
   }
 
+  public final class PositionedGlyphs {
+    method public float getAscent();
+    method public float getDescent();
+    method @NonNull public android.graphics.fonts.Font getFont(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getGlyphId(@IntRange(from=0) int);
+    method public float getOriginX();
+    method public float getOriginY();
+    method public float getPositionX(@IntRange(from=0) int);
+    method public float getPositionY(@IntRange(from=0) int);
+    method @NonNull public android.graphics.text.GlyphStyle getStyle();
+    method public float getTotalAdvance();
+    method @IntRange(from=0) public int glyphCount();
+  }
+
+  public class TextShaper {
+    method @NonNull public static android.graphics.text.PositionedGlyphs shapeTextRun(@NonNull char[], int, int, int, int, float, float, boolean, @NonNull android.graphics.Paint);
+    method @NonNull public static android.graphics.text.PositionedGlyphs shapeTextRun(@NonNull CharSequence, int, int, int, int, float, float, boolean, @NonNull android.graphics.Paint);
+  }
+
 }
 
 package android.hardware {
@@ -46799,6 +46836,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";
@@ -46993,6 +47031,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 {
@@ -49994,6 +50036,10 @@
     method @NonNull public android.text.StaticLayout.Builder setUseLineSpacingFromFallbacks(boolean);
   }
 
+  public class StyledTextShaper {
+    method @NonNull public static java.util.List<android.graphics.text.PositionedGlyphs> shapeText(@NonNull CharSequence, int, int, @NonNull android.text.TextDirectionHeuristic, @NonNull android.text.TextPaint);
+  }
+
   public interface TextDirectionHeuristic {
     method public boolean isRtl(char[], int, int);
     method public boolean isRtl(CharSequence, int, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index a058496..949a54a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7429,7 +7429,7 @@
     field public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0; // 0x0
     field public static final String EXTRA_CHANGE_REASON = "changeReason";
     field @Deprecated public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
-    field public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
+    field @Deprecated public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
     field public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
     field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
     field public static final String EXTRA_URL = "android.net.wifi.extra.URL";
@@ -7437,7 +7437,7 @@
     field public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
     field public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
     field public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
-    field public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
+    field @Deprecated public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
     field public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
     field public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
     field public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0; // 0x0
diff --git a/api/test-current.txt b/api/test-current.txt
index 75ea4b4..4c2aa5a 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);
@@ -3406,6 +3408,8 @@
     field public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
     field public static final String NOTIFICATION_BADGING = "notification_badging";
     field public static final String POWER_MENU_LOCKED_SHOW_CONTENT = "power_menu_locked_show_content";
+    field public static final String SELECTED_SPELL_CHECKER = "selected_spell_checker";
+    field public static final String SELECTED_SPELL_CHECKER_SUBTYPE = "selected_spell_checker_subtype";
     field public static final String SHOW_FIRST_CRASH_DIALOG_DEV_OPTION = "show_first_crash_dialog_dev_option";
     field public static final String SHOW_IME_WITH_HARD_KEYBOARD = "show_ime_with_hard_keyboard";
     field @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds";
@@ -5289,6 +5293,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);
@@ -5538,6 +5543,18 @@
 
 }
 
+package android.view.textservice {
+
+  public final class SpellCheckerSubtype implements android.os.Parcelable {
+    field public static final int SUBTYPE_ID_NONE = 0; // 0x0
+  }
+
+  public final class TextServicesManager {
+    method public boolean isSpellCheckerEnabled();
+  }
+
+}
+
 package android.widget {
 
   public abstract class AbsListView extends android.widget.AdapterView<android.widget.ListAdapter> implements android.widget.Filter.FilterListener android.text.TextWatcher android.view.ViewTreeObserver.OnGlobalLayoutListener android.view.ViewTreeObserver.OnTouchModeChangeListener {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 4ccc7e6..cb65482 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.
@@ -3191,6 +3192,8 @@
     optional int32 end_y = 7;  // Y coordinate for ACTION_MOVE event.
     optional int32 left_boundary = 8;  // left edge width + left inset
     optional int32 right_boundary = 9;  // screen width - (right edge width + right inset)
+    optional float ml_model_score = 10;  // The score between 0 and 1 which is the prediction output
+        // for the Back Gesture model.
 
     enum WindowHorizontalLocation {
         DEFAULT_LOCATION = 0;
@@ -10461,6 +10464,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..e8937a8 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,21 @@
     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, e.g. any
+     * PendingIntent that needs to be used with inline reply or bubbles.
+     */
+    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 +316,27 @@
         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.\nStrongly consider"
+                    + " using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality"
+                    + " depends on the PendingIntent being mutable, e.g. if it needs to"
+                    + " be used with inline replies or bubbles.";
+
+        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 +401,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 +428,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 +548,7 @@
             intents[i].prepareToLeaveProcess(context);
             resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
         }
+        checkFlags(flags, packageName);
         try {
             IIntentSender target =
                 ActivityManager.getService().getIntentSenderWithFeature(
@@ -521,6 +575,7 @@
             intents[i].prepareToLeaveProcess(context);
             resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
         }
+        checkFlags(flags, packageName);
         try {
             IIntentSender target =
                 ActivityManager.getService().getIntentSenderWithFeature(
@@ -572,6 +627,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 +707,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/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/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
index f6cd726..1173c31 100644
--- a/core/java/android/hardware/input/InputManagerInternal.java
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -78,4 +78,26 @@
      */
     public abstract boolean transferTouchFocus(@NonNull IBinder fromChannelToken,
             @NonNull IBinder toChannelToken);
+
+    /** Registers the {@link LidSwitchCallback} to begin receiving notifications. */
+    public abstract void registerLidSwitchCallback(@NonNull LidSwitchCallback callbacks);
+
+    /**
+     * Unregisters a {@link LidSwitchCallback callback} previously registered with
+     * {@link #registerLidSwitchCallback(LidSwitchCallback)}.
+     */
+    public abstract void unregisterLidSwitchCallback(@NonNull LidSwitchCallback callbacks);
+
+    /** Callback interface for notifications relating to the lid switch. */
+    public interface LidSwitchCallback {
+        /**
+         * This callback is invoked when the lid switch changes state. Will be triggered once on
+         * registration of the callback with a {@code whenNanos} of 0 and then on every subsequent
+         * change in lid switch state.
+         *
+         * @param whenNanos the time when the change occurred
+         * @param lidOpen true if the lid is open
+         */
+        void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
+    }
 }
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/provider/Settings.java b/core/java/android/provider/Settings.java
index 07867e2..e978608 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7663,6 +7663,8 @@
          * @hide
          */
         @UnsupportedAppUsage
+        @TestApi
+        @SuppressLint("NoSettingsProvider")
         public static final String SELECTED_SPELL_CHECKER = "selected_spell_checker";
 
         /**
@@ -7673,6 +7675,8 @@
          * @hide
          */
         @UnsupportedAppUsage
+        @TestApi
+        @SuppressLint("NoSettingsProvider")
         public static final String SELECTED_SPELL_CHECKER_SUBTYPE =
                 "selected_spell_checker_subtype";
 
@@ -14464,6 +14468,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/text/StyledTextShaper.java b/core/java/android/text/StyledTextShaper.java
new file mode 100644
index 0000000..bf90614
--- /dev/null
+++ b/core/java/android/text/StyledTextShaper.java
@@ -0,0 +1,67 @@
+/*
+ * 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.text;
+
+import android.annotation.NonNull;
+import android.graphics.Paint;
+import android.graphics.text.PositionedGlyphs;
+import android.graphics.text.TextShaper;
+
+import java.util.List;
+
+/**
+ * Provides text shaping for multi-styled text.
+ *
+ * @see TextShaper#shapeTextRun(char[], int, int, int, int, float, float, boolean, Paint)
+ * @see TextShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)
+ * @see StyledTextShaper#shapeText(CharSequence, int, int, TextDirectionHeuristic, TextPaint)
+ */
+public class StyledTextShaper {
+    private StyledTextShaper() {}
+
+
+    /**
+     * Shape multi-styled text.
+     *
+     * @param text a styled text.
+     * @param start a start index of shaping target in the text.
+     * @param count a length of shaping target in the text.
+     * @param dir a text direction.
+     * @param paint a paint
+     * @return a shape result.
+     */
+    public static @NonNull List<PositionedGlyphs> shapeText(
+            @NonNull CharSequence text, int start, int count,
+            @NonNull TextDirectionHeuristic dir, @NonNull TextPaint paint) {
+        MeasuredParagraph mp = MeasuredParagraph.buildForBidi(
+                text, start, start + count, dir, null);
+        TextLine tl = TextLine.obtain();
+        try {
+            tl.set(paint, text, start, start + count,
+                    mp.getParagraphDir(),
+                    mp.getDirections(start, start + count),
+                    false /* tabstop is not supported */,
+                    null,
+                    -1, -1 // ellipsis is not supported.
+            );
+            return tl.shape();
+        } finally {
+            TextLine.recycle(tl);
+        }
+    }
+
+}
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 3c51fa7..b826832 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -23,6 +23,8 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Paint.FontMetricsInt;
+import android.graphics.text.PositionedGlyphs;
+import android.graphics.text.TextShaper;
 import android.os.Build;
 import android.text.Layout.Directions;
 import android.text.Layout.TabStops;
@@ -35,6 +37,7 @@
 import com.android.internal.util.ArrayUtils;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Represents a line of styled text, for measuring in visual order and
@@ -307,6 +310,36 @@
     }
 
     /**
+     * Shape the TextLine.
+     */
+    List<PositionedGlyphs> shape() {
+        List<PositionedGlyphs> glyphs = new ArrayList<>();
+        float horizontal = 0;
+        float x = 0;
+        final int runCount = mDirections.getRunCount();
+        for (int runIndex = 0; runIndex < runCount; runIndex++) {
+            final int runStart = mDirections.getRunStart(runIndex);
+            if (runStart > mLen) break;
+            final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen);
+            final boolean runIsRtl = mDirections.isRunRtl(runIndex);
+
+            int segStart = runStart;
+            for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
+                if (j == runLimit || charAt(j) == TAB_CHAR) {
+                    horizontal += shapeRun(glyphs, segStart, j, runIsRtl, x + horizontal,
+                            runIndex != (runCount - 1) || j != mLen);
+
+                    if (j != runLimit) {  // charAt(j) == TAB_CHAR
+                        horizontal = mDir * nextTab(horizontal * mDir);
+                    }
+                    segStart = j + 1;
+                }
+            }
+        }
+        return glyphs;
+    }
+
+    /**
      * Returns the signed graphical offset from the leading margin.
      *
      * Following examples are all for measuring offset=3. LX(e.g. L0, L1, ...) denotes a
@@ -483,12 +516,12 @@
 
         if ((mDir == Layout.DIR_LEFT_TO_RIGHT) == runIsRtl) {
             float w = -measureRun(start, limit, limit, runIsRtl, null);
-            handleRun(start, limit, limit, runIsRtl, c, x + w, top,
+            handleRun(start, limit, limit, runIsRtl, c, null, x + w, top,
                     y, bottom, null, false);
             return w;
         }
 
-        return handleRun(start, limit, limit, runIsRtl, c, x, top,
+        return handleRun(start, limit, limit, runIsRtl, c, null, x, top,
                 y, bottom, null, needWidth);
     }
 
@@ -507,10 +540,35 @@
      */
     private float measureRun(int start, int offset, int limit, boolean runIsRtl,
             FontMetricsInt fmi) {
-        return handleRun(start, offset, limit, runIsRtl, null, 0, 0, 0, 0, fmi, true);
+        return handleRun(start, offset, limit, runIsRtl, null, null, 0, 0, 0, 0, fmi, true);
     }
 
     /**
+     * Shape a unidirectional (but possibly multi-styled) run of text.
+     *
+     * @param glyphs the output positioned glyphs list
+     * @param start the line-relative start
+     * @param limit the line-relative limit
+     * @param runIsRtl true if the run is right-to-left
+     * @param x the position of the run that is closest to the leading margin
+     * @param needWidth true if the width value is required.
+     * @return the signed width of the run, based on the paragraph direction.
+     * Only valid if needWidth is true.
+     */
+    private float shapeRun(List<PositionedGlyphs> glyphs, int start,
+            int limit, boolean runIsRtl, float x, boolean needWidth) {
+
+        if ((mDir == Layout.DIR_LEFT_TO_RIGHT) == runIsRtl) {
+            float w = -measureRun(start, limit, limit, runIsRtl, null);
+            handleRun(start, limit, limit, runIsRtl, null, glyphs, x + w, 0, 0, 0, null, false);
+            return w;
+        }
+
+        return handleRun(start, limit, limit, runIsRtl, null, glyphs, x, 0, 0, 0, null, needWidth);
+    }
+
+
+    /**
      * Walk the cursor through this line, skipping conjuncts and
      * zero-width characters.
      *
@@ -841,6 +899,7 @@
      * @param end the end of the text
      * @param runIsRtl true if the run is right-to-left
      * @param c the canvas, can be null if rendering is not needed
+     * @param glyphs the output positioned glyph list, can be null if not necessary
      * @param x the edge of the run closest to the leading margin
      * @param top the top of the line
      * @param y the baseline
@@ -854,7 +913,7 @@
      */
     private float handleText(TextPaint wp, int start, int end,
             int contextStart, int contextEnd, boolean runIsRtl,
-            Canvas c, float x, int top, int y, int bottom,
+            Canvas c, List<PositionedGlyphs> glyphs, float x, int top, int y, int bottom,
             FontMetricsInt fmi, boolean needWidth, int offset,
             @Nullable ArrayList<DecorationInfo> decorations) {
 
@@ -878,16 +937,20 @@
             totalWidth = getRunAdvance(wp, start, end, contextStart, contextEnd, runIsRtl, offset);
         }
 
-        if (c != null) {
-            final float leftX, rightX;
-            if (runIsRtl) {
-                leftX = x - totalWidth;
-                rightX = x;
-            } else {
-                leftX = x;
-                rightX = x + totalWidth;
-            }
+        final float leftX, rightX;
+        if (runIsRtl) {
+            leftX = x - totalWidth;
+            rightX = x;
+        } else {
+            leftX = x;
+            rightX = x + totalWidth;
+        }
 
+        if (glyphs != null) {
+            shapeTextRun(glyphs, wp, start, end, contextStart, contextEnd, runIsRtl, leftX);
+        }
+
+        if (c != null) {
             if (wp.bgColor != 0) {
                 int previousColor = wp.getColor();
                 Paint.Style previousStyle = wp.getStyle();
@@ -1072,6 +1135,7 @@
      * @param limit the limit of the run
      * @param runIsRtl true if the run is right-to-left
      * @param c the canvas, can be null
+     * @param glyphs the output positioned glyphs, can be null
      * @param x the end of the run closest to the leading margin
      * @param top the top of the line
      * @param y the baseline
@@ -1082,7 +1146,8 @@
      * valid if needWidth is true
      */
     private float handleRun(int start, int measureLimit,
-            int limit, boolean runIsRtl, Canvas c, float x, int top, int y,
+            int limit, boolean runIsRtl, Canvas c,
+            List<PositionedGlyphs> glyphs, float x, int top, int y,
             int bottom, FontMetricsInt fmi, boolean needWidth) {
 
         if (measureLimit < start || measureLimit > limit) {
@@ -1115,7 +1180,7 @@
             wp.set(mPaint);
             wp.setStartHyphenEdit(adjustStartHyphenEdit(start, wp.getStartHyphenEdit()));
             wp.setEndHyphenEdit(adjustEndHyphenEdit(limit, wp.getEndHyphenEdit()));
-            return handleText(wp, start, limit, start, limit, runIsRtl, c, x, top,
+            return handleText(wp, start, limit, start, limit, runIsRtl, c, glyphs, x, top,
                     y, bottom, fmi, needWidth, measureLimit, null);
         }
 
@@ -1196,8 +1261,8 @@
                             adjustStartHyphenEdit(activeStart, mPaint.getStartHyphenEdit()));
                     activePaint.setEndHyphenEdit(
                             adjustEndHyphenEdit(activeEnd, mPaint.getEndHyphenEdit()));
-                    x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, x,
-                            top, y, bottom, fmi, needWidth || activeEnd < measureLimit,
+                    x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c,
+                            glyphs, x, top, y, bottom, fmi, needWidth || activeEnd < measureLimit,
                             Math.min(activeEnd, mlimit), mDecorations);
 
                     activeStart = j;
@@ -1223,7 +1288,7 @@
                     adjustStartHyphenEdit(activeStart, mPaint.getStartHyphenEdit()));
             activePaint.setEndHyphenEdit(
                     adjustEndHyphenEdit(activeEnd, mPaint.getEndHyphenEdit()));
-            x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, x,
+            x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, glyphs, x,
                     top, y, bottom, fmi, needWidth || activeEnd < measureLimit,
                     Math.min(activeEnd, mlimit), mDecorations);
         }
@@ -1260,6 +1325,45 @@
     }
 
     /**
+     * Shape a text run with the set-up paint.
+     *
+     * @param glyphs the output positioned glyphs list
+     * @param paint the paint used to render the text
+     * @param start the start of the run
+     * @param end the end of the run
+     * @param contextStart the start of context for the run
+     * @param contextEnd the end of the context for the run
+     * @param runIsRtl true if the run is right-to-left
+     * @param x the x position of the left edge of the run
+     */
+    private void shapeTextRun(List<PositionedGlyphs> glyphs, TextPaint paint,
+            int start, int end, int contextStart, int contextEnd, boolean runIsRtl, float x) {
+
+        int count = end - start;
+        int contextCount = contextEnd - contextStart;
+        if (mCharsValid) {
+            glyphs.add(TextShaper.shapeTextRun(
+                    mChars,
+                    start, count,
+                    contextStart, contextCount,
+                    x, 0f,
+                    runIsRtl,
+                    paint
+            ));
+        } else {
+            glyphs.add(TextShaper.shapeTextRun(
+                    mText,
+                    mStart + start, count,
+                    mStart + contextStart, contextCount,
+                    x, 0f,
+                    runIsRtl,
+                    paint
+            ));
+        }
+    }
+
+
+    /**
      * Returns the next tab position.
      *
      * @param h the (unsigned) offset from the leading margin
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/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 5836538..daab70a 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -752,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/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 b438f8f..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,
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/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7452d64f..778ebb0 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;
 
@@ -1787,7 +1810,7 @@
                     .setParent(getRenderSurfaceControl())
                     .setCallsite("ViewRootImpl.getBoundsLayer")
                     .build();
-            setBoundsLayerCrop();
+            setBoundsLayerCrop(mTransaction);
             mTransaction.show(mBoundsLayer).apply();
         }
        return mBoundsLayer;
@@ -1815,25 +1838,41 @@
         return ret;
     }
 
-    private void setBoundsLayerCrop() {
+    private void setBoundsLayerCrop(Transaction t) {
         // mWinFrame is already adjusted for surface insets. So offset it and use it as
         // the cropping bounds.
         mTempBoundsRect.set(mWinFrame);
         mTempBoundsRect.offsetTo(mWindowAttributes.surfaceInsets.left,
                 mWindowAttributes.surfaceInsets.top);
-        mTransaction.setWindowCrop(mBoundsLayer, mTempBoundsRect);
+        t.setWindowCrop(mBoundsLayer, mTempBoundsRect);
     }
 
     /**
      * Called after window layout to update the bounds surface. If the surface insets have changed
      * or the surface has resized, update the bounds surface.
      */
-    private void updateBoundsLayer() {
+    private boolean updateBoundsLayer(SurfaceControl.Transaction t) {
         if (mBoundsLayer != null) {
-            setBoundsLayerCrop();
-            mTransaction.deferTransactionUntil(mBoundsLayer,
-                    getRenderSurfaceControl(), mSurface.getNextFrameNumber())
-                    .apply();
+            setBoundsLayerCrop(t);
+            t.deferTransactionUntil(mBoundsLayer, getRenderSurfaceControl(),
+                mSurface.getNextFrameNumber());
+            return true;
+        }
+        return false;
+    }
+
+    private void prepareSurfaces(boolean sizeChanged) {
+        final SurfaceControl.Transaction t = mTransaction;
+        final SurfaceControl sc = getRenderSurfaceControl();
+        if (!sc.isValid()) return;
+
+        boolean applyTransaction = updateBoundsLayer(t);
+        if (sizeChanged) {
+            applyTransaction = true;
+            t.setBufferSize(sc, mSurfaceSize.x, mSurfaceSize.y);
+        }
+        if (applyTransaction) {
+            t.apply();
         }
     }
 
@@ -2924,7 +2963,16 @@
         }
 
         if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || windowAttributesChanged) {
-            updateBoundsLayer();
+            // If the surface has been replaced, there's a chance the bounds layer is not parented
+            // to the new layer. When updating bounds layer, also reparent to the main VRI
+            // SurfaceControl to ensure it's correctly placed in the hierarchy.
+            //
+            // This needs to be done on the client side since WMS won't reparent the children to the
+            // new surface if it thinks the app is closing. WMS gets the signal that the app is
+            // stopping, but on the client side it doesn't get stopped since it's restarted quick
+            // enough. WMS doesn't want to keep around old children since they will leak when the
+            // client creates new children.
+            prepareSurfaces(surfaceSizeChanged);
         }
 
         final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
@@ -7517,6 +7565,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:");
@@ -9080,6 +9160,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);
@@ -9088,6 +9171,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);
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/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/view/textservice/SpellCheckerSubtype.java b/core/java/android/view/textservice/SpellCheckerSubtype.java
index 8224e0e..12fe626 100644
--- a/core/java/android/view/textservice/SpellCheckerSubtype.java
+++ b/core/java/android/view/textservice/SpellCheckerSubtype.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.os.Parcel;
@@ -53,6 +54,7 @@
     /**
      * @hide
      */
+    @TestApi
     public static final int SUBTYPE_ID_NONE = 0;
     private static final String SUBTYPE_LANGUAGE_TAG_NONE = "";
 
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index acb35d6..cd70a31 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.annotation.UserIdInt;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -259,6 +260,7 @@
      * @hide
      */
     @UnsupportedAppUsage
+    @TestApi
     public boolean isSpellCheckerEnabled() {
         try {
             return mService.isSpellCheckerEnabled(mUserId);
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/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/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 86e7adf..9eaeed1 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1801,6 +1801,12 @@
       "group": "WM_DEBUG_FOCUS_LIGHT",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
+    "625447638": {
+      "message": "Resize reasons for w=%s:  %s configChanged=%b dragResizingChanged=%b reportOrientationChanged=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "628276090": {
       "message": "Delaying app transition for screen rotation animation to finish",
       "level": "VERBOSE",
@@ -2113,12 +2119,6 @@
       "group": "WM_DEBUG_WINDOW_ORGANIZER",
       "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
     },
-    "1160771501": {
-      "message": "Resize reasons for w=%s:  %s surfaceResized=%b configChanged=%b dragResizingChanged=%b reportOrientationChanged=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_RESIZE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
     "1166381079": {
       "message": "Execute app transition: %s, displayId: %d Callers=%s",
       "level": "WARN",
diff --git a/graphics/java/android/graphics/RenderEffect.java b/graphics/java/android/graphics/RenderEffect.java
new file mode 100644
index 0000000..9fc0c8e
--- /dev/null
+++ b/graphics/java/android/graphics/RenderEffect.java
@@ -0,0 +1,145 @@
+/*
+ * 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.graphics;
+
+import android.annotation.NonNull;
+import android.graphics.Shader.TileMode;
+
+import libcore.util.NativeAllocationRegistry;
+
+/**
+ * Intermediate rendering step used to render drawing commands with a corresponding
+ * visual effect
+ *
+ * @hide
+ */
+public final class RenderEffect {
+
+    private static class RenderEffectHolder {
+        public static final NativeAllocationRegistry RENDER_EFFECT_REGISTRY =
+                NativeAllocationRegistry.createMalloced(
+                        RenderEffect.class.getClassLoader(), nativeGetFinalizer());
+    }
+
+    /**
+     * Create a {@link RenderEffect} instance that will offset the drawing content
+     * by the provided x and y offset.
+     * @param offsetX offset along the x axis in pixels
+     * @param offsetY offset along the y axis in pixels
+     */
+    @NonNull
+    public static RenderEffect createOffsetEffect(float offsetX, float offsetY) {
+        return new RenderEffect(nativeCreateOffsetEffect(offsetX, offsetY, 0));
+    }
+
+    /**
+     * Create a {@link RenderEffect} instance with the provided x and y offset
+     * @param offsetX offset along the x axis in pixels
+     * @param offsetY offset along the y axis in pixels
+     * @param input target RenderEffect used to render in the offset coordinates.
+     */
+    @NonNull
+    public static RenderEffect createOffsetEffect(
+            float offsetX,
+            float offsetY,
+            @NonNull RenderEffect input
+    ) {
+        return new RenderEffect(nativeCreateOffsetEffect(
+                    offsetX,
+                    offsetY,
+                    input.getNativeInstance()
+                )
+        );
+    }
+
+    /**
+     * Create a {@link RenderEffect} that blurs the contents of the optional input RenderEffect
+     * with the specified radius along the x and y axis. If no input RenderEffect is provided
+     * then all drawing commands issued with a {@link android.graphics.RenderNode} that this
+     * RenderEffect is installed in will be blurred
+     * @param radiusX Radius of blur along the X axis
+     * @param radiusY Radius of blur along the Y axis
+     * @param inputEffect Input RenderEffect that provides the content to be blurred, can be null
+     *                    to indicate that the drawing commands on the RenderNode are to be
+     *                    blurred instead of the input RenderEffect
+     * @param edgeTreatment Policy for how to blur content near edges of the blur kernel
+     */
+    @NonNull
+    public static RenderEffect createBlurEffect(
+            float radiusX,
+            float radiusY,
+            @NonNull RenderEffect inputEffect,
+            @NonNull TileMode edgeTreatment
+    ) {
+        long nativeInputEffect = inputEffect != null ? inputEffect.mNativeRenderEffect : 0;
+        return new RenderEffect(
+                nativeCreateBlurEffect(
+                        radiusX,
+                        radiusY,
+                        nativeInputEffect,
+                        edgeTreatment.nativeInt
+                )
+            );
+    }
+
+    /**
+     * Create a {@link RenderEffect} that blurs the contents of the
+     * {@link android.graphics.RenderNode} that this RenderEffect is installed on with the
+     * specified radius along hte x and y axis.
+     * @param radiusX Radius of blur along the X axis
+     * @param radiusY Radius of blur along the Y axis
+     * @param edgeTreatment Policy for how to blur content near edges of the blur kernel
+     */
+    @NonNull
+    public static RenderEffect createBlurEffect(
+            float radiusX,
+            float radiusY,
+            @NonNull TileMode edgeTreatment
+    ) {
+        return new RenderEffect(
+                nativeCreateBlurEffect(
+                        radiusX,
+                        radiusY,
+                        0,
+                        edgeTreatment.nativeInt
+                )
+        );
+    }
+
+    private final long mNativeRenderEffect;
+
+    /* only constructed from static factory methods */
+    private RenderEffect(long nativeRenderEffect) {
+        mNativeRenderEffect = nativeRenderEffect;
+        RenderEffectHolder.RENDER_EFFECT_REGISTRY.registerNativeAllocation(
+                this, mNativeRenderEffect);
+    }
+
+    /**
+     * Obtain the pointer to the underlying RenderEffect to be configured
+     * on a RenderNode object via {@link RenderNode#setRenderEffect(RenderEffect)}
+     */
+    /* package */ long getNativeInstance() {
+        return mNativeRenderEffect;
+    }
+
+    private static native long nativeCreateOffsetEffect(
+            float offsetX, float offsetY, long nativeInput);
+    private static native long nativeCreateBlurEffect(
+            float radiusX, float radiusY, long nativeInput, int edgeTreatment);
+    private static native long nativeGetFinalizer();
+}
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 8aacbc7..d812c1a 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -850,6 +850,23 @@
     }
 
     /**
+     * Configure the {@link android.graphics.RenderEffect} to apply to this RenderNode. This
+     * will apply a visual effect to the end result of the contents of this RenderNode before
+     * it is drawn into the destination. For example if
+     * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, Shader.TileMode)}
+     * is provided, the contents will be drawn in a separate layer, then this layer will
+     * be blurred when this RenderNode is drawn into the destination.
+     * @param renderEffect to be applied to the RenderNode. Passing null clears all previously
+     *          configured RenderEffects
+     *
+     * @hide
+     */
+    public void setRenderEffect(@Nullable RenderEffect renderEffect) {
+        nSetRenderEffect(mNativeRenderNode,
+                renderEffect != null ? renderEffect.getNativeInstance() : 0);
+    }
+
+    /**
      * Returns the translucency level of this display list.
      *
      * @return A value between 0.0f and 1.0f
@@ -1655,6 +1672,9 @@
     private static native boolean nSetAlpha(long renderNode, float alpha);
 
     @CriticalNative
+    private static native void nSetRenderEffect(long renderNode, long renderEffect);
+
+    @CriticalNative
     private static native boolean nSetHasOverlappingRendering(long renderNode,
             boolean hasOverlappingRendering);
 
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index cbae675..2a52ce9 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -26,8 +26,11 @@
 import android.graphics.RectF;
 import android.os.LocaleList;
 import android.os.ParcelFileDescriptor;
+import android.util.Log;
+import android.util.LongSparseArray;
 import android.util.TypedValue;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 
 import dalvik.annotation.optimization.CriticalNative;
@@ -40,6 +43,7 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.ref.WeakReference;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.channels.FileChannel;
@@ -56,6 +60,15 @@
     private static final int STYLE_ITALIC = 1;
     private static final int STYLE_NORMAL = 0;
 
+    private static final Object MAP_LOCK = new Object();
+    // We need to have mapping from native ptr to Font object for later accessing from TextShape
+    // result since Typeface doesn't have reference to Font object and it is not always created from
+    // Font object. Sometimes Typeface is created in native layer only and there might not be Font
+    // object in Java layer. So, if not found in this cache, create new Font object for API user.
+    @GuardedBy("MAP_LOCK")
+    private static final LongSparseArray<WeakReference<Font>> FONT_PTR_MAP =
+            new LongSparseArray<>();
+
     /**
      * A builder class for creating new Font.
      */
@@ -501,6 +514,10 @@
         mTtcIndex = ttcIndex;
         mAxes = axes;
         mLocaleList = localeList;
+
+        synchronized (MAP_LOCK) {
+            FONT_PTR_MAP.append(mNativePtr, new WeakReference<>(this));
+        }
     }
 
     /**
@@ -637,6 +654,63 @@
             + "}";
     }
 
+    /**
+     * Lookup Font object from native pointer or create new one if not found.
+     * @hide
+     */
+    public static Font findOrCreateFontFromNativePtr(long ptr) {
+        // First, lookup from known mapps.
+        synchronized (MAP_LOCK) {
+            WeakReference<Font> fontRef = FONT_PTR_MAP.get(ptr);
+            if (fontRef != null) {
+                Font font = fontRef.get();
+                if (font != null) {
+                    return font;
+                }
+            }
+
+            // If not found, create Font object from native object for Java API users.
+            ByteBuffer buffer = NativeFontBufferHelper.refByteBuffer(ptr);
+            long packed = nGetFontInfo(ptr);
+            int weight = (int) (packed & 0x0000_0000_0000_FFFFL);
+            boolean italic = (packed & 0x0000_0000_0001_0000L) != 0;
+            int ttcIndex = (int) ((packed & 0x0000_FFFF_0000_0000L) >> 32);
+            int axisCount = (int) ((packed & 0xFFFF_0000_0000_0000L) >> 48);
+            FontVariationAxis[] axes = new FontVariationAxis[axisCount];
+            char[] charBuffer = new char[4];
+            for (int i = 0; i < axisCount; ++i) {
+                long packedAxis = nGetAxisInfo(ptr, i);
+                float value = Float.intBitsToFloat((int) (packedAxis & 0x0000_0000_FFFF_FFFFL));
+                charBuffer[0] = (char) ((packedAxis & 0xFF00_0000_0000_0000L) >> 56);
+                charBuffer[1] = (char) ((packedAxis & 0x00FF_0000_0000_0000L) >> 48);
+                charBuffer[2] = (char) ((packedAxis & 0x0000_FF00_0000_0000L) >> 40);
+                charBuffer[3] = (char) ((packedAxis & 0x0000_00FF_0000_0000L) >> 32);
+                axes[i] = new FontVariationAxis(new String(charBuffer), value);
+            }
+            Font.Builder builder = new Font.Builder(buffer)
+                    .setWeight(weight)
+                    .setSlant(italic ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT)
+                    .setTtcIndex(ttcIndex)
+                    .setFontVariationSettings(axes);
+
+            Font newFont = null;
+            try {
+                newFont = builder.build();
+                FONT_PTR_MAP.append(ptr, new WeakReference<>(newFont));
+            } catch (IOException e) {
+                // This must not happen since the buffer was already created once.
+                Log.e("Font", "Failed to create font object from existing buffer.", e);
+            }
+            return newFont;
+        }
+    }
+
+    @CriticalNative
+    private static native long nGetFontInfo(long ptr);
+
+    @CriticalNative
+    private static native long nGetAxisInfo(long ptr, int i);
+
     @FastNative
     private static native float nGetGlyphBounds(long font, int glyphId, long paint, RectF rect);
 
diff --git a/graphics/java/android/graphics/fonts/NativeFontBufferHelper.java b/graphics/java/android/graphics/fonts/NativeFontBufferHelper.java
new file mode 100644
index 0000000..5655e7f
--- /dev/null
+++ b/graphics/java/android/graphics/fonts/NativeFontBufferHelper.java
@@ -0,0 +1,62 @@
+/*
+ * 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.graphics.fonts;
+
+import android.annotation.NonNull;
+
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
+import libcore.util.NativeAllocationRegistry;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This is a helper class for showing native allocated buffer in Java API.
+ *
+ * @hide
+ */
+public class NativeFontBufferHelper {
+    private NativeFontBufferHelper() {}
+
+    private static final NativeAllocationRegistry REGISTRY =
+            NativeAllocationRegistry.createMalloced(
+                    ByteBuffer.class.getClassLoader(), nGetReleaseFunc());
+
+    /**
+     * Wrap native buffer with ByteBuffer with adding reference to it.
+     */
+    public static @NonNull ByteBuffer refByteBuffer(long fontPtr) {
+        long refPtr = nRefFontBuffer(fontPtr);
+        ByteBuffer buffer = nWrapByteBuffer(refPtr);
+
+        // Releasing native object so that decreasing shared pointer ref count when the byte buffer
+        // is GCed.
+        REGISTRY.registerNativeAllocation(buffer, refPtr);
+
+        return buffer;
+    }
+
+    @CriticalNative
+    private static native long nRefFontBuffer(long fontPtr);
+
+    @FastNative
+    private static native ByteBuffer nWrapByteBuffer(long refPtr);
+
+    @CriticalNative
+    private static native long nGetReleaseFunc();
+}
diff --git a/graphics/java/android/graphics/text/GlyphStyle.java b/graphics/java/android/graphics/text/GlyphStyle.java
new file mode 100644
index 0000000..cc8c4d2
--- /dev/null
+++ b/graphics/java/android/graphics/text/GlyphStyle.java
@@ -0,0 +1,234 @@
+/*
+ * 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.graphics.text;
+
+import android.annotation.ColorInt;
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.graphics.Paint;
+
+import java.util.Objects;
+
+/**
+ * Represents subset of Paint parameters such as font size, scaleX that is used to draw a glyph.
+ *
+ * Glyph is a most primitive unit of text drawing.
+ *
+ */
+public class GlyphStyle {
+    private @ColorInt int mColor;
+    private float mFontSize;
+    private float mScaleX;
+    private float mSkewX;
+    private int mFlags;
+
+    /**
+     * @param color a color.
+     * @param fontSize a font size in pixels.
+     * @param scaleX a horizontal scale factor.
+     * @param skewX a horizontal skew factor
+     * @param flags paint flags
+     *
+     * @see Paint#getFlags()
+     * @see Paint#setFlags(int)
+     */
+    public GlyphStyle(
+            @ColorInt int color,
+            @FloatRange(from = 0) float fontSize,
+            @FloatRange(from = 0) float scaleX,
+            @FloatRange(from = 0) float skewX,
+            int flags) {
+        mColor = color;
+        mFontSize = fontSize;
+        mScaleX = scaleX;
+        mSkewX = skewX;
+        mFlags = flags;
+    }
+
+    /**
+     * Create glyph style from Paint
+     *
+     * @param paint a paint
+     */
+    public GlyphStyle(@NonNull Paint paint) {
+        setFromPaint(paint);
+    }
+
+    /**
+     * Gets the color.
+     *
+     * @return a color
+     * @see Paint#getColor()
+     * @see Paint#setColor(int)
+     */
+    public @ColorInt int getColor() {
+        return mColor;
+    }
+
+    /**
+     * Sets the color.
+     *
+     * @param color a color
+     * @see Paint#getColor()
+     * @see Paint#setColor(int)
+     */
+    public void setColor(@ColorInt int color) {
+        mColor = color;
+    }
+
+    /**
+     * Gets the font size in pixels.
+     *
+     * @return font size
+     * @see Paint#getTextSize()
+     * @see Paint#setTextSize(float)
+     */
+    public @FloatRange(from = 0) float getFontSize() {
+        return mFontSize;
+    }
+
+    /**
+     * Sets the font size in pixels.
+     *
+     * @param fontSize font size in pixel
+     * @see Paint#getTextSize()
+     * @see Paint#setTextSize(float)
+     */
+    public void setFontSize(@FloatRange(from = 0) float fontSize) {
+        mFontSize = fontSize;
+    }
+
+    /**
+     * Return the horizontal scale factor
+     *
+     * @return a horizontal scale factor
+     * @see Paint#getTextScaleX()
+     * @see Paint#setTextScaleX(float)
+     */
+    public @FloatRange(from = 0) float getScaleX() {
+        return mScaleX;
+    }
+
+    /**
+     * Set the horizontal scale factor
+     *
+     * @param scaleX a horizontal scale factor
+     * @see Paint#getTextScaleX()
+     * @see Paint#setTextScaleX(float)
+     */
+    public void setScaleX(@FloatRange(from = 0) float scaleX) {
+        mScaleX = scaleX;
+    }
+
+    /**
+     * Return the horizontal skew factor
+     *
+     * @return a horizontal skew factor
+     * @see Paint#getTextSkewX()
+     * @see Paint#setTextSkewX(float)
+     */
+    public @FloatRange(from = 0) float getSkewX() {
+        return mSkewX;
+    }
+
+    /**
+     * Set the horizontal skew factor
+     *
+     * @param skewX a horizontal skew factor
+     * @see Paint#getTextSkewX()
+     * @see Paint#setTextSkewX(float)
+     */
+    public void setSkewX(@FloatRange(from = 0) float skewX) {
+        mSkewX = skewX;
+    }
+
+    /**
+     * Returns the Paint flags.
+     *
+     * @return a paint flags
+     * @see Paint#getFlags()
+     * @see Paint#setFlags(int)
+     */
+    public int getFlags() {
+        return mFlags;
+    }
+
+    /**
+     * Set the Paint flags.
+     *
+     * @param flags a paint flags
+     * @see Paint#getFlags()
+     * @see Paint#setFlags(int)
+     */
+    public void setFlags(int flags) {
+        mFlags = flags;
+    }
+
+    /**
+     * Applies glyph style to the paint object.
+     *
+     * @param paint a paint object
+     */
+    public void applyToPaint(@NonNull Paint paint) {
+        paint.setColor(mColor);
+        paint.setTextSize(mFontSize);
+        paint.setTextScaleX(mScaleX);
+        paint.setTextSkewX(mSkewX);
+        paint.setFlags(mFlags);
+    }
+
+    /**
+     * Copy parameters from a Paint object.
+     *
+     * @param paint a paint object
+     */
+    public void setFromPaint(@NonNull Paint paint) {
+        mColor = paint.getColor();
+        mFontSize = paint.getTextSize();
+        mScaleX = paint.getTextScaleX();
+        mSkewX = paint.getTextSkewX();
+        mFlags = paint.getFlags();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof GlyphStyle)) return false;
+        GlyphStyle that = (GlyphStyle) o;
+        return that.mColor == mColor
+                && Float.compare(that.mFontSize, mFontSize) == 0
+                && Float.compare(that.mScaleX, mScaleX) == 0
+                && Float.compare(that.mSkewX, mSkewX) == 0
+                && mFlags == that.mFlags;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mColor, mFontSize, mScaleX, mSkewX, mFlags);
+    }
+
+    @Override
+    public String toString() {
+        return "GlyphStyle{"
+                + "mColor=" + mColor
+                + ", mFontSize=" + mFontSize
+                + ", mScaleX=" + mScaleX
+                + ", mSkewX=" + mSkewX
+                + ", mFlags=" + mFlags
+                + '}';
+    }
+}
diff --git a/graphics/java/android/graphics/text/PositionedGlyphs.java b/graphics/java/android/graphics/text/PositionedGlyphs.java
new file mode 100644
index 0000000..7364d54
--- /dev/null
+++ b/graphics/java/android/graphics/text/PositionedGlyphs.java
@@ -0,0 +1,277 @@
+/*
+ * 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.graphics.text;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.graphics.fonts.Font;
+
+import com.android.internal.util.Preconditions;
+
+import dalvik.annotation.optimization.CriticalNative;
+
+import libcore.util.NativeAllocationRegistry;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+/**
+ * Text shaping result object for single style text.
+ *
+ * You can get text shaping result by
+ * {@link TextShaper#shapeTextRun(char[], int, int, int, int, float, float, boolean, Paint)} and
+ * {@link TextShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)}.
+ *
+ * @see TextShaper#shapeTextRun(char[], int, int, int, int, float, float, boolean, Paint)
+ * @see TextShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)
+ */
+public final class PositionedGlyphs {
+    private static final NativeAllocationRegistry REGISTRY =
+            NativeAllocationRegistry.createMalloced(
+                    Typeface.class.getClassLoader(), nReleaseFunc());
+
+    private final long mLayoutPtr;
+    private final float mXOffset;
+    private final float mYOffset;
+    private final GlyphStyle mGlyphStyle;
+    private final ArrayList<Font> mFonts;
+
+    /**
+     * Returns the total amount of advance consumed by this positioned glyphs.
+     *
+     * The advance is an amount of width consumed by the glyph. The total amount of advance is
+     * a total amount of advance consumed by this series of glyphs. In other words, if another
+     * glyph is placed next to this series of  glyphs, it's X offset should be shifted this amount
+     * of width.
+     *
+     * @return total amount of advance
+     */
+    public float getTotalAdvance() {
+        return nGetTotalAdvance(mLayoutPtr);
+    }
+
+    /**
+     * Effective ascent value of this positioned glyphs.
+     *
+     * If two or more font files are used in this series of glyphs, the effective ascent will be
+     * the minimum ascent value across the all font files.
+     *
+     * @return effective ascent value
+     */
+    public float getAscent() {
+        return nGetAscent(mLayoutPtr);
+    }
+
+    /**
+     * Effective descent value of this positioned glyphs.
+     *
+     * If two or more font files are used in this series of glyphs, the effective descent will be
+     * the maximum descent value across the all font files.
+     *
+     * @return effective descent value
+     */
+    public float getDescent() {
+        return nGetDescent(mLayoutPtr);
+    }
+
+    /**
+     * Returns the glyph style used for drawing the glyph at the given index.
+     *
+     * @return A glyph style
+     */
+    @NonNull
+    public GlyphStyle getStyle() {
+        return mGlyphStyle;
+    }
+
+    /**
+     * Returns the amount of X offset added to glyph position.
+     *
+     * @return The X offset added to glyph position.
+     */
+    public float getOriginX() {
+        return mXOffset;
+    }
+
+    /**
+     * Returns the amount of Y offset added to glyph position.
+     *
+     * @return The Y offset added to glyph position.
+     */
+    public float getOriginY() {
+        return mYOffset;
+    }
+
+    /**
+     * Returns the number of glyphs stored.
+     *
+     * @return the number of glyphs
+     */
+    @IntRange(from = 0)
+    public int glyphCount() {
+        return nGetGlyphCount(mLayoutPtr);
+    }
+
+    /**
+     * Returns the font object used for drawing the glyph at the given index.
+     *
+     * @param index the glyph index
+     * @return the font object used for drawing the glyph at the given index
+     */
+    @NonNull
+    public Font getFont(@IntRange(from = 0) int index) {
+        Preconditions.checkArgumentInRange(index, 0, glyphCount() - 1, "index");
+        return mFonts.get(index);
+    }
+
+    /**
+     * Returns the glyph ID used for drawing the glyph at the given index.
+     *
+     * @param index the glyph index
+     * @return A font object
+     */
+    @IntRange(from = 0)
+    public int getGlyphId(@IntRange(from = 0) int index) {
+        Preconditions.checkArgumentInRange(index, 0, glyphCount() - 1, "index");
+        return nGetGlyphId(mLayoutPtr, index);
+    }
+
+    /**
+     * Returns the x coordinate of the glyph position at the given index.
+     *
+     * @param index the glyph index
+     * @return A X offset in pixels
+     */
+    public float getPositionX(@IntRange(from = 0) int index) {
+        Preconditions.checkArgumentInRange(index, 0, glyphCount() - 1, "index");
+        return nGetX(mLayoutPtr, index) + mXOffset;
+    }
+
+    /**
+     * Returns the y coordinate of the glyph position at the given index.
+     *
+     * @param index the glyph index
+     * @return A Y offset in pixels.
+     */
+    public float getPositionY(@IntRange(from = 0) int index) {
+        Preconditions.checkArgumentInRange(index, 0, glyphCount() - 1, "index");
+        return nGetY(mLayoutPtr, index) + mYOffset;
+    }
+
+    /**
+     * Create single style layout from native result.
+     *
+     * @hide
+     *
+     * @param layoutPtr the address of native layout object.
+     * @param paint a paint object
+     */
+    public PositionedGlyphs(long layoutPtr, @NonNull Paint paint, float xOffset, float yOffset) {
+        mLayoutPtr = layoutPtr;
+        mGlyphStyle = new GlyphStyle(paint);
+        int glyphCount = nGetGlyphCount(layoutPtr);
+        mFonts = new ArrayList<>(glyphCount);
+        mXOffset = xOffset;
+        mYOffset = yOffset;
+
+        long prevPtr = 0;
+        Font prevFont = null;
+        for (int i = 0; i < glyphCount; ++i) {
+            long ptr = nGetFont(layoutPtr, i);
+            if (prevPtr != ptr) {
+                prevPtr = ptr;
+                prevFont = Font.findOrCreateFontFromNativePtr(ptr);
+            }
+            mFonts.add(prevFont);
+        }
+
+        REGISTRY.registerNativeAllocation(this, layoutPtr);
+    }
+
+    @CriticalNative
+    private static native int nGetGlyphCount(long minikinLayout);
+    @CriticalNative
+    private static native float nGetTotalAdvance(long minikinLayout);
+    @CriticalNative
+    private static native float nGetAscent(long minikinLayout);
+    @CriticalNative
+    private static native float nGetDescent(long minikinLayout);
+    @CriticalNative
+    private static native int nGetGlyphId(long minikinLayout, int i);
+    @CriticalNative
+    private static native float nGetX(long minikinLayout, int i);
+    @CriticalNative
+    private static native float nGetY(long minikinLayout, int i);
+    @CriticalNative
+    private static native long nGetFont(long minikinLayout, int i);
+    @CriticalNative
+    private static native long nReleaseFunc();
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof PositionedGlyphs)) return false;
+        PositionedGlyphs that = (PositionedGlyphs) o;
+
+        if (!mGlyphStyle.equals(that.mGlyphStyle)) return false;
+        if (mXOffset != that.mXOffset || mYOffset != that.mYOffset) return false;
+        if (glyphCount() != that.glyphCount()) return false;
+
+        for (int i = 0; i < glyphCount(); ++i) {
+            if (getGlyphId(i) != that.getGlyphId(i)) return false;
+            if (getPositionX(i) != that.getPositionX(i)) return false;
+            if (getPositionY(i) != that.getPositionY(i)) return false;
+            // Intentionally using reference equality since font equality is heavy due to buffer
+            // compare.
+            if (getFont(i) != that.getFont(i)) return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int hashCode = Objects.hash(mXOffset, mYOffset, mGlyphStyle);
+        for (int i = 0; i < glyphCount(); ++i) {
+            hashCode = Objects.hash(hashCode,
+                    getGlyphId(i), getPositionX(i), getPositionY(i), getFont(i));
+        }
+        return hashCode;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("[");
+        for (int i = 0; i < glyphCount(); ++i) {
+            if (i != 0) {
+                sb.append(", ");
+            }
+            sb.append("[ ID = " + getGlyphId(i) + ","
+                    + " pos = (" + getPositionX(i) + "," + getPositionY(i) + ")"
+                    + " font = " + getFont(i) + " ]");
+        }
+        sb.append("]");
+        return "PositionedGlyphs{"
+                + "glyphs = " + sb.toString()
+                + ", mXOffset=" + mXOffset
+                + ", mYOffset=" + mYOffset
+                + ", mGlyphStyle=" + mGlyphStyle
+                + '}';
+    }
+}
diff --git a/graphics/java/android/graphics/text/TextShaper.java b/graphics/java/android/graphics/text/TextShaper.java
new file mode 100644
index 0000000..f40ed8f
--- /dev/null
+++ b/graphics/java/android/graphics/text/TextShaper.java
@@ -0,0 +1,125 @@
+/*
+ * 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.graphics.text;
+
+import android.annotation.NonNull;
+import android.graphics.Paint;
+import android.text.TextDirectionHeuristic;
+import android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
+
+import dalvik.annotation.optimization.FastNative;
+
+/**
+ * Provides conversion from a text into glyph array.
+ *
+ * Text shaping is a preprocess for drawing text into canvas with glyphs. The glyph is a most
+ * primitive unit of the text drawing, consist of glyph identifier in the font file and its position
+ * and style. You can draw the shape result to Canvas by calling Canvas#drawGlyphs.
+
+ *
+ * @see TextShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)
+ * @see TextShaper#shapeTextRun(char[], int, int, int, int, float, float, boolean, Paint)
+ * @see android.text.StyledTextShaper#shapeText(CharSequence, int, int, TextDirectionHeuristic,
+ * TextPaint)
+ */
+public class TextShaper {
+    private TextShaper() {}  // Do not instantiate
+
+    /**
+     * Shape non-styled text.
+     *
+     * This function shapes the text of the given range under the context of given context range.
+     * Some script, e.g. Arabic or Devanagari, changes letter shape based on its location or
+     * surrounding characters.
+     *
+     * @param text a text buffer to be shaped
+     * @param start a start index of shaping target in the buffer.
+     * @param count a length of shaping target in the buffer.
+     * @param contextStart a start index of context used for shaping in the buffer.
+     * @param contextCount a length of context used for shaping in the buffer.
+     * @param xOffset an additional amount of x offset of the result glyphs.
+     * @param yOffset an additional amount of y offset of the result glyphs.
+     * @param isRtl true if this text is shaped for RTL direction, false otherwise.
+     * @param paint a paint used for shaping text.
+     * @return a shape result.
+     */
+    @NonNull
+    public static PositionedGlyphs shapeTextRun(
+            @NonNull char[] text, int start, int count, int contextStart, int contextCount,
+            float xOffset, float yOffset, boolean isRtl, @NonNull Paint paint) {
+        Preconditions.checkNotNull(text);
+        Preconditions.checkNotNull(paint);
+        return new PositionedGlyphs(
+                nativeShapeTextRun(text, start, count, contextStart, contextCount, isRtl,
+                        paint.getNativeInstance()),
+                paint, xOffset, yOffset);
+    }
+
+    /**
+     * Shape non-styled text.
+     *
+     * This function shapes the text of the given range under the context of given context range.
+     * Some script, e.g. Arabic or Devanagari, changes letter shape based on its location or
+     * surrounding characters.
+     *
+     * @param text a text buffer to be shaped. Any styled spans stored in this text are ignored.
+     * @param start a start index of shaping target in the buffer.
+     * @param count a length of shaping target in the buffer.
+     * @param contextStart a start index of context used for shaping in the buffer.
+     * @param contextCount a length of context used for shaping in the buffer.
+     * @param xOffset an additional amount of x offset of the result glyphs.
+     * @param yOffset an additional amount of y offset of the result glyphs.
+     * @param isRtl true if this text is shaped for RTL direction, false otherwise.
+     * @param paint a paint used for shaping text.
+     * @return a shape result
+     */
+    @NonNull
+    public static PositionedGlyphs shapeTextRun(
+            @NonNull CharSequence text, int start, int count, int contextStart, int contextCount,
+            float xOffset, float yOffset, boolean isRtl, @NonNull Paint paint) {
+        Preconditions.checkNotNull(text);
+        Preconditions.checkNotNull(paint);
+        if (text instanceof String) {
+            return new PositionedGlyphs(
+                    nativeShapeTextRun(
+                            (String) text, start, count, contextStart, contextCount, isRtl,
+                            paint.getNativeInstance()),
+                    paint, xOffset, yOffset);
+        } else {
+            char[] buf = new char[contextCount];
+            TextUtils.getChars(text, contextStart, contextStart + contextCount, buf, 0);
+            return new PositionedGlyphs(
+                    nativeShapeTextRun(
+                            buf, start - contextStart, count,
+                            0, contextCount, isRtl, paint.getNativeInstance()),
+                    paint, xOffset, yOffset);
+        }
+    }
+
+    @FastNative
+    private static native long nativeShapeTextRun(
+            char[] text, int start, int count, int contextStart, int contextCount,
+            boolean isRtl, long nativePaint);
+
+    @FastNative
+    private static native long nativeShapeTextRun(
+            String text, int start, int count, int contextStart, int contextCount,
+            boolean isRtl, long nativePaint);
+
+}
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/hwui/Android.bp b/libs/hwui/Android.bp
index 90d2537..975265e 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -327,6 +327,7 @@
         "jni/PathMeasure.cpp",
         "jni/Picture.cpp",
         "jni/Shader.cpp",
+        "jni/RenderEffect.cpp",
         "jni/Typeface.cpp",
         "jni/Utils.cpp",
         "jni/YuvToJpegEncoder.cpp",
@@ -334,6 +335,7 @@
         "jni/fonts/FontFamily.cpp",
         "jni/text/LineBreaker.cpp",
         "jni/text/MeasuredText.cpp",
+        "jni/text/TextShaper.cpp",
     ],
 
     header_libs: [ "android_graphics_jni_headers" ],
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index ff9cf45..8fba9cf 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -49,6 +49,12 @@
     return true;
 }
 
+bool LayerProperties::setImageFilter(SkImageFilter* imageFilter) {
+    if(mImageFilter.get() == imageFilter) return false;
+    mImageFilter = sk_ref_sp(imageFilter);
+    return true;
+}
+
 bool LayerProperties::setFromPaint(const SkPaint* paint) {
     bool changed = false;
     changed |= setAlpha(static_cast<uint8_t>(PaintUtils::getAlphaDirect(paint)));
@@ -63,6 +69,7 @@
     setAlpha(other.alpha());
     setXferMode(other.xferMode());
     setColorFilter(other.getColorFilter());
+    setImageFilter(other.getImageFilter());
     return *this;
 }
 
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index ef4cd1f..aeb60e6 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -27,6 +27,7 @@
 #include "utils/PaintUtils.h"
 
 #include <SkBlendMode.h>
+#include <SkImageFilter.h>
 #include <SkCamera.h>
 #include <SkColor.h>
 #include <SkMatrix.h>
@@ -93,6 +94,10 @@
 
     SkColorFilter* getColorFilter() const { return mColorFilter.get(); }
 
+    bool setImageFilter(SkImageFilter* imageFilter);
+
+    SkImageFilter* getImageFilter() const { return mImageFilter.get(); }
+
     // Sets alpha, xfermode, and colorfilter from an SkPaint
     // paint may be NULL, in which case defaults will be set
     bool setFromPaint(const SkPaint* paint);
@@ -118,6 +123,7 @@
     uint8_t mAlpha;
     SkBlendMode mMode;
     sk_sp<SkColorFilter> mColorFilter;
+    sk_sp<SkImageFilter> mImageFilter;
 };
 
 /*
@@ -541,6 +547,7 @@
     bool promotedToLayer() const {
         return mLayerProperties.mType == LayerType::None && fitsOnLayer() &&
                (mComputedFields.mNeedLayerForFunctors ||
+                mLayerProperties.mImageFilter != nullptr ||
                 (!MathUtils::isZero(mPrimitiveFields.mAlpha) && mPrimitiveFields.mAlpha < 1 &&
                  mPrimitiveFields.mHasOverlappingRendering));
     }
diff --git a/libs/hwui/apex/LayoutlibLoader.cpp b/libs/hwui/apex/LayoutlibLoader.cpp
index 4bbf121..dca10e2 100644
--- a/libs/hwui/apex/LayoutlibLoader.cpp
+++ b/libs/hwui/apex/LayoutlibLoader.cpp
@@ -47,6 +47,7 @@
 extern int register_android_graphics_NinePatch(JNIEnv*);
 extern int register_android_graphics_PathEffect(JNIEnv* env);
 extern int register_android_graphics_Shader(JNIEnv* env);
+extern int register_android_graphics_RenderEffect(JNIEnv* env);
 extern int register_android_graphics_Typeface(JNIEnv* env);
 
 namespace android {
@@ -108,6 +109,7 @@
         {"android.graphics.RecordingCanvas", REG_JNI(register_android_view_DisplayListCanvas)},
 //        {"android.graphics.Region", REG_JNI(register_android_graphics_Region)},
         {"android.graphics.Shader", REG_JNI(register_android_graphics_Shader)},
+        {"android.graphics.RenderEffect", REG_JNI(register_android_graphics_RenderEffect)},
         {"android.graphics.Typeface", REG_JNI(register_android_graphics_Typeface)},
         {"android.graphics.animation.NativeInterpolatorFactory",
          REG_JNI(register_android_graphics_animation_NativeInterpolatorFactory)},
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index 12e2e81..e1f5abd7 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -43,6 +43,7 @@
 extern int register_android_graphics_NinePatch(JNIEnv*);
 extern int register_android_graphics_PathEffect(JNIEnv* env);
 extern int register_android_graphics_Shader(JNIEnv* env);
+extern int register_android_graphics_RenderEffect(JNIEnv* env);
 extern int register_android_graphics_Typeface(JNIEnv* env);
 extern int register_android_graphics_YuvImage(JNIEnv* env);
 
@@ -73,6 +74,7 @@
 extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
 extern int register_android_graphics_text_MeasuredText(JNIEnv* env);
 extern int register_android_graphics_text_LineBreaker(JNIEnv *env);
+extern int register_android_graphics_text_TextShaper(JNIEnv *env);
 
 extern int register_android_util_PathParser(JNIEnv* env);
 extern int register_android_view_DisplayListCanvas(JNIEnv* env);
@@ -123,6 +125,7 @@
     REG_JNI(register_android_graphics_Picture),
     REG_JNI(register_android_graphics_Region),
     REG_JNI(register_android_graphics_Shader),
+    REG_JNI(register_android_graphics_RenderEffect),
     REG_JNI(register_android_graphics_TextureLayer),
     REG_JNI(register_android_graphics_Typeface),
     REG_JNI(register_android_graphics_YuvImage),
@@ -137,6 +140,7 @@
     REG_JNI(register_android_graphics_pdf_PdfRenderer),
     REG_JNI(register_android_graphics_text_MeasuredText),
     REG_JNI(register_android_graphics_text_LineBreaker),
+    REG_JNI(register_android_graphics_text_TextShaper),
 
     REG_JNI(register_android_util_PathParser),
     REG_JNI(register_android_view_RenderNode),
diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h
index 6cde9c5..a15803a 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -72,7 +72,7 @@
         size_t start = 0;
         size_t nGlyphs = layout.nGlyphs();
         for (size_t i = 0; i < nGlyphs; i++) {
-            const minikin::MinikinFont* nextFont = layout.getFont(i);
+            const minikin::MinikinFont* nextFont = layout.getFont(i)->typeface().get();
             if (i > 0 && nextFont != curFont) {
                 SkFont* skfont = &paint->getSkFont();
                 MinikinFontSkia::populateSkFont(skfont, curFont, layout.getFakery(start));
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index 0bb689c..4e2016a 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -157,7 +157,6 @@
 private:
 
     using SkPaint::setShader;
-    using SkPaint::setImageFilter;
 
     SkFont mFont;
     sk_sp<SkDrawLooper> mLooper;
diff --git a/libs/hwui/jni/FontUtils.h b/libs/hwui/jni/FontUtils.h
index b36b4e6..f93a0da 100644
--- a/libs/hwui/jni/FontUtils.h
+++ b/libs/hwui/jni/FontUtils.h
@@ -38,6 +38,14 @@
   minikin::Font font;
 };
 
+// We assume FontWrapper's address is the same as underlying Font's address.
+// This assumption is used for looking up Java font object from native address.
+// The Font object can be created without Java's Font object but all Java's Font objects point to
+// the native FontWrapper. So when looking up Java object from minikin::Layout which gives us Font
+// address, we lookup Font Java object from Font address with assumption that it is the same as
+// FontWrapper address.
+static_assert(offsetof(FontWrapper, font) == 0);
+
 // Utility wrapper for java.util.List
 class ListHelper {
 public:
diff --git a/libs/hwui/jni/RenderEffect.cpp b/libs/hwui/jni/RenderEffect.cpp
new file mode 100644
index 0000000..0ebd0ca
--- /dev/null
+++ b/libs/hwui/jni/RenderEffect.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+#include "Bitmap.h"
+#include "GraphicsJNI.h"
+#include "SkImageFilter.h"
+#include "SkImageFilters.h"
+#include "graphics_jni_helpers.h"
+#include "utils/Blur.h"
+#include <utils/Log.h>
+
+using namespace android::uirenderer;
+
+static jlong createOffsetEffect(
+    JNIEnv* env,
+    jobject,
+    jfloat offsetX,
+    jfloat offsetY,
+    jlong inputFilterHandle
+) {
+    auto* inputFilter = reinterpret_cast<const SkImageFilter*>(inputFilterHandle);
+    sk_sp<SkImageFilter> offset = SkImageFilters::Offset(offsetX, offsetY, sk_ref_sp(inputFilter));
+    return reinterpret_cast<jlong>(offset.release());
+}
+
+static jlong createBlurEffect(JNIEnv* env , jobject, jfloat radiusX,
+        jfloat radiusY, jlong inputFilterHandle, jint edgeTreatment) {
+    auto* inputImageFilter = reinterpret_cast<SkImageFilter*>(inputFilterHandle);
+    sk_sp<SkImageFilter> blurFilter =
+            SkImageFilters::Blur(
+                    Blur::convertRadiusToSigma(radiusX),
+                    Blur::convertRadiusToSigma(radiusY),
+                    static_cast<SkTileMode>(edgeTreatment),
+                    sk_ref_sp(inputImageFilter),
+                    nullptr);
+    return reinterpret_cast<jlong>(blurFilter.release());
+}
+
+static void RenderEffect_safeUnref(SkImageFilter* filter) {
+    SkSafeUnref(filter);
+}
+
+static jlong getRenderEffectFinalizer(JNIEnv*, jobject) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&RenderEffect_safeUnref));
+}
+
+static const JNINativeMethod gRenderEffectMethods[] = {
+    {"nativeGetFinalizer", "()J", (void*)getRenderEffectFinalizer},
+    {"nativeCreateOffsetEffect", "(FFJ)J", (void*)createOffsetEffect},
+    {"nativeCreateBlurEffect", "(FFJI)J", (void*)createBlurEffect}
+};
+
+int register_android_graphics_RenderEffect(JNIEnv* env) {
+    android::RegisterMethodsOrDie(env, "android/graphics/RenderEffect",
+            gRenderEffectMethods, NELEM(gRenderEffectMethods));
+    return 0;
+}
\ No newline at end of file
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index 85c802b..4b4aa92 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -215,6 +215,12 @@
     return SET_AND_DIRTY(setAlpha, alpha, RenderNode::ALPHA);
 }
 
+static jboolean android_view_RenderNode_setRenderEffect(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
+        jlong renderEffectPtr) {
+    SkImageFilter* imageFilter = reinterpret_cast<SkImageFilter*>(renderEffectPtr);
+    return SET_AND_DIRTY(mutateLayerProperties().setImageFilter, imageFilter, RenderNode::GENERIC);
+}
+
 static jboolean android_view_RenderNode_setHasOverlappingRendering(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
         bool hasOverlappingRendering) {
     return SET_AND_DIRTY(setHasOverlappingRendering, hasOverlappingRendering,
@@ -690,6 +696,7 @@
     { "nSetRevealClip",        "(JZFFF)Z", (void*) android_view_RenderNode_setRevealClip },
 
     { "nSetAlpha",             "(JF)Z",  (void*) android_view_RenderNode_setAlpha },
+    { "nSetRenderEffect",      "(JJ)V",  (void*) android_view_RenderNode_setRenderEffect },
     { "nSetHasOverlappingRendering", "(JZ)Z",
             (void*) android_view_RenderNode_setHasOverlappingRendering },
     { "nSetUsageHint",    "(JI)V", (void*) android_view_RenderNode_setUsageHint },
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index bcdb4f5..0eb4095 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -198,6 +198,59 @@
     return spacing;
 }
 
+// Critical Native
+static jlong Font_getFontInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
+    MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font.typeface().get());
+
+    uint64_t result = font->font.style().weight();
+    result |= font->font.style().slant() == minikin::FontStyle::Slant::ITALIC ? 0x10000 : 0x00000;
+    result |= ((static_cast<uint64_t>(minikinSkia->GetFontIndex())) << 32);
+    result |= ((static_cast<uint64_t>(minikinSkia->GetAxes().size())) << 48);
+    return result;
+}
+
+// Critical Native
+static jlong Font_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle, jint index) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
+    MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font.typeface().get());
+    const minikin::FontVariation& var = minikinSkia->GetAxes().at(index);
+    uint32_t floatBinary = *reinterpret_cast<const uint32_t*>(&var.value);
+    return (static_cast<uint64_t>(var.axisTag) << 32) | static_cast<uint64_t>(floatBinary);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct FontBufferWrapper {
+    FontBufferWrapper(const std::shared_ptr<minikin::MinikinFont>& font) : minikinFont(font) {}
+    // MinikinFont holds a shared pointer of SkTypeface which has reference to font data.
+    std::shared_ptr<minikin::MinikinFont> minikinFont;
+};
+
+static void unrefBuffer(jlong nativePtr) {
+    FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr);
+    delete wrapper;
+}
+
+// Critical Native
+static jlong FontBufferHelper_refFontBuffer(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
+    return reinterpret_cast<jlong>(new FontBufferWrapper(font->font.typeface()));
+}
+
+// Fast Native
+static jobject FontBufferHelper_wrapByteBuffer(JNIEnv* env, jobject, jlong nativePtr) {
+    FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr);
+    return env->NewDirectByteBuffer(
+        const_cast<void*>(wrapper->minikinFont->GetFontData()),
+        wrapper->minikinFont->GetFontSize());
+}
+
+// Critical Native
+static jlong FontBufferHelper_getReleaseFunc(CRITICAL_JNI_PARAMS) {
+    return reinterpret_cast<jlong>(unrefBuffer);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static const JNINativeMethod gFontBuilderMethods[] = {
@@ -211,13 +264,23 @@
 static const JNINativeMethod gFontMethods[] = {
     { "nGetGlyphBounds", "(JIJLandroid/graphics/RectF;)F", (void*) Font_getGlyphBounds },
     { "nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F", (void*) Font_getFontMetrics },
+    { "nGetFontInfo", "(J)J", (void*) Font_getFontInfo },
+    { "nGetAxisInfo", "(JI)J", (void*) Font_getAxisInfo },
+};
+
+static const JNINativeMethod gFontBufferHelperMethods[] = {
+    { "nRefFontBuffer", "(J)J", (void*) FontBufferHelper_refFontBuffer },
+    { "nWrapByteBuffer", "(J)Ljava/nio/ByteBuffer;", (void*) FontBufferHelper_wrapByteBuffer },
+    { "nGetReleaseFunc", "()J", (void*) FontBufferHelper_getReleaseFunc },
 };
 
 int register_android_graphics_fonts_Font(JNIEnv* env) {
     return RegisterMethodsOrDie(env, "android/graphics/fonts/Font$Builder", gFontBuilderMethods,
             NELEM(gFontBuilderMethods)) +
             RegisterMethodsOrDie(env, "android/graphics/fonts/Font", gFontMethods,
-            NELEM(gFontMethods));
+            NELEM(gFontMethods)) +
+            RegisterMethodsOrDie(env, "android/graphics/fonts/NativeFontBufferHelper",
+            gFontBufferHelperMethods, NELEM(gFontBufferHelperMethods));
 }
 
 }
diff --git a/libs/hwui/jni/text/TextShaper.cpp b/libs/hwui/jni/text/TextShaper.cpp
new file mode 100644
index 0000000..9d9e91f
--- /dev/null
+++ b/libs/hwui/jni/text/TextShaper.cpp
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "TextShaper"
+
+#include "graphics_jni_helpers.h"
+#include <nativehelper/ScopedStringChars.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <set>
+#include <algorithm>
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+#include <hwui/MinikinSkia.h>
+#include <hwui/MinikinUtils.h>
+#include <hwui/Paint.h>
+#include <minikin/MinikinPaint.h>
+#include <minikin/MinikinFont.h>
+
+namespace android {
+
+struct LayoutWrapper {
+    LayoutWrapper(minikin::Layout&& layout, float ascent, float descent)
+        : layout(std::move(layout)), ascent(ascent), descent(descent)  {}
+    minikin::Layout layout;
+    float ascent;
+    float descent;
+};
+
+static void releaseLayout(jlong ptr) {
+    delete reinterpret_cast<LayoutWrapper*>(ptr);
+}
+
+static jlong shapeTextRun(const uint16_t* text, int textSize, int start, int count,
+    int contextStart, int contextCount, minikin::Bidi bidiFlags,
+    const Paint& paint, const Typeface* typeface) {
+
+    minikin::MinikinPaint minikinPaint = MinikinUtils::prepareMinikinPaint(&paint, typeface);
+
+    minikin::Layout layout = MinikinUtils::doLayout(&paint, bidiFlags, typeface,
+        text, textSize, start, count, contextStart, contextCount, nullptr);
+
+    std::set<const minikin::Font*> seenFonts;
+    float overallAscent = 0;
+    float overallDescent = 0;
+    for (int i = 0; i < layout.nGlyphs(); ++i) {
+        const minikin::Font* font = layout.getFont(i);
+        if (seenFonts.find(font) != seenFonts.end()) continue;
+        minikin::MinikinExtent extent = {};
+        font->typeface()->GetFontExtent(&extent, minikinPaint, layout.getFakery(i));
+        overallAscent = std::min(overallAscent, extent.ascent);
+        overallDescent = std::max(overallDescent, extent.descent);
+    }
+
+    std::unique_ptr<LayoutWrapper> ptr = std::make_unique<LayoutWrapper>(
+        std::move(layout), overallAscent, overallDescent
+    );
+
+    return reinterpret_cast<jlong>(ptr.release());
+}
+
+static jlong TextShaper_shapeTextRunChars(JNIEnv *env, jobject, jcharArray charArray,
+    jint start, jint count, jint contextStart, jint contextCount, jboolean isRtl,
+    jlong paintPtr) {
+    ScopedCharArrayRO text(env, charArray);
+    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
+    const Typeface* typeface = paint->getAndroidTypeface();
+    const minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
+    return shapeTextRun(
+        text.get(), text.size(),
+        start, count,
+        contextStart, contextCount,
+        bidiFlags,
+        *paint, typeface);
+
+}
+
+static jlong TextShaper_shapeTextRunString(JNIEnv *env, jobject, jstring string,
+    jint start, jint count, jint contextStart, jint contextCount, jboolean isRtl,
+    jlong paintPtr) {
+    ScopedStringChars text(env, string);
+    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
+    const Typeface* typeface = paint->getAndroidTypeface();
+    const minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
+    return shapeTextRun(
+        text.get(), text.size(),
+        start, count,
+        contextStart, contextCount,
+        bidiFlags,
+        *paint, typeface);
+}
+
+// CriticalNative
+static jint TextShaper_Result_getGlyphCount(CRITICAL_JNI_PARAMS_COMMA jlong ptr) {
+    const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
+    return layout->layout.nGlyphs();
+}
+
+// CriticalNative
+static jfloat TextShaper_Result_getTotalAdvance(CRITICAL_JNI_PARAMS_COMMA jlong ptr) {
+    const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
+    return layout->layout.getAdvance();
+}
+
+// CriticalNative
+static jfloat TextShaper_Result_getAscent(CRITICAL_JNI_PARAMS_COMMA jlong ptr) {
+    const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
+    return layout->ascent;
+}
+
+// CriticalNative
+static jfloat TextShaper_Result_getDescent(CRITICAL_JNI_PARAMS_COMMA jlong ptr) {
+    const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
+    return layout->descent;
+}
+
+// CriticalNative
+static jint TextShaper_Result_getGlyphId(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
+    const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
+    return layout->layout.getGlyphId(i);
+}
+
+// CriticalNative
+static jfloat TextShaper_Result_getX(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
+    const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
+    return layout->layout.getX(i);
+}
+
+// CriticalNative
+static jfloat TextShaper_Result_getY(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
+    const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
+    return layout->layout.getY(i);
+}
+
+// CriticalNative
+static jlong TextShaper_Result_getFont(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
+    const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
+    return reinterpret_cast<jlong>(layout->layout.getFont(i));
+}
+
+// CriticalNative
+static jlong TextShaper_Result_nReleaseFunc(CRITICAL_JNI_PARAMS) {
+    return reinterpret_cast<jlong>(releaseLayout);
+}
+
+static const JNINativeMethod gMethods[] = {
+    // Fast Natives
+    {"nativeShapeTextRun", "("
+        "[C"  // text
+        "I"  // start
+        "I"  // count
+        "I"  // contextStart
+        "I"  // contextCount
+        "Z"  // isRtl
+        "J)"  // paint
+        "J",  // LayoutPtr
+        (void*) TextShaper_shapeTextRunChars},
+
+    {"nativeShapeTextRun", "("
+        "Ljava/lang/String;"  // text
+        "I"  // start
+        "I"  // count
+        "I"  // contextStart
+        "I"  // contextCount
+        "Z"  // isRtl
+        "J)"  // paint
+        "J",  // LayoutPtr
+        (void*) TextShaper_shapeTextRunString},
+
+};
+
+static const JNINativeMethod gResultMethods[] = {
+    { "nGetGlyphCount", "(J)I", (void*)TextShaper_Result_getGlyphCount },
+    { "nGetTotalAdvance", "(J)F", (void*)TextShaper_Result_getTotalAdvance },
+    { "nGetAscent", "(J)F", (void*)TextShaper_Result_getAscent },
+    { "nGetDescent", "(J)F", (void*)TextShaper_Result_getDescent },
+    { "nGetGlyphId", "(JI)I", (void*)TextShaper_Result_getGlyphId },
+    { "nGetX", "(JI)F", (void*)TextShaper_Result_getX },
+    { "nGetY", "(JI)F", (void*)TextShaper_Result_getY },
+    { "nGetFont", "(JI)J", (void*)TextShaper_Result_getFont },
+    { "nReleaseFunc", "()J", (void*)TextShaper_Result_nReleaseFunc },
+};
+
+int register_android_graphics_text_TextShaper(JNIEnv* env) {
+    return RegisterMethodsOrDie(env, "android/graphics/text/TextShaper", gMethods,
+                                NELEM(gMethods))
+        + RegisterMethodsOrDie(env, "android/graphics/text/PositionedGlyphs",
+            gResultMethods, NELEM(gResultMethods));
+}
+
+}
+
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 00ceb2d..1473b3e 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -172,10 +172,12 @@
                             SkPaint* paint) {
     paint->setFilterQuality(kLow_SkFilterQuality);
     if (alphaMultiplier < 1.0f || properties.alpha() < 255 ||
-        properties.xferMode() != SkBlendMode::kSrcOver || properties.getColorFilter() != nullptr) {
+        properties.xferMode() != SkBlendMode::kSrcOver || properties.getColorFilter() != nullptr ||
+        properties.getImageFilter() != nullptr) {
         paint->setAlpha(properties.alpha() * alphaMultiplier);
         paint->setBlendMode(properties.xferMode());
         paint->setColorFilter(sk_ref_sp(properties.getColorFilter()));
+        paint->setImageFilter(sk_ref_sp(properties.getImageFilter()));
         return true;
     }
     return false;
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..9deeb8f 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -34,6 +34,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
+import android.database.StaleDataException;
 import android.net.Uri;
 import android.os.Environment;
 import android.os.FileUtils;
@@ -492,7 +493,12 @@
     public Uri getRingtoneUri(int position) {
         // use cursor directly instead of requerying it, which could easily
         // cause position to shuffle.
-        if (mCursor == null || !mCursor.moveToPosition(position)) {
+        try {
+            if (mCursor == null || !mCursor.moveToPosition(position)) {
+                return null;
+            }
+        } catch (StaleDataException | IllegalStateException e) {
+            Log.e(TAG, "Unexpected Exception has been catched.", e);
             return null;
         }
 
@@ -1130,11 +1136,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 +1170,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/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 24fbe00..c5197ae 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
@@ -16491,6 +16492,23 @@
 
 package android.graphics.text {
 
+  public class GlyphStyle {
+    ctor public GlyphStyle(@ColorInt int, @FloatRange(from=0) float, @FloatRange(from=0) float, @FloatRange(from=0) float, int);
+    ctor public GlyphStyle(@NonNull android.graphics.Paint);
+    method public void applyToPaint(@NonNull android.graphics.Paint);
+    method @ColorInt public int getColor();
+    method public int getFlags();
+    method @FloatRange(from=0) public float getFontSize();
+    method @FloatRange(from=0) public float getScaleX();
+    method @FloatRange(from=0) public float getSkewX();
+    method public void setColor(@ColorInt int);
+    method public void setFlags(int);
+    method public void setFontSize(@FloatRange(from=0) float);
+    method public void setFromPaint(@NonNull android.graphics.Paint);
+    method public void setScaleX(@FloatRange(from=0) float);
+    method public void setSkewX(@FloatRange(from=0) float);
+  }
+
   public class LineBreaker {
     method @NonNull public android.graphics.text.LineBreaker.Result computeLineBreaks(@NonNull android.graphics.text.MeasuredText, @NonNull android.graphics.text.LineBreaker.ParagraphConstraints, @IntRange(from=0) int);
     field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
@@ -16551,6 +16569,25 @@
     method @NonNull public android.graphics.text.MeasuredText.Builder setComputeLayout(boolean);
   }
 
+  public final class PositionedGlyphs {
+    method public float getAscent();
+    method public float getDescent();
+    method @NonNull public android.graphics.fonts.Font getFont(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getGlyphId(@IntRange(from=0) int);
+    method public float getOriginX();
+    method public float getOriginY();
+    method public float getPositionX(@IntRange(from=0) int);
+    method public float getPositionY(@IntRange(from=0) int);
+    method @NonNull public android.graphics.text.GlyphStyle getStyle();
+    method public float getTotalAdvance();
+    method @IntRange(from=0) public int glyphCount();
+  }
+
+  public class TextShaper {
+    method @NonNull public static android.graphics.text.PositionedGlyphs shapeTextRun(@NonNull char[], int, int, int, int, float, float, boolean, @NonNull android.graphics.Paint);
+    method @NonNull public static android.graphics.text.PositionedGlyphs shapeTextRun(@NonNull CharSequence, int, int, int, int, float, float, boolean, @NonNull android.graphics.Paint);
+  }
+
 }
 
 package android.hardware {
@@ -44936,6 +44973,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";
@@ -45130,6 +45168,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 {
@@ -48131,6 +48173,10 @@
     method @NonNull public android.text.StaticLayout.Builder setUseLineSpacingFromFallbacks(boolean);
   }
 
+  public class StyledTextShaper {
+    method @NonNull public static java.util.List<android.graphics.text.PositionedGlyphs> shapeText(@NonNull CharSequence, int, int, @NonNull android.text.TextDirectionHeuristic, @NonNull android.text.TextPaint);
+  }
+
   public interface TextDirectionHeuristic {
     method public boolean isRtl(char[], int, int);
     method public boolean isRtl(CharSequence, int, int);
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/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index 92d0858..ac8b7b5 100644
--- a/packages/SystemUI/res/layout/media_output_list_item.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item.xml
@@ -75,18 +75,6 @@
             android:textSize="12sp"
             android:fontFamily="roboto-regular"
             android:visibility="gone"/>
-        <ProgressBar
-            android:id="@+id/volume_indeterminate_progress"
-            style="@*android:style/Widget.Material.ProgressBar.Horizontal"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="16dp"
-            android:layout_marginEnd="15dp"
-            android:layout_marginBottom="1dp"
-            android:layout_alignParentBottom="true"
-            android:indeterminate="true"
-            android:indeterminateOnly="true"
-            android:visibility="gone"/>
         <SeekBar
             android:id="@+id/volume_seekbar"
             android:layout_width="match_parent"
@@ -94,6 +82,17 @@
             android:layout_alignParentBottom="true"/>
     </RelativeLayout>
 
+    <ProgressBar
+        android:id="@+id/volume_indeterminate_progress"
+        style="@*android:style/Widget.Material.ProgressBar.Horizontal"
+        android:layout_width="258dp"
+        android:layout_height="18dp"
+        android:layout_marginStart="68dp"
+        android:layout_marginTop="40dp"
+        android:indeterminate="true"
+        android:indeterminateOnly="true"
+        android:visibility="gone"/>
+
     <View
         android:layout_width="1dp"
         android:layout_height="36dp"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2e56df3..8777d50 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1380,4 +1380,5 @@
     <dimen name="media_output_dialog_header_back_icon_size">36dp</dimen>
     <dimen name="media_output_dialog_header_icon_padding">16dp</dimen>
     <dimen name="media_output_dialog_icon_corner_radius">16dp</dimen>
+    <dimen name="media_output_dialog_title_anim_y_delta">12.5dp</dimen>
 </resources>
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/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 810cecc..f6571ef 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -251,10 +251,9 @@
         // App icon
         ImageView appIcon = mViewHolder.getAppIcon();
         if (data.getAppIcon() != null) {
-            appIcon.setImageDrawable(data.getAppIcon());
+            appIcon.setImageIcon(data.getAppIcon());
         } else {
-            Drawable iconDrawable = mContext.getDrawable(R.drawable.ic_music_note);
-            appIcon.setImageDrawable(iconDrawable);
+            appIcon.setImageResource(R.drawable.ic_music_note);
         }
 
         // Song name
@@ -332,7 +331,7 @@
             int actionId = ACTION_IDS[i];
             final ImageButton button = mViewHolder.getAction(actionId);
             MediaAction mediaAction = actionIcons.get(i);
-            button.setImageDrawable(mediaAction.getDrawable());
+            button.setImageIcon(mediaAction.getIcon());
             button.setContentDescription(mediaAction.getContentDescription());
             Runnable action = mediaAction.getAction();
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index 40a879a..0ed96ee 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -33,7 +33,7 @@
     /**
      * Icon shown on player, close to app name.
      */
-    val appIcon: Drawable?,
+    val appIcon: Icon?,
     /**
      * Artist name.
      */
@@ -109,7 +109,7 @@
 
 /** State of a media action. */
 data class MediaAction(
-    val drawable: Drawable?,
+    val icon: Icon?,
     val action: Runnable?,
     val contentDescription: CharSequence?
 )
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index cb6b22c..5d63cc7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -455,7 +455,7 @@
         val app = builder.loadHeaderAppName()
 
         // App Icon
-        val smallIconDrawable: Drawable = sbn.notification.smallIcon.loadDrawable(context)
+        val smallIcon = sbn.notification.smallIcon
 
         // Song name
         var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE)
@@ -501,8 +501,13 @@
                 } else {
                     null
                 }
+                val mediaActionIcon = if (action.getIcon()?.getType() == Icon.TYPE_RESOURCE) {
+                    Icon.createWithResource(packageContext, action.getIcon()!!.getResId())
+                } else {
+                    action.getIcon()
+                }
                 val mediaAction = MediaAction(
-                        action.getIcon().loadDrawable(packageContext),
+                        mediaActionIcon,
                         runnable,
                         action.title)
                 actionIcons.add(mediaAction)
@@ -518,7 +523,7 @@
             val hasCheckedForResume = mediaEntries[key]?.hasCheckedForResume == true
             val active = mediaEntries[key]?.active ?: true
             onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, bgColor, app,
-                    smallIconDrawable, artist, song, artWorkIcon, actionIcons,
+                    smallIcon, artist, song, artWorkIcon, actionIcons,
                     actionsToShowCollapsed, sbn.packageName, token, notif.contentIntent, null,
                     active, resumeAction = resumeAction, isLocalSession = isLocalSession,
                     notificationKey = key, hasCheckedForResume = hasCheckedForResume,
@@ -572,7 +577,7 @@
         val source = ImageDecoder.createSource(context.getContentResolver(), uri)
         return try {
             ImageDecoder.decodeBitmap(source) {
-                decoder, info, source -> decoder.isMutableRequired = true
+                decoder, info, source -> decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
             }
         } catch (e: IOException) {
             Log.e(TAG, "Unable to load bitmap", e)
@@ -612,7 +617,7 @@
 
     private fun getResumeMediaAction(action: Runnable): MediaAction {
         return MediaAction(
-            context.getDrawable(R.drawable.lb_ic_play),
+            Icon.createWithResource(context, R.drawable.lb_ic_play),
             action,
             context.getString(R.string.controls_media_resume)
         )
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 9b6a9ea..d1630eb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -44,6 +44,8 @@
     private static final String TAG = "MediaOutputAdapter";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
+    private ViewGroup mConnectedItem;
+
     public MediaOutputAdapter(MediaOutputController controller) {
         super(controller);
     }
@@ -79,18 +81,6 @@
         return mController.getMediaDevices().size();
     }
 
-    void onItemClick(MediaDevice device) {
-        mController.connectDevice(device);
-        device.setState(MediaDeviceState.STATE_CONNECTING);
-        notifyDataSetChanged();
-    }
-
-    void onItemClick(int customizedItem) {
-        if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
-            mController.launchBluetoothPairing();
-        }
-    }
-
     @Override
     CharSequence getItemTitle(MediaDevice device) {
         if (device.getDeviceType() == MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE
@@ -117,6 +107,10 @@
         @Override
         void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
             super.onBind(device, topMargin, bottomMargin);
+            final boolean currentlyConnected = isCurrentlyConnected(device);
+            if (currentlyConnected) {
+                mConnectedItem = mFrameLayout;
+            }
             if (mController.isTransferring()) {
                 if (device.getState() == MediaDeviceState.STATE_CONNECTING
                         && !mController.hasAdjustVolumeUserRestriction()) {
@@ -133,16 +127,16 @@
                             false /* showSeekBar*/, false /* showProgressBar */,
                             true /* showSubtitle */);
                     mSubTitleText.setText(R.string.media_output_dialog_connect_failed);
-                    mFrameLayout.setOnClickListener(v -> onItemClick(device));
+                    mFrameLayout.setOnClickListener(v -> onItemClick(v, device));
                 } else if (!mController.hasAdjustVolumeUserRestriction()
-                        && isCurrentConnected(device)) {
+                        && currentlyConnected) {
                     setTwoLineLayout(device, null /* title */, true /* bFocused */,
                             true /* showSeekBar*/, false /* showProgressBar */,
                             false /* showSubtitle */);
                     initSeekbar(device);
                 } else {
                     setSingleLineLayout(getItemTitle(device), false /* bFocused */);
-                    mFrameLayout.setOnClickListener(v -> onItemClick(device));
+                    mFrameLayout.setOnClickListener(v -> onItemClick(v, device));
                 }
             }
         }
@@ -160,5 +154,24 @@
                 mFrameLayout.setOnClickListener(v -> onItemClick(CUSTOMIZED_ITEM_PAIR_NEW));
             }
         }
+
+        private void onItemClick(View view, MediaDevice device) {
+            if (mController.isTransferring()) {
+                return;
+            }
+
+            playSwitchingAnim(mConnectedItem, view);
+            mController.connectDevice(device);
+            device.setState(MediaDeviceState.STATE_CONNECTING);
+            if (!isAnimating()) {
+                notifyDataSetChanged();
+            }
+        }
+
+        private void onItemClick(int customizedItem) {
+            if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
+                mController.launchBluetoothPairing();
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 01dc6c4..2d3e77d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.media.dialog;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.graphics.Typeface;
 import android.text.TextUtils;
@@ -33,6 +35,7 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.settingslib.media.MediaDevice;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 
 /**
@@ -50,6 +53,7 @@
 
     private boolean mIsDragging;
     private int mMargin;
+    private boolean mIsAnimating;
 
     Context mContext;
     View mHolderView;
@@ -75,7 +79,7 @@
         return device.getName();
     }
 
-    boolean isCurrentConnected(MediaDevice device) {
+    boolean isCurrentlyConnected(MediaDevice device) {
         return TextUtils.equals(device.getId(),
                 mController.getCurrentConnectedMediaDevice().getId());
     }
@@ -84,10 +88,17 @@
         return mIsDragging;
     }
 
+    boolean isAnimating() {
+        return mIsAnimating;
+    }
+
     /**
      * ViewHolder for binding device view.
      */
     abstract class MediaDeviceBaseViewHolder extends RecyclerView.ViewHolder {
+
+        private static final int ANIM_DURATION = 200;
+
         final FrameLayout mFrameLayout;
         final TextView mTitleText;
         final TextView mTwoLineTitleText;
@@ -123,17 +134,16 @@
         private void setMargin(boolean topMargin, boolean bottomMargin) {
             ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mFrameLayout
                     .getLayoutParams();
-            if (topMargin) {
-                params.topMargin = mMargin;
-            }
-            if (bottomMargin) {
-                params.bottomMargin = mMargin;
-            }
+            params.topMargin = topMargin ? mMargin : 0;
+            params.bottomMargin = bottomMargin ? mMargin : 0;
             mFrameLayout.setLayoutParams(params);
         }
+
         void setSingleLineLayout(CharSequence title, boolean bFocused) {
-            mTitleText.setVisibility(View.VISIBLE);
             mTwoLineLayout.setVisibility(View.GONE);
+            mProgressBar.setVisibility(View.GONE);
+            mTitleText.setVisibility(View.VISIBLE);
+            mTitleText.setTranslationY(0);
             mTitleText.setText(title);
             if (bFocused) {
                 mTitleText.setTypeface(Typeface.create(FONT_SELECTED_TITLE, Typeface.NORMAL));
@@ -146,9 +156,11 @@
                 boolean showSeekBar, boolean showProgressBar, boolean showSubtitle) {
             mTitleText.setVisibility(View.GONE);
             mTwoLineLayout.setVisibility(View.VISIBLE);
+            mSeekBar.setAlpha(1);
             mSeekBar.setVisibility(showSeekBar ? View.VISIBLE : View.GONE);
             mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
             mSubTitleText.setVisibility(showSubtitle ? View.VISIBLE : View.GONE);
+            mTwoLineTitleText.setTranslationY(0);
             if (device == null) {
                 mTwoLineTitleText.setText(title);
             } else {
@@ -189,5 +201,53 @@
                 }
             });
         }
+
+        void playSwitchingAnim(@NonNull View from, @NonNull View to) {
+            final float delta = (float) (mContext.getResources().getDimensionPixelSize(
+                    R.dimen.media_output_dialog_title_anim_y_delta));
+            final SeekBar fromSeekBar = from.requireViewById(R.id.volume_seekbar);
+            final TextView toTitleText = to.requireViewById(R.id.title);
+            if (fromSeekBar.getVisibility() != View.VISIBLE || toTitleText.getVisibility()
+                    != View.VISIBLE) {
+                return;
+            }
+            mIsAnimating = true;
+            // Animation for title text
+            toTitleText.setTypeface(Typeface.create(FONT_SELECTED_TITLE, Typeface.NORMAL));
+            toTitleText.animate()
+                    .setDuration(ANIM_DURATION)
+                    .translationY(-delta)
+                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                    .setListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            to.requireViewById(R.id.volume_indeterminate_progress).setVisibility(
+                                    View.VISIBLE);
+                        }
+                    });
+            // Animation for seek bar
+            fromSeekBar.animate()
+                    .alpha(0)
+                    .setDuration(ANIM_DURATION)
+                    .setListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            final TextView fromTitleText = from.requireViewById(
+                                    R.id.two_line_title);
+                            fromTitleText.setTypeface(Typeface.create(FONT_TITLE, Typeface.NORMAL));
+                            fromTitleText.animate()
+                                    .setDuration(ANIM_DURATION)
+                                    .translationY(delta)
+                                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                                    .setListener(new AnimatorListenerAdapter() {
+                                        @Override
+                                        public void onAnimationEnd(Animator animation) {
+                                            mIsAnimating = false;
+                                            notifyDataSetChanged();
+                                        }
+                                    });
+                        }
+                    });
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index ebca8a7..3b82999 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -170,7 +170,7 @@
             mHeaderSubtitle.setText(subTitle);
             mHeaderTitle.setGravity(Gravity.NO_GRAVITY);
         }
-        if (!mAdapter.isDragging()) {
+        if (!mAdapter.isDragging() && !mAdapter.isAnimating()) {
             mAdapter.notifyDataSetChanged();
         }
         // Show when remote media session is available
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 6d6d6cb..1538e9e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -207,6 +207,7 @@
     private boolean mUseMLModel;
     private float mMLModelThreshold;
     private String mPackageName;
+    private float mMLResults;
 
     private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
 
@@ -531,10 +532,10 @@
             new long[]{(long) y},
         };
 
-        final float results = mBackGestureTfClassifierProvider.predict(featuresVector);
-        if (results == -1) return -1;
+        mMLResults = mBackGestureTfClassifierProvider.predict(featuresVector);
+        if (mMLResults == -1) return -1;
 
-        return results >= mMLModelThreshold ? 1 : 0;
+        return mMLResults >= mMLModelThreshold ? 1 : 0;
     }
 
     private boolean isWithinTouchRegion(int x, int y) {
@@ -611,7 +612,8 @@
                 (int) mDownPoint.x, (int) mDownPoint.y,
                 (int) mEndPoint.x, (int) mEndPoint.y,
                 mEdgeWidthLeft + mLeftInset,
-                mDisplaySize.x - (mEdgeWidthRight + mRightInset));
+                mDisplaySize.x - (mEdgeWidthRight + mRightInset),
+                mUseMLModel ? mMLResults : -2);
     }
 
     private void onMotionEvent(MotionEvent ev) {
@@ -621,6 +623,7 @@
             // either the bouncer is showing or the notification panel is hidden
             mInputEventReceiver.setBatchingEnabled(false);
             mIsOnLeftEdge = ev.getX() <= mEdgeWidthLeft + mLeftInset;
+            mMLResults = 0;
             mLogGesture = false;
             mInRejectedExclusion = false;
             mAllowGesture = !mDisabledForQuickstep && mIsBackGestureAllowed
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index b0fcdf8..98e5794 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -262,10 +262,10 @@
 
         if (!PipUtils.hasSystemFeature(context)) {
             Log.w(TAG, "Device not support PIP feature");
-            return;
+        } else {
+            mTaskOrganizer.addListener(this, WINDOWING_MODE_PINNED);
+            displayController.addDisplayWindowListener(this);
         }
-        mTaskOrganizer.addListener(this, WINDOWING_MODE_PINNED);
-        displayController.addDisplayWindowListener(this);
     }
 
     public Handler getUpdateHandler() {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
index 6ac4e4cb..d27f257 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
@@ -219,41 +219,38 @@
             PipTaskOrganizer pipTaskOrganizer,
             WindowManagerShellWrapper windowManagerShellWrapper
     ) {
-        if (mInitialized) {
-            return;
-        }
+        if (!mInitialized) {
+            mInitialized = true;
+            mContext = context;
+            mPipNotification = new PipNotification(context, this);
+            mPipBoundsHandler = pipBoundsHandler;
+            // Ensure that we have the display info in case we get calls to update the bounds
+            // before the listener calls back
+            final DisplayInfo displayInfo = new DisplayInfo();
+            context.getDisplay().getDisplayInfo(displayInfo);
+            mPipBoundsHandler.onDisplayInfoChanged(displayInfo);
 
-        mInitialized = true;
-        mContext = context;
-        mPipNotification = new PipNotification(context, this);
-        mPipBoundsHandler = pipBoundsHandler;
-        // Ensure that we have the display info in case we get calls to update the bounds before the
-        // listener calls back
-        final DisplayInfo displayInfo = new DisplayInfo();
-        context.getDisplay().getDisplayInfo(displayInfo);
-        mPipBoundsHandler.onDisplayInfoChanged(displayInfo);
+            mResizeAnimationDuration = context.getResources()
+                    .getInteger(R.integer.config_pipResizeAnimationDuration);
+            mPipTaskOrganizer = pipTaskOrganizer;
+            mPipTaskOrganizer.registerPipTransitionCallback(this);
+            mActivityTaskManager = ActivityTaskManager.getService();
+            IntentFilter intentFilter = new IntentFilter();
+            intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
+            mContext.registerReceiver(mBroadcastReceiver, intentFilter, UserHandle.USER_ALL);
 
-        mResizeAnimationDuration = context.getResources()
-                .getInteger(R.integer.config_pipResizeAnimationDuration);
-        mPipTaskOrganizer = pipTaskOrganizer;
-        mPipTaskOrganizer.registerPipTransitionCallback(this);
-        mActivityTaskManager = ActivityTaskManager.getService();
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
-        mContext.registerReceiver(mBroadcastReceiver, intentFilter, UserHandle.USER_ALL);
+            // Initialize the last orientation and apply the current configuration
+            Configuration initialConfig = mContext.getResources().getConfiguration();
+            mLastOrientation = initialConfig.orientation;
+            loadConfigurationsAndApply(initialConfig);
 
-        // Initialize the last orientation and apply the current configuration
-        Configuration initialConfig = mContext.getResources().getConfiguration();
-        mLastOrientation = initialConfig.orientation;
-        loadConfigurationsAndApply(initialConfig);
-
-        mMediaSessionManager =
-                (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
-        mWindowManagerShellWrapper = windowManagerShellWrapper;
-        try {
-            mWindowManagerShellWrapper.addPinnedStackListener(mPinnedStackListener);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to register pinned stack listener", e);
+            mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class);
+            mWindowManagerShellWrapper = windowManagerShellWrapper;
+            try {
+                mWindowManagerShellWrapper.addPinnedStackListener(mPinnedStackListener);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to register pinned stack listener", e);
+            }
         }
     }
 
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/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 500de2d..9320499 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.stack;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
 import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
 import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
 import static com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.ANCHOR_SCROLLING;
@@ -73,6 +74,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.keyguard.KeyguardSliceView;
 import com.android.settingslib.Utils;
@@ -97,7 +99,6 @@
 import com.android.systemui.statusbar.notification.ShadeViewRefactor;
 import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -260,6 +261,7 @@
     private boolean mDismissAllInProgress;
     private boolean mFadeNotificationsOnDismiss;
     private FooterDismissListener mFooterDismissListener;
+    private boolean mFlingAfterUpEvent;
 
     /**
      * Was the scroller scrolled to the top when the down motion was observed?
@@ -3789,6 +3791,13 @@
                             if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
                                 float currentOverScrollTop = getCurrentOverScrollAmount(true);
                                 if (currentOverScrollTop == 0.0f || initialVelocity > 0) {
+                                    mFlingAfterUpEvent = true;
+                                    setFinishScrollingCallback(() -> {
+                                        mFlingAfterUpEvent = false;
+                                        InteractionJankMonitor.getInstance()
+                                                .end(CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
+                                        setFinishScrollingCallback(null);
+                                    });
                                     fling(-initialVelocity);
                                 } else {
                                     onOverScrollFling(false, initialVelocity);
@@ -3840,6 +3849,10 @@
         return true;
     }
 
+    boolean isFlingAfterUpEvent() {
+        return mFlingAfterUpEvent;
+    }
+
     @ShadeViewRefactor(RefactorComponent.INPUT)
     protected boolean isInsideQsContainer(MotionEvent ev) {
         return ev.getY() < mQsContainer.getBottom();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 703c214..6820819 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -19,6 +19,7 @@
 import static android.service.notification.NotificationStats.DISMISSAL_SHADE;
 import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
 import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnEmptySpaceClickListener;
@@ -47,6 +48,7 @@
 import android.widget.FrameLayout;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
@@ -1556,6 +1558,14 @@
             if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
                 mView.setCheckForLeaveBehind(true);
             }
+
+            // When swiping directly on the NSSL, this would only get an onTouchEvent.
+            // We log any touches other than down, which will be captured by onTouchEvent.
+            // In the intercept we only start tracing when it's not a down (otherwise that down
+            // would be duplicated when intercepted).
+            if (scrollWantsIt && ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
+                InteractionJankMonitor.getInstance().begin(CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
+            }
             return swipeWantsIt || scrollWantsIt || expandWantsIt;
         }
 
@@ -1611,7 +1621,32 @@
             if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
                 mView.setCheckForLeaveBehind(true);
             }
+            traceJankOnTouchEvent(ev.getActionMasked(), scrollerWantsIt);
             return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt;
         }
+
+        private void traceJankOnTouchEvent(int action, boolean scrollerWantsIt) {
+            // Handle interaction jank monitor cases.
+            switch (action) {
+                case MotionEvent.ACTION_DOWN:
+                    if (scrollerWantsIt) {
+                        InteractionJankMonitor.getInstance()
+                                .begin(CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
+                    }
+                    break;
+                case MotionEvent.ACTION_UP:
+                    if (scrollerWantsIt && !mView.isFlingAfterUpEvent()) {
+                        InteractionJankMonitor.getInstance()
+                                .end(CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
+                    }
+                    break;
+                case MotionEvent.ACTION_CANCEL:
+                    if (scrollerWantsIt) {
+                        InteractionJankMonitor.getInstance()
+                                .cancel(CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
+                    }
+                    break;
+            }
+        }
     }
 }
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/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index cd9cc07..3f636ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -18,6 +18,8 @@
 
 import static android.view.View.GONE;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE;
 import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
@@ -62,6 +64,7 @@
 import android.widget.TextView;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
@@ -1139,6 +1142,7 @@
                     onQsExpansionStarted();
                     mInitialHeightOnTouch = mQsExpansionHeight;
                     mQsTracking = true;
+                    traceQsJank(true /* startTracing */, false /* wasCancelled */);
                     mNotificationStackScrollLayoutController.cancelLongPress();
                 }
                 break;
@@ -1170,6 +1174,7 @@
                         && shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, h)) {
                     mView.getParent().requestDisallowInterceptTouchEvent(true);
                     mQsTracking = true;
+                    traceQsJank(true /* startTracing */, false /* wasCancelled */);
                     onQsExpansionStarted();
                     notifyExpandingFinished();
                     mInitialHeightOnTouch = mQsExpansionHeight;
@@ -1202,6 +1207,19 @@
                 && x < stackScrollerX + mNotificationStackScrollLayoutController.getWidth();
     }
 
+    private void traceQsJank(boolean startTracing, boolean wasCancelled) {
+        InteractionJankMonitor monitor = InteractionJankMonitor.getInstance();
+        if (startTracing) {
+            monitor.begin(CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE);
+        } else {
+            if (wasCancelled) {
+                monitor.cancel(CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE);
+            } else {
+                monitor.end(CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE);
+            }
+        }
+    }
+
     private void initDownStates(MotionEvent event) {
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
             mOnlyAffordanceInThisMotion = false;
@@ -1315,9 +1333,9 @@
         final int action = event.getActionMasked();
         if (action == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
                 && mBarState != KEYGUARD && !mQsExpanded && mQsExpansionEnabled) {
-
             // Down in the empty area while fully expanded - go to QS.
             mQsTracking = true;
+            traceQsJank(true /* startTracing */, false /* wasCancelled */);
             mConflictingQsExpansionGesture = true;
             onQsExpansionStarted();
             mInitialHeightOnTouch = mQsExpansionHeight;
@@ -1405,6 +1423,7 @@
             return;
         }
         mExpectingSynthesizedDown = true;
+        InteractionJankMonitor.getInstance().begin(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
         onTrackingStarted();
         updatePanelExpanded();
     }
@@ -1474,6 +1493,7 @@
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
                 mQsTracking = true;
+                traceQsJank(true /* startTracing */, false /* wasCancelled */);
                 mInitialTouchY = y;
                 mInitialTouchX = x;
                 onQsExpansionStarted();
@@ -1513,6 +1533,9 @@
                 if (fraction != 0f || y >= mInitialTouchY) {
                     flingQsWithCurrentVelocity(y,
                             event.getActionMasked() == MotionEvent.ACTION_CANCEL);
+                } else {
+                    traceQsJank(false /* startTracing */,
+                            event.getActionMasked() == MotionEvent.ACTION_CANCEL);
                 }
                 if (mQsVelocityTracker != null) {
                     mQsVelocityTracker.recycle();
@@ -1893,7 +1916,7 @@
      * @see #flingSettings(float, int, Runnable, boolean)
      */
     public void flingSettings(float vel, int type) {
-        flingSettings(vel, type, null, false /* isClick */);
+        flingSettings(vel, type, null /* onFinishRunnable */, false /* isClick */);
     }
 
     /**
@@ -1923,6 +1946,7 @@
             if (onFinishRunnable != null) {
                 onFinishRunnable.run();
             }
+            traceQsJank(false /* startTracing */, type != FLING_EXPAND /* wasCancelled */);
             return;
         }
 
@@ -1947,12 +1971,18 @@
             setQsExpansion((Float) animation.getAnimatedValue());
         });
         animator.addListener(new AnimatorListenerAdapter() {
+            private boolean mIsCanceled;
             @Override
             public void onAnimationStart(Animator animation) {
                 notifyExpandingStarted();
             }
 
             @Override
+            public void onAnimationCancel(Animator animation) {
+                mIsCanceled = true;
+            }
+
+            @Override
             public void onAnimationEnd(Animator animation) {
                 mAnimatingQS = false;
                 notifyExpandingFinished();
@@ -1961,6 +1991,7 @@
                 if (onFinishRunnable != null) {
                     onFinishRunnable.run();
                 }
+                traceQsJank(false /* startTracing */, mIsCanceled /* wasCancelled */);
             }
         });
         // Let's note that we're animating QS. Moving the animator here will cancel it immediately,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
index bc80a1a..a4fc3a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
@@ -49,6 +49,7 @@
 import android.view.WindowInsetsController;
 import android.widget.FrameLayout;
 
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.view.FloatingActionMode;
 import com.android.internal.widget.FloatingToolbar;
 import com.android.systemui.R;
@@ -145,6 +146,7 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         setWillNotDraw(!DEBUG);
+        InteractionJankMonitor.getInstance().init(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 6fa99ba..5a01f47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
 import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
 import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
 import static com.android.systemui.classifier.Classifier.UNLOCK;
@@ -40,6 +41,7 @@
 import android.view.ViewTreeObserver;
 import android.view.animation.Interpolator;
 
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
 import com.android.systemui.DejankUtils;
@@ -109,6 +111,7 @@
     private boolean mMotionAborted;
     private boolean mUpwardsWhenThresholdReached;
     private boolean mAnimatingOnDown;
+    private boolean mHandlingPointerUp;
 
     private ValueAnimator mHeightAnimator;
     private ObjectAnimator mPeekAnimator;
@@ -356,6 +359,9 @@
 
     protected void startExpandMotion(float newX, float newY, boolean startTracking,
             float expandedHeight) {
+        if (!mHandlingPointerUp) {
+            InteractionJankMonitor.getInstance().begin(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+        }
         mInitialOffsetOnTouch = expandedHeight;
         mInitialTouchY = newY;
         mInitialTouchX = newX;
@@ -571,6 +577,7 @@
             target = getMaxPanelHeight() - getClearAllHeightWithPadding();
         }
         if (target == mExpandedHeight || getOverExpansionAmount() > 0f && expand) {
+            InteractionJankMonitor.getInstance().end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
             notifyExpandingFinished();
             return;
         }
@@ -622,7 +629,12 @@
                 }
                 setAnimator(null);
                 if (!mCancelled) {
+                    InteractionJankMonitor.getInstance()
+                            .end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
                     notifyExpandingFinished();
+                } else {
+                    InteractionJankMonitor.getInstance()
+                            .cancel(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
                 }
                 notifyBarPanelExpansionChanged();
             }
@@ -1272,7 +1284,9 @@
                         final float newY = event.getY(newIndex);
                         final float newX = event.getX(newIndex);
                         mTrackingPointer = event.getPointerId(newIndex);
+                        mHandlingPointerUp = true;
                         startExpandMotion(newX, newY, true /* startTracking */, mExpandedHeight);
+                        mHandlingPointerUp = false;
                     }
                     break;
                 case MotionEvent.ACTION_POINTER_DOWN:
@@ -1330,6 +1344,12 @@
                 case MotionEvent.ACTION_CANCEL:
                     addMovement(event);
                     endMotionEvent(event, x, y, false /* forceCancel */);
+                    InteractionJankMonitor monitor = InteractionJankMonitor.getInstance();
+                    if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+                        monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+                    } else {
+                        monitor.cancel(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+                    }
                     break;
             }
             return !mGestureWaitForTouchSlop || mTracking;
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/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 0e376bd..2d460aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -192,6 +192,7 @@
     public void onItemClick_clickDevice_verifyConnectDevice() {
         assertThat(mMediaDevice2.getState()).isEqualTo(
                 LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
+        mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
         mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
         mViewHolder.mFrameLayout.performClick();
 
diff --git a/packages/overlays/IconShapePebbleOverlay/res/values/config.xml b/packages/overlays/IconShapePebbleOverlay/res/values/config.xml
index 2465fe0..e7eeb30 100644
--- a/packages/overlays/IconShapePebbleOverlay/res/values/config.xml
+++ b/packages/overlays/IconShapePebbleOverlay/res/values/config.xml
@@ -18,7 +18,7 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. -->
-    <string name="config_icon_mask" translatable="false">"MM55,0 C25,0 0,25 0,50 0,78 28,100 55,100 85,100 100,85 100,58 100,30 86,0 55,0 Z"</string>
+    <string name="config_icon_mask" translatable="false">"M55,0 C25,0 0,25 0,50 0,78 28,100 55,100 85,100 100,85 100,58 100,30 86,0 55,0 Z"</string>
     <!-- Flag indicating whether round icons should be parsed from the application manifest. -->
     <bool name="config_useRoundIcon">false</bool>
     <!-- Corner radius of system dialogs -->
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/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 4a4c39d..cc8a330 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -46,6 +46,7 @@
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
 import android.hardware.input.InputManagerInternal;
+import android.hardware.input.InputManagerInternal.LidSwitchCallback;
 import android.hardware.input.KeyboardLayout;
 import android.hardware.input.TouchCalibration;
 import android.media.AudioManager;
@@ -189,6 +190,10 @@
     private Map<IBinder, VibratorToken> mVibratorTokens = new ArrayMap<IBinder, VibratorToken>();
     private int mNextVibratorTokenValue;
 
+    // State for lid switch
+    private final Object mLidSwitchLock = new Object();
+    private List<LidSwitchCallback> mLidSwitchCallbacks = new ArrayList<>();
+
     // State for the currently installed input filter.
     final Object mInputFilterLock = new Object();
     IInputFilter mInputFilter; // guarded by mInputFilterLock
@@ -330,6 +335,9 @@
     public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
     public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE;
 
+    /** Indicates an open state for the lid switch. */
+    public static final int SW_STATE_LID_OPEN = 0;
+
     /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
     final boolean mUseDevInputEventForAudioJack;
 
@@ -353,13 +361,33 @@
     }
 
     public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
+        if (mWindowManagerCallbacks != null) {
+            unregisterLidSwitchCallbackInternal(mWindowManagerCallbacks);
+        }
         mWindowManagerCallbacks = callbacks;
+        registerLidSwitchCallbackInternal(mWindowManagerCallbacks);
     }
 
     public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
         mWiredAccessoryCallbacks = callbacks;
     }
 
+    void registerLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) {
+        boolean lidOpen;
+        synchronized (mLidSwitchLock) {
+            mLidSwitchCallbacks.add(callback);
+            lidOpen = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID)
+                    == SW_STATE_LID_OPEN;
+        }
+        callback.notifyLidSwitchChanged(0 /* whenNanos */, lidOpen);
+    }
+
+    void unregisterLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) {
+        synchronized (mLidSwitchLock) {
+            mLidSwitchCallbacks.remove(callback);
+        }
+    }
+
     public void start() {
         Slog.i(TAG, "Starting input manager");
         nativeStart(mPtr);
@@ -1934,6 +1962,7 @@
         synchronized (mInputFilterLock) { }
         synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
         synchronized (mGestureMonitorPidsLock) { /* Test if blocked by gesture monitor pids lock */}
+        synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ }
         nativeMonitor(mPtr);
     }
 
@@ -1964,7 +1993,15 @@
 
         if ((switchMask & SW_LID_BIT) != 0) {
             final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
-            mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
+
+            ArrayList<LidSwitchCallback> callbacksCopy;
+            synchronized (mLidSwitchLock) {
+                callbacksCopy = new ArrayList<>(mLidSwitchCallbacks);
+            }
+            for (int i = 0; i < callbacksCopy.size(); i++) {
+                LidSwitchCallback callbacks = callbacksCopy.get(i);
+                callbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
+            }
         }
 
         if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
@@ -2263,20 +2300,13 @@
     /**
      * Callback interface implemented by the Window Manager.
      */
-    public interface WindowManagerCallbacks {
+    public interface WindowManagerCallbacks extends LidSwitchCallback {
         /**
          * This callback is invoked when the confuguration changes.
          */
         public void notifyConfigurationChanged();
 
         /**
-         * This callback is invoked when the lid switch changes state.
-         * @param whenNanos the time when the change occurred
-         * @param lidOpen true if the lid is open
-         */
-        public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
-
-        /**
          * This callback is invoked when the camera lens cover switch changes state.
          * @param whenNanos the time when the change occurred
          * @param lensCovered true is the lens is covered
@@ -2603,6 +2633,16 @@
                 @NonNull IBinder toChannelToken) {
             return InputManagerService.this.transferTouchFocus(fromChannelToken, toChannelToken);
         }
+
+        @Override
+        public void registerLidSwitchCallback(LidSwitchCallback callbacks) {
+            registerLidSwitchCallbackInternal(callbacks);
+        }
+
+        @Override
+        public void unregisterLidSwitchCallback(LidSwitchCallback callbacks) {
+            unregisterLidSwitchCallbackInternal(callbacks);
+        }
     }
 
     @Override
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/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3e7304b..1ae1681 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6214,8 +6214,11 @@
 
         synchronized (mLock) {
             final AndroidPackage p = mPackages.get(packageName);
+            if (p == null) {
+                return false;
+            }
             final PackageSetting ps = getPackageSetting(p.getPackageName());
-            if (p == null || ps == null) {
+            if (ps == null) {
                 return false;
             }
             final int callingUid = Binder.getCallingUid();
@@ -25949,6 +25952,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/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6792430..1cb610f 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:
@@ -7864,7 +7867,7 @@
         InsetUtils.addInsets(insets, getLetterboxInsets());
         return new RemoteAnimationTarget(task.mTaskId, record.getMode(),
                 record.mAdapter.mCapturedLeash, !fillsParent(),
-                mainWindow.mWinAnimator.mLastClipRect, insets,
+                new Rect(), insets,
                 getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds,
                 record.mAdapter.mStackBounds, task.getWindowConfiguration(),
                 false /*isNotInRecents*/,
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..0402140 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -666,7 +666,7 @@
      */
     CompatModePackages mCompatModePackages;
 
-    private FontScaleSettingObserver mFontScaleSettingObserver;
+    private SettingObserver mSettingsObserver;
 
     WindowOrganizerController mWindowOrganizerController;
     TaskOrganizerController mTaskOrganizerController;
@@ -676,16 +676,19 @@
 
     private int mDeviceOwnerUid = Process.INVALID_UID;
 
-    private final class FontScaleSettingObserver extends ContentObserver {
+    private final class SettingObserver extends ContentObserver {
         private final Uri mFontScaleUri = Settings.System.getUriFor(FONT_SCALE);
         private final Uri mHideErrorDialogsUri = Settings.Global.getUriFor(HIDE_ERROR_DIALOGS);
+        private final Uri mForceBoldTextUri = Settings.Secure.getUriFor(
+                Settings.Secure.FORCE_BOLD_TEXT);
 
-        public FontScaleSettingObserver() {
+        SettingObserver() {
             super(mH);
             final ContentResolver resolver = mContext.getContentResolver();
             resolver.registerContentObserver(mFontScaleUri, false, this, UserHandle.USER_ALL);
             resolver.registerContentObserver(mHideErrorDialogsUri, false, this,
                     UserHandle.USER_ALL);
+            resolver.registerContentObserver(mForceBoldTextUri, false, this, UserHandle.USER_ALL);
         }
 
         @Override
@@ -698,6 +701,8 @@
                     synchronized (mGlobalLock) {
                         updateShouldShowDialogsLocked(getGlobalConfiguration());
                     }
+                } else if (mForceBoldTextUri.equals(uri)) {
+                    updateForceBoldTextIfNeeded(userId);
                 }
             }
         }
@@ -757,7 +762,7 @@
     }
 
     public void installSystemProviders() {
-        mFontScaleSettingObserver = new FontScaleSettingObserver();
+        mSettingsObserver = new SettingObserver();
     }
 
     public void retrieveSettings(ContentResolver resolver) {
@@ -5362,6 +5367,20 @@
         }
     }
 
+    private void updateForceBoldTextIfNeeded(@UserIdInt int userId) {
+        final int forceBoldTextConfig = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.FORCE_BOLD_TEXT, Configuration.FORCE_BOLD_TEXT_UNDEFINED, userId);
+        synchronized (mGlobalLock) {
+            if (getGlobalConfiguration().forceBoldText == forceBoldTextConfig) {
+                return;
+            }
+            final Configuration configuration =
+                    mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY);
+            configuration.forceBoldText = forceBoldTextConfig;
+            updatePersistentConfiguration(configuration, userId);
+        }
+    }
+
     // Actually is sleeping or shutting down or whatever else in the future
     // is an inactive state.
     boolean isSleepingOrShuttingDownLocked() {
@@ -7187,16 +7206,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/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index b50cb4c..42a20ff 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -929,7 +929,7 @@
                     ? MODE_OPENING
                     : MODE_CLOSING;
             mTarget = new RemoteAnimationTarget(mTask.mTaskId, mode, mCapturedLeash,
-                    !topApp.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
+                    !topApp.fillsParent(), new Rect(),
                     insets, mTask.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top),
                     mLocalBounds, mBounds, mTask.getWindowConfiguration(),
                     mIsRecentTaskInvisible, null, null);
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/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/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7d293dd..d434bf9 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";
@@ -2423,8 +2423,8 @@
                 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             }
             if (winAnimator.mSurfaceController != null) {
-                outSurfaceSize.set(winAnimator.mSurfaceController.getWidth(),
-                                         winAnimator.mSurfaceController.getHeight());
+                win.calculateSurfaceBounds(win.getAttrs(), mTmpRect);
+                outSurfaceSize.set(mTmpRect.width(), mTmpRect.height());
             }
             getInsetsSourceControls(win, outActiveControls);
         }
@@ -8247,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 422e6f2..ad28177 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1409,15 +1409,14 @@
         // Add a window that is using blastSync to the resizing list if it hasn't been reported
         // already. This because the window is waiting on a finishDrawing from the client.
         if (didFrameInsetsChange
-                || winAnimator.mSurfaceResized
                 || configChanged
                 || dragResizingChanged
                 || mReportOrientationChanged
                 || shouldSendRedrawForSync()) {
             ProtoLog.v(WM_DEBUG_RESIZE,
-                        "Resize reasons for w=%s:  %s surfaceResized=%b configChanged=%b "
+                        "Resize reasons for w=%s:  %s configChanged=%b "
                                 + "dragResizingChanged=%b reportOrientationChanged=%b",
-                        this, mWindowFrames.getInsetsChangedInfo(), winAnimator.mSurfaceResized,
+                        this, mWindowFrames.getInsetsChangedInfo(),
                         configChanged, dragResizingChanged, mReportOrientationChanged);
 
             // If it's a dead window left on screen, and the configuration changed, there is nothing
@@ -3633,7 +3632,6 @@
         // that may cause WINDOW_FREEZE_TIMEOUT because resizing the client keeps failing.
         mReportOrientationChanged = false;
         mDragResizingChangeReported = true;
-        mWinAnimator.mSurfaceResized = false;
         mWindowFrames.resetInsetsChanged();
 
         final MergedConfiguration mergedConfiguration = mLastReportedConfiguration;
@@ -4952,93 +4950,6 @@
     }
 
     /**
-     * Calculate the window crop according to system decor policy. In general this is
-     * the system decor rect (see #calculateSystemDecorRect), but we also have some
-     * special cases. This rectangle is in screen space.
-     */
-    void calculatePolicyCrop(Rect policyCrop) {
-        final DisplayContent displayContent = getDisplayContent();
-
-        if (!displayContent.isDefaultDisplay && !displayContent.supportsSystemDecorations()) {
-            // On a different display there is no system decor. Crop the window
-            // by the screen boundaries.
-            final DisplayInfo displayInfo = getDisplayInfo();
-            policyCrop.set(0, 0, mWindowFrames.mCompatFrame.width(),
-                    mWindowFrames.mCompatFrame.height());
-            policyCrop.intersect(-mWindowFrames.mCompatFrame.left, -mWindowFrames.mCompatFrame.top,
-                    displayInfo.logicalWidth - mWindowFrames.mCompatFrame.left,
-                    displayInfo.logicalHeight - mWindowFrames.mCompatFrame.top);
-        } else if (skipDecorCrop()) {
-            // Windows without policy decor aren't cropped.
-            policyCrop.set(0, 0, mWindowFrames.mCompatFrame.width(),
-                    mWindowFrames.mCompatFrame.height());
-        } else {
-            // Crop to the system decor specified by policy.
-            calculateSystemDecorRect(policyCrop);
-        }
-    }
-
-    /**
-     * The system decor rect is the region of the window which is not covered
-     * by system decorations.
-     */
-    private void calculateSystemDecorRect(Rect systemDecorRect) {
-        final Rect decorRect = mWindowFrames.mDecorFrame;
-        final int width = mWindowFrames.mFrame.width();
-        final int height = mWindowFrames.mFrame.height();
-
-        final int left = mWindowFrames.mFrame.left;
-        final int top = mWindowFrames.mFrame.top;
-
-        // Initialize the decor rect to the entire frame.
-        if (isDockedResizing()) {
-            // If we are resizing with the divider, the task bounds might be smaller than the
-            // stack bounds. The system decor is used to clip to the task bounds, which we don't
-            // want in this case in order to avoid holes.
-            //
-            // We take care to not shrink the width, for surfaces which are larger than
-            // the display region. Of course this area will not eventually be visible
-            // but if we truncate the width now, we will calculate incorrectly
-            // when adjusting to the stack bounds.
-            final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
-            systemDecorRect.set(0, 0,
-                    Math.max(width, displayInfo.logicalWidth),
-                    Math.max(height, displayInfo.logicalHeight));
-        } else {
-            systemDecorRect.set(0, 0, width, height);
-        }
-
-        // If a freeform window is animating from a position where it would be cutoff, it would be
-        // cutoff during the animation. We don't want that, so for the duration of the animation
-        // we ignore the decor cropping and depend on layering to position windows correctly.
-
-        // We also ignore cropping when the window is currently being drag resized in split screen
-        // to prevent issues with the crop for screenshot.
-        final boolean cropToDecor =
-                !(inFreeformWindowingMode() && isAnimatingLw()) && !isDockedResizing();
-        if (cropToDecor) {
-            // Intersect with the decor rect, offsetted by window position.
-            systemDecorRect.intersect(decorRect.left - left, decorRect.top - top,
-                    decorRect.right - left, decorRect.bottom - top);
-        }
-
-        // If size compatibility is being applied to the window, the
-        // surface is scaled relative to the screen.  Also apply this
-        // scaling to the crop rect.  We aren't using the standard rect
-        // scale function because we want to round things to make the crop
-        // always round to a larger rect to ensure we don't crop too
-        // much and hide part of the window that should be seen.
-        if (mInvGlobalScale != 1.0f && inSizeCompatMode()) {
-            final float scale = mInvGlobalScale;
-            systemDecorRect.left = (int) (systemDecorRect.left * scale - 0.5f);
-            systemDecorRect.top = (int) (systemDecorRect.top * scale - 0.5f);
-            systemDecorRect.right = (int) ((systemDecorRect.right + 1) * scale - 0.5f);
-            systemDecorRect.bottom = (int) ((systemDecorRect.bottom + 1) * scale - 0.5f);
-        }
-
-    }
-
-    /**
      * Expand the given rectangle by this windows surface insets. This
      * takes you from the 'window size' to the 'surface size'.
      * The surface insets are positive in each direction, so we inset by
@@ -5095,9 +5006,10 @@
             // on the new one. This prevents blinking when we change elevation of freeform and
             // pinned windows.
             if (!mWinAnimator.tryChangeFormatInPlaceLocked()) {
-                mWinAnimator.preserveSurfaceLocked();
+                mWinAnimator.preserveSurfaceLocked(getPendingTransaction());
                 result |= RELAYOUT_RES_SURFACE_CHANGED
                         | RELAYOUT_RES_FIRST_TIME;
+                scheduleAnimation();
             }
         }
 
@@ -5113,9 +5025,10 @@
             // to preserve and destroy windows which are attached to another, they
             // will keep their surface and its size may change over time.
             if (mHasSurface && !isChildWindow()) {
-                mWinAnimator.preserveSurfaceLocked();
+                mWinAnimator.preserveSurfaceLocked(getPendingTransaction());
                 result |= RELAYOUT_RES_SURFACE_CHANGED |
                     RELAYOUT_RES_FIRST_TIME;
+                scheduleAnimation();
             }
         }
         final boolean freeformResizing = isDragResizing()
@@ -5939,4 +5852,37 @@
     void requestRedrawForSync() {
         mRedrawForSyncReported = false;
     }
+
+    void calculateSurfaceBounds(WindowManager.LayoutParams attrs, Rect outSize) {
+        outSize.setEmpty();
+        if ((attrs.flags & FLAG_SCALED) != 0) {
+            // For a scaled surface, we always want the requested size.
+            outSize.right = mRequestedWidth;
+            outSize.bottom = mRequestedHeight;
+        } else {
+            // When we're doing a drag-resizing, request a surface that's fullscreen size,
+            // so that we don't need to reallocate during the process. This also prevents
+            // buffer drops due to size mismatch.
+            if (isDragResizing()) {
+                final DisplayInfo displayInfo = getDisplayInfo();
+                outSize.right = displayInfo.logicalWidth;
+                outSize.bottom = displayInfo.logicalHeight;
+            } else {
+                getCompatFrameSize(outSize);
+            }
+        }
+
+        // This doesn't necessarily mean that there is an error in the system. The sizes might be
+        // incorrect, because it is before the first layout or draw.
+        if (outSize.width() < 1) {
+            outSize.right = 1;
+        }
+        if (outSize.height() < 1) {
+            outSize.bottom = 1;
+        }
+
+        // Adjust for surface insets.
+        outSize.inset(-attrs.surfaceInsets.left, -attrs.surfaceInsets.top,
+                -attrs.surfaceInsets.right, -attrs.surfaceInsets.bottom);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 029c158..2ace23f 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -121,12 +121,6 @@
 
     boolean mAnimationIsEntrance;
 
-    /**
-     * Set when we have changed the size of the surface, to know that
-     * we must tell them application to resize (and thus redraw itself).
-     */
-    boolean mSurfaceResized;
-
     WindowSurfaceController mSurfaceController;
     private WindowSurfaceController mPendingDestroySurface;
 
@@ -141,9 +135,6 @@
     float mAlpha = 0;
     float mLastAlpha = 0;
 
-    Rect mTmpClipRect = new Rect();
-    Rect mLastClipRect = new Rect();
-    Rect mLastFinalClipRect = new Rect();
     Rect mTmpStackBounds = new Rect();
     private Rect mTmpAnimatingBounds = new Rect();
     private Rect mTmpSourceBounds = new Rect();
@@ -358,7 +349,7 @@
         return result;
     }
 
-    void preserveSurfaceLocked() {
+    void preserveSurfaceLocked(SurfaceControl.Transaction t) {
         if (mDestroyPreservedSurfaceUponRedraw) {
             // This could happen when switching the surface mode very fast. For example,
             // we preserved a surface when dragResizing changed to true. Then before the
@@ -385,7 +376,7 @@
             // Our SurfaceControl is always at layer 0 within the parent Surface managed by
             // window-state. We want this old Surface to stay on top of the new one
             // until we do the swap, so we place it at a positive layer.
-            mSurfaceController.mSurfaceControl.setLayer(PRESERVED_SURFACE_LAYER);
+            t.setLayer(mSurfaceController.getClientViewRootSurface(), PRESERVED_SURFACE_LAYER);
         }
         mDestroyPreservedSurfaceUponRedraw = true;
         mSurfaceDestroyDeferred = true;
@@ -462,7 +453,8 @@
             flags |= SurfaceControl.SKIP_SCREENSHOT;
         }
 
-        calculateSurfaceBounds(w, attrs, mTmpSize);
+        w.calculateSurfaceBounds(attrs, mTmpSize);
+
         final int width = mTmpSize.width();
         final int height = mTmpSize.height();
 
@@ -474,9 +466,6 @@
                     + " format=" + attrs.format + " flags=" + flags);
         }
 
-        // We may abort, so initialize to defaults.
-        mLastClipRect.set(0, 0, 0, 0);
-
         // Set up surface control with initial size.
         try {
 
@@ -538,40 +527,6 @@
         return mSurfaceController;
     }
 
-    private void calculateSurfaceBounds(WindowState w, LayoutParams attrs, Rect outSize) {
-        outSize.setEmpty();
-        if ((attrs.flags & FLAG_SCALED) != 0) {
-            // For a scaled surface, we always want the requested size.
-            outSize.right = w.mRequestedWidth;
-            outSize.bottom = w.mRequestedHeight;
-        } else {
-            // When we're doing a drag-resizing, request a surface that's fullscreen size,
-            // so that we don't need to reallocate during the process. This also prevents
-            // buffer drops due to size mismatch.
-            if (w.isDragResizing()) {
-                final DisplayInfo displayInfo = w.getDisplayInfo();
-                outSize.right = displayInfo.logicalWidth;
-                outSize.bottom = displayInfo.logicalHeight;
-            } else {
-                w.getCompatFrameSize(outSize);
-            }
-        }
-
-        // Something is wrong and SurfaceFlinger will not like this, try to revert to reasonable
-        // values. This doesn't necessarily mean that there is an error in the system. The sizes
-        // might be incorrect, because it is before the first layout or draw.
-        if (outSize.width() < 1) {
-            outSize.right = 1;
-        }
-        if (outSize.height() < 1) {
-            outSize.bottom = 1;
-        }
-
-        // Adjust for surface insets.
-        outSize.inset(-attrs.surfaceInsets.left, -attrs.surfaceInsets.top,
-                -attrs.surfaceInsets.right, -attrs.surfaceInsets.bottom);
-    }
-
     boolean hasSurface() {
         return mSurfaceController != null && mSurfaceController.hasSurface();
     }
@@ -680,77 +635,6 @@
         mDsDy = mWin.mGlobalScale;
     }
 
-    /**
-     * Calculate the window-space crop rect and fill clipRect.
-     * @return true if clipRect has been filled otherwise, no window space crop should be applied.
-     */
-    private boolean calculateCrop(Rect clipRect) {
-        final WindowState w = mWin;
-        final DisplayContent displayContent = w.getDisplayContent();
-        clipRect.setEmpty();
-
-        if (displayContent == null) {
-            return false;
-        }
-
-        if (w.getWindowConfiguration().tasksAreFloating()
-                || WindowConfiguration.isSplitScreenWindowingMode(w.getWindowingMode())) {
-            return false;
-        }
-
-        // During forced seamless rotation, the surface bounds get updated with the crop in the
-        // new rotation, which is not compatible with showing the surface in the old rotation.
-        // To work around that we disable cropping for such windows, as it is not necessary anyways.
-        if (w.mForceSeamlesslyRotate) {
-            return false;
-        }
-
-        // If we're animating, the wallpaper should only
-        // be updated at the end of the animation.
-        if (w.mAttrs.type == TYPE_WALLPAPER) {
-            return false;
-        }
-
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG,
-                "Updating crop win=" + w + " mLastCrop=" + mLastClipRect);
-
-        w.calculatePolicyCrop(mSystemDecorRect);
-
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame="
-                + w.getDecorFrame() + " mSystemDecorRect=" + mSystemDecorRect);
-
-        // We use the clip rect as provided by the tranformation for non-fullscreen windows to
-        // avoid premature clipping with the system decor rect.
-        clipRect.set(mSystemDecorRect);
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect);
-
-        w.expandForSurfaceInsets(clipRect);
-
-        // The clip rect was generated assuming (0,0) as the window origin,
-        // so we need to translate to match the actual surface coordinates.
-        clipRect.offset(w.mAttrs.surfaceInsets.left, w.mAttrs.surfaceInsets.top);
-
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG,
-                "win=" + w + " Clip rect after stack adjustment=" + clipRect);
-
-        w.transformClipRectFromScreenToSurfaceSpace(clipRect);
-
-        return true;
-    }
-
-    private void applyCrop(Rect clipRect, boolean recoveringMemory) {
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "applyCrop: win=" + mWin
-                + " clipRect=" + clipRect);
-        if (clipRect != null) {
-            if (!clipRect.equals(mLastClipRect)) {
-                mLastClipRect.set(clipRect);
-                mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
-            }
-        } else {
-            mSurfaceController.clearCropInTransaction(recoveringMemory);
-        }
-    }
-
     private boolean shouldConsumeMainWindowSizeTransaction() {
       // We only consume the transaction when the client is calling relayout
       // because this is the only time we know the frameNumber will be valid
@@ -777,31 +661,6 @@
         final LayoutParams attrs = mWin.getAttrs();
         final Task task = w.getTask();
 
-        calculateSurfaceBounds(w, attrs, mTmpSize);
-
-        // Once relayout has been called at least once, we need to make sure
-        // we only resize the client surface during calls to relayout. For
-        // clients which use indeterminate measure specs (MATCH_PARENT),
-        // we may try and change their window size without a call to relayout.
-        // However, this would be unsafe, as the client may be in the middle
-        // of producing a frame at the old size, having just completed layout
-        // to find the surface size changed underneath it.
-        final boolean relayout = !w.mRelayoutCalled || w.mInRelayout;
-        if (relayout) {
-            mSurfaceResized = mSurfaceController.setBufferSizeInTransaction(
-                    mTmpSize.width(), mTmpSize.height(), recoveringMemory);
-        } else {
-            mSurfaceResized = false;
-        }
-        // If we are undergoing seamless rotation, the surface has already
-        // been set up to persist at it's old location. We need to freeze
-        // updates until a resize occurs.
-
-        Rect clipRect = null;
-        if (calculateCrop(mTmpClipRect)) {
-            clipRect = mTmpClipRect;
-        }
-
         if (shouldConsumeMainWindowSizeTransaction()) {
             task.getMainWindowSizeChangeTask().getSurfaceControl().deferTransactionUntil(
                     mWin.getClientViewRootSurface(), mWin.getFrameNumber());
@@ -816,6 +675,11 @@
 
         final Rect insets = attrs.surfaceInsets;
 
+        // getFrameNumber is only valid in the call-stack of relayoutWindow
+        // as this is the only-time we know the client renderer
+        // is paused.
+        final boolean relayout = !w.mRelayoutCalled || w.mInRelayout;
+
         if (!w.mSeamlesslyRotated) {
             // Used to offset the WSA when stack position changes before a resize.
             int xOffset = mXOffset;
@@ -838,12 +702,6 @@
                     }
                      xOffset = -mTmpPos.x;
                     yOffset = -mTmpPos.y;
-                     // Crop also needs to be extended so the bottom isn't cut off when the WSA
-                    // position is moved.
-                    if (clipRect != null) {
-                        clipRect.right += mTmpPos.x;
-                        clipRect.bottom += mTmpPos.y;
-                    }
                 }
             }
             if (!mIsWallpaper) {
@@ -858,7 +716,6 @@
             // Wallpaper is already updated above when calling setWallpaperPositionAndScale so
             // we only need to consider the non-wallpaper case here.
             if (!mIsWallpaper) {
-                applyCrop(clipRect, recoveringMemory);
                 mSurfaceController.setMatrixInTransaction(
                     mDsDx * w.mHScale,
                     mDtDx * w.mVScale,
@@ -866,10 +723,6 @@
                     mDsDy * w.mVScale, recoveringMemory);
             }
         }
-
-        if (mSurfaceResized) {
-            mWin.getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
-        }
     }
 
     /**
@@ -1064,7 +917,6 @@
                 mDtDy * mWin.mTmpMatrixArray[MSKEW_X] * mWin.mHScale,
                 mDsDy * mWin.mTmpMatrixArray[MSCALE_Y] * mWin.mVScale,
                 recoveringMemory);
-        applyCrop(null, recoveringMemory);
     }
 
     /**
@@ -1255,7 +1107,6 @@
 
     void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
-        mLastClipRect.dumpDebug(proto, LAST_CLIP_RECT);
         if (mSurfaceController != null) {
             mSurfaceController.dumpDebug(proto, SURFACE);
         }
@@ -1276,11 +1127,7 @@
             pw.print(prefix); pw.print(" mLastHidden="); pw.println(mLastHidden);
             pw.print(prefix); pw.print("mEnterAnimationPending=" + mEnterAnimationPending);
             pw.print(prefix); pw.print("mSystemDecorRect="); mSystemDecorRect.printShortString(pw);
-            pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw);
 
-            if (!mLastFinalClipRect.isEmpty()) {
-                pw.print(" mLastFinalClipRect="); mLastFinalClipRect.printShortString(pw);
-            }
             pw.println();
         }
 
@@ -1288,8 +1135,7 @@
             pw.print(prefix); pw.print("mPendingDestroySurface=");
                     pw.println(mPendingDestroySurface);
         }
-        if (mSurfaceResized || mSurfaceDestroyDeferred) {
-            pw.print(prefix); pw.print("mSurfaceResized="); pw.print(mSurfaceResized);
+        if (mSurfaceDestroyDeferred) {
                     pw.print(" mSurfaceDestroyDeferred="); pw.println(mSurfaceDestroyDeferred);
         }
         if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) {
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index e8bf468..bbcb312 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1468,7 +1468,7 @@
     // Need a shared pointer: will be passing it into all unpacking jobs.
     std::shared_ptr<ZipArchive> zipFile(zipFileHandle, [](ZipArchiveHandle h) { CloseArchive(h); });
     void* cookie = nullptr;
-    const auto libFilePrefix = path::join(constants().libDir, abi);
+    const auto libFilePrefix = path::join(constants().libDir, abi) + "/";
     if (StartIteration(zipFile.get(), &cookie, libFilePrefix, constants().libSuffix)) {
         LOG(ERROR) << "Failed to start zip iteration for " << apkFullPath;
         return false;
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 6e3bde3..8b1e9c5 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -94,12 +94,29 @@
      * @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
@@ -126,7 +143,7 @@
 
         @Override
         public long getLastInteraction(String packageName, int userId, String shortcutId) {
-            enforceSystemOrRoot("get last interaction");
+            enforceSystemRootOrSystemUI(getContext(), "get last interaction");
             return mDataManager.getLastInteraction(packageName, userId, shortcutId);
         }
     }
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/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 13f04d2..2efd4b5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -117,7 +117,6 @@
             assertEquals(win.mActivityRecord.getPrefixOrderIndex(), app.prefixOrderIndex);
             assertEquals(win.mActivityRecord.getTask().mTaskId, app.taskId);
             assertEquals(mMockLeash, app.leash);
-            assertEquals(win.mWinAnimator.mLastClipRect, app.clipRect);
             assertEquals(false, app.isTranslucent);
             verify(mMockTransaction).setPosition(mMockLeash, app.position.x, app.position.y);
             verify(mMockTransaction).setWindowCrop(mMockLeash, 100, 50);
@@ -274,7 +273,6 @@
             assertEquals(new Rect(0, 0, 200, 200), app.startBounds);
             assertEquals(mMockLeash, app.leash);
             assertEquals(mMockThumbnailLeash, app.startLeash);
-            assertEquals(win.mWinAnimator.mLastClipRect, app.clipRect);
             assertEquals(false, app.isTranslucent);
             verify(mMockTransaction).setPosition(
                     mMockLeash, app.startBounds.left, app.startBounds.top);
@@ -325,7 +323,6 @@
             assertEquals(new Rect(50, 100, 150, 150), app.startBounds);
             assertEquals(mMockLeash, app.leash);
             assertEquals(mMockThumbnailLeash, app.startLeash);
-            assertEquals(win.mWinAnimator.mLastClipRect, app.clipRect);
             assertEquals(false, app.isTranslucent);
             verify(mMockTransaction).setPosition(
                     mMockLeash, app.startBounds.left, app.startBounds.top);
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/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index ca3626d..0cf63f4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -115,12 +115,6 @@
                 expectedRect.bottom);
     }
 
-    private void assertPolicyCrop(WindowState w, int left, int top, int right, int bottom) {
-        Rect policyCrop = new Rect();
-        w.calculatePolicyCrop(policyCrop);
-        assertRect(policyCrop, left, top, right, bottom);
-    }
-
     @Test
     public void testLayoutInFullscreenTaskInsets() {
         // fullscreen task doesn't use bounds for computeFrame
@@ -335,12 +329,10 @@
         final WindowFrames windowFrames = w.getWindowFrames();
         windowFrames.setFrames(pf, df, cf, vf, dcf, sf);
         w.computeFrame();
-        assertPolicyCrop(w, 0, cf.top, logicalWidth, cf.bottom);
 
         windowFrames.mDecorFrame.setEmpty();
         // Likewise with no decor frame we would get no crop
         w.computeFrame();
-        assertPolicyCrop(w, 0, 0, logicalWidth, logicalHeight);
 
         // Now we set up a window which doesn't fill the entire decor frame.
         // Normally it would be cropped to it's frame but in the case of docked resizing
@@ -355,16 +347,7 @@
         w.mRequestedHeight = logicalHeight / 2;
         w.computeFrame();
 
-        // Normally the crop is shrunk from the decor frame
-        // to the computed window frame.
-        assertPolicyCrop(w, 0, 0, logicalWidth / 2, logicalHeight / 2);
-
         doReturn(true).when(w).isDockedResizing();
-        // But if we are docked resizing it won't be, however we will still be
-        // shrunk to the decor frame and the display.
-        assertPolicyCrop(w, 0, 0,
-                Math.min(pf.width(), displayInfo.logicalWidth),
-                Math.min(pf.height(), displayInfo.logicalHeight));
     }
 
     @Test
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/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..7a0e1cd 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -85,8 +85,6 @@
 import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.aidl.IImsConfig;
-import android.telephony.ims.aidl.IImsMmTelFeature;
-import android.telephony.ims.aidl.IImsRcsFeature;
 import android.telephony.ims.aidl.IImsRegistration;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -94,7 +92,6 @@
 import android.util.Log;
 import android.util.Pair;
 
-import com.android.ims.internal.IImsServiceFeatureCallback;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.CellNetworkScanResult;
@@ -2807,7 +2804,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 = {
@@ -7380,80 +7381,6 @@
     }
 
     /**
-     * Returns the {@link IImsMmTelFeature} that corresponds to the given slot Id and MMTel
-     * feature or {@link null} if the service is not available. If an MMTelFeature is available, the
-     * {@link IImsServiceFeatureCallback} callback is registered as a listener for feature updates.
-     * @param slotIndex The SIM slot that we are requesting the {@link IImsMmTelFeature} for.
-     * @param callback Listener that will send updates to ImsManager when there are updates to
-     * ImsServiceController.
-     * @return {@link IImsMmTelFeature} interface for the feature specified or {@code null} if
-     * it is unavailable.
-     * @hide
-     */
-    public @Nullable IImsMmTelFeature getImsMmTelFeatureAndListen(int slotIndex,
-            IImsServiceFeatureCallback callback) {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null) {
-                return telephony.getMmTelFeatureAndListen(slotIndex, callback);
-            }
-        } catch (RemoteException e) {
-            Rlog.e(TAG, "getImsMmTelFeatureAndListen, RemoteException: "
-                    + e.getMessage());
-        }
-        return null;
-    }
-
-    /**
-     * Returns the {@link IImsRcsFeature} that corresponds to the given slot Id and RCS
-     * feature for emergency calling or {@link null} if the service is not available. If an
-     * RcsFeature is available, the {@link IImsServiceFeatureCallback} callback is registered as a
-     * listener for feature updates.
-     * @param slotIndex The SIM slot that we are requesting the {@link IImsRcsFeature} for.
-     * @param callback Listener that will send updates to ImsManager when there are updates to
-     * ImsServiceController.
-     * @return {@link IImsRcsFeature} interface for the feature specified or {@code null} if
-     * it is unavailable.
-     * @hide
-     */
-    public @Nullable IImsRcsFeature getImsRcsFeatureAndListen(int slotIndex,
-            IImsServiceFeatureCallback callback) {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null) {
-                return telephony.getRcsFeatureAndListen(slotIndex, callback);
-            }
-        } catch (RemoteException e) {
-            Rlog.e(TAG, "getImsRcsFeatureAndListen, RemoteException: "
-                    + e.getMessage());
-        }
-        return null;
-    }
-
-    /**
-     * Unregister a IImsServiceFeatureCallback previously associated with an ImsFeature through
-     * {@link #getImsMmTelFeatureAndListen(int, IImsServiceFeatureCallback)} or
-     * {@link #getImsRcsFeatureAndListen(int, IImsServiceFeatureCallback)}.
-     * @param slotIndex The SIM slot associated with the callback.
-     * @param featureType The {@link android.telephony.ims.feature.ImsFeature.FeatureType}
-     *                    associated with the callback.
-     * @param callback The callback to be unregistered.
-     * @hide
-     */
-    public void unregisterImsFeatureCallback(int slotIndex, int featureType,
-            IImsServiceFeatureCallback callback) {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null) {
-                telephony.unregisterImsFeatureCallback(slotIndex, featureType, callback);
-            }
-        } catch (RemoteException e) {
-            Rlog.e(TAG, "unregisterImsFeatureCallback, RemoteException: "
-                    + e.getMessage());
-        }
-    }
-
-    /**
      * @return the {@IImsRegistration} interface that corresponds with the slot index and feature.
      * @param slotIndex The SIM slot corresponding to the ImsService ImsRegistration is active for.
      * @param feature An integer indicating the feature that we wish to get the ImsRegistration for.
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index f6c14e6..ee2fce7 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -59,6 +59,7 @@
  * manager.
  */
 public class ImsMmTelManager implements RegistrationManager {
+    private static final String TAG = "ImsMmTelManager";
 
     /**
      * @hide
@@ -809,7 +810,7 @@
         }
 
         try {
-            getITelephony().isMmTelCapabilitySupported(mSubId, new IIntegerConsumer.Stub() {
+            iTelephony.isMmTelCapabilitySupported(mSubId, new IIntegerConsumer.Stub() {
                 @Override
                 public void accept(int result) {
                     executor.execute(() -> callback.accept(result == 1));
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index da7311c..8a05bdf 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -16,6 +16,7 @@
 
 package android.telephony.ims;
 
+import android.annotation.LongDef;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.app.Service;
@@ -41,6 +42,11 @@
 import com.android.ims.internal.IImsFeatureStatusCallback;
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
  * ImsService must register the service in their AndroidManifest to be detected by the framework.
@@ -98,6 +104,32 @@
     private static final String LOG_TAG = "ImsService";
 
     /**
+     * This ImsService supports the capability to place emergency calls over MMTEL.
+     * @hide This is encoded into the {@link ImsFeature#FEATURE_EMERGENCY_MMTEL}, but we will be
+     * adding other capabilities in a central location, so track this capability here as well.
+     */
+    public static final long CAPABILITY_EMERGENCY_OVER_MMTEL = 1 << 0;
+
+    /**
+     * @hide
+     */
+    @LongDef(flag = true,
+            prefix = "CAPABILITY_",
+            value = {
+                    CAPABILITY_EMERGENCY_OVER_MMTEL
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ImsServiceCapability {}
+
+    /**
+     * Used for logging purposes, see {@link #getCapabilitiesString(long)}
+     * @hide
+     */
+    private static final Map<Long, String> CAPABILITIES_LOG_MAP = new HashMap<Long, String>() {{
+            put(CAPABILITY_EMERGENCY_OVER_MMTEL, "EMERGENCY_OVER_MMTEL");
+        }};
+
+    /**
      * The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService.
      * @hide
      */
@@ -409,4 +441,30 @@
     public ImsRegistrationImplBase getRegistration(int slotId) {
         return new ImsRegistrationImplBase();
     }
+
+    /**
+     * @return A string representation of the ImsService capabilties for logging.
+     * @hide
+     */
+    public static String getCapabilitiesString(@ImsServiceCapability long caps) {
+        StringBuffer result = new StringBuffer();
+        result.append("capabilities={ ");
+        // filter incrementally fills 0s from  left to right. This is used to keep filtering out
+        // more bits in the long until the remaining leftmost bits are all zero.
+        long filter = 0xFFFFFFFFFFFFFFFFL;
+        // position of iterator to potentially print capability.
+        long i = 0;
+        while ((caps & filter) != 0 && i <= 63) {
+            long bitToCheck = (1L << i);
+            if ((caps & bitToCheck) != 0) {
+                result.append(CAPABILITIES_LOG_MAP.getOrDefault(bitToCheck, bitToCheck + "?"));
+                result.append(" ");
+            }
+            // shift left by one and fill in another 1 on the leftmost bit.
+            filter <<= 1;
+            i++;
+        }
+        result.append("}");
+        return result.toString();
+    }
 }
\ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
index 9e46142..d012703b 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
@@ -22,6 +22,7 @@
 import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
 import android.telephony.ims.aidl.IImsRegistrationCallback;
 
+import com.android.ims.internal.IImsServiceFeatureCallback;
 import com.android.internal.telephony.IIntegerConsumer;
 
 /**
@@ -50,4 +51,9 @@
     void setUceSettingEnabled(int subId, boolean isEnabled);
     void registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c);
     void unregisterUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c);
+
+    // Internal commands that should not be made public
+    void registerRcsFeatureCallback(int slotId, in IImsServiceFeatureCallback callback,
+            boolean oneShot);
+    void unregisterImsFeatureCallback(in IImsServiceFeatureCallback callback);
 }
diff --git a/telephony/java/com/android/ims/ImsFeatureContainer.aidl b/telephony/java/com/android/ims/ImsFeatureContainer.aidl
new file mode 100644
index 0000000..9706f20
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsFeatureContainer.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims;
+
+parcelable ImsFeatureContainer;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/ImsFeatureContainer.java b/telephony/java/com/android/ims/ImsFeatureContainer.java
new file mode 100644
index 0000000..b259679
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsFeatureContainer.java
@@ -0,0 +1,172 @@
+/*
+ * 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.ims;
+
+import android.annotation.NonNull;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.ims.ImsService;
+import android.telephony.ims.aidl.IImsConfig;
+import android.telephony.ims.aidl.IImsRegistration;
+import android.telephony.ims.feature.ImsFeature;
+
+import java.util.Objects;
+
+/**
+ * Contains an IBinder linking to the appropriate ImsFeature as well as the associated
+ * interfaces.
+ * @hide
+ */
+public final class ImsFeatureContainer implements Parcelable {
+    /**
+     * ImsFeature that is being tracked.
+     */
+    public final IBinder imsFeature;
+
+    /**
+     * IImsConfig interface that should be associated with the ImsFeature.
+     */
+    public final android.telephony.ims.aidl.IImsConfig imsConfig;
+
+    /**
+     * IImsRegistration interface that should be associated with this ImsFeature.
+     */
+    public final IImsRegistration imsRegistration;
+
+    /**
+     * State of the feature that is being tracked.
+     */
+    private @ImsFeature.ImsState int mState = ImsFeature.STATE_UNAVAILABLE;
+
+    /**
+     * Capabilities of this ImsService.
+     */
+    private @ImsService.ImsServiceCapability long mCapabilities;
+    /**
+     * Contains the ImsFeature IBinder as well as the ImsService interfaces associated with
+     * that feature.
+     * @param iFace IBinder connection to the ImsFeature.
+     * @param iConfig IImsConfig interface associated with the ImsFeature.
+     * @param iReg IImsRegistration interface associated with the ImsFeature
+     * @param initialCaps The initial capabilities that the ImsService supports.
+     */
+    public ImsFeatureContainer(@NonNull IBinder iFace, @NonNull IImsConfig iConfig,
+            @NonNull IImsRegistration iReg, long initialCaps) {
+        imsFeature = iFace;
+        imsConfig = iConfig;
+        imsRegistration = iReg;
+        mCapabilities = initialCaps;
+    }
+
+    /**
+     * Create an ImsFeatureContainer from a Parcel.
+     */
+    private ImsFeatureContainer(Parcel in) {
+        imsFeature = in.readStrongBinder();
+        imsConfig = IImsConfig.Stub.asInterface(in.readStrongBinder());
+        imsRegistration = IImsRegistration.Stub.asInterface(in.readStrongBinder());
+        mState = in.readInt();
+        mCapabilities = in.readLong();
+    }
+
+    /**
+     * @return the capabilties that are associated with the ImsService that this ImsFeature
+     * belongs to.
+     */
+    public @ImsService.ImsServiceCapability long getCapabilities() {
+        return mCapabilities;
+    }
+
+    /**
+     * Update the capabilities that are associated with the ImsService that this ImsFeature
+     * belongs to.
+     */
+    public void setCapabilities(@ImsService.ImsServiceCapability long caps) {
+        mCapabilities = caps;
+    }
+
+    /**
+     * @return The state of the ImsFeature.
+     */
+    public @ImsFeature.ImsState int getState() {
+        return mState;
+    }
+
+    /**
+     * Set the state that is associated with the ImsService that this ImsFeature
+     * belongs to.
+     */
+    public void setState(@ImsFeature.ImsState int state) {
+        mState = state;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        ImsFeatureContainer that = (ImsFeatureContainer) o;
+        return imsFeature.equals(that.imsFeature) &&
+                imsConfig.equals(that.imsConfig) &&
+                imsRegistration.equals(that.imsRegistration) &&
+                mState == that.getState() &&
+                mCapabilities == that.getCapabilities();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(imsFeature, imsConfig, imsRegistration, mState, mCapabilities);
+    }
+
+    @Override
+    public String toString() {
+        return "FeatureContainer{" +
+                "imsFeature=" + imsFeature +
+                ", imsConfig=" + imsConfig +
+                ", imsRegistration=" + imsRegistration +
+                ", state=" + ImsFeature.STATE_LOG_MAP.get(mState) +
+                ", capabilities = " + ImsService.getCapabilitiesString(mCapabilities) +
+                '}';
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(imsFeature);
+        dest.writeStrongInterface(imsConfig);
+        dest.writeStrongInterface(imsRegistration);
+        dest.writeInt(mState);
+        dest.writeLong(mCapabilities);
+    }
+
+
+    public static final Creator<ImsFeatureContainer> CREATOR = new Creator<ImsFeatureContainer>() {
+        @Override
+        public ImsFeatureContainer createFromParcel(Parcel source) {
+            return new ImsFeatureContainer(source);
+        }
+
+        @Override
+        public ImsFeatureContainer[] newArray(int size) {
+            return new ImsFeatureContainer[size];
+        }
+    };
+}
diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
index 9a9cf53..f5f67bd 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
@@ -16,13 +16,18 @@
 
 package com.android.ims.internal;
 
+import com.android.ims.ImsFeatureContainer;
 /**
- *  Interface from ImsResolver to ImsServiceProxy in ImsManager.
- * Callback to ImsManager when a feature changes in the ImsServiceController.
+ *  Interface from ImsResolver to FeatureConnections.
+ * Callback to FeatureConnections when a feature's status changes.
  * {@hide}
  */
 oneway interface IImsServiceFeatureCallback {
-    void imsFeatureCreated(int slotId, int feature);
-    void imsFeatureRemoved(int slotId, int feature);
-    void imsStatusChanged(int slotId, int feature, int status);
+    void imsFeatureCreated(in ImsFeatureContainer feature);
+    // Reason defined in FeatureConnector.UnavailableReason
+    void imsFeatureRemoved(int reason);
+    // Status defined in ImsFeature.ImsState.
+    void imsStatusChanged(int status);
+    //Capabilities defined in ImsService.ImsServiceCapability
+    void updateCapabilities(long capabilities);
 }
\ No newline at end of file
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 02a74ba..ef5078d 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -829,22 +829,15 @@
      *  as well as registering the MmTelFeature for callbacks using the IImsServiceFeatureCallback
      *  interface.
      */
-    IImsMmTelFeature getMmTelFeatureAndListen(int slotId, in IImsServiceFeatureCallback callback);
-
-    /**
-     *  Get IImsRcsFeature binder from ImsResolver that corresponds to the subId and RCS feature
-     *  as well as registering the RcsFeature for callbacks using the IImsServiceFeatureCallback
-     *  interface.
-     */
-    IImsRcsFeature getRcsFeatureAndListen(int slotId, in IImsServiceFeatureCallback callback);
+    void registerMmTelFeatureCallback(int slotId, in IImsServiceFeatureCallback callback,
+            boolean oneShot);
 
     /**
      * Unregister a callback that was previously registered through
-     * {@link #getMmTelFeatureAndListen} or {@link #getRcsFeatureAndListen}. This should always be
-     * called when the callback is no longer being used.
+     * {@link #registerMmTelFeatureCallback}. This should always be called when the callback is no
+     * longer being used.
      */
-    void unregisterImsFeatureCallback(int slotId, int featureType,
-            in IImsServiceFeatureCallback callback);
+    void unregisterImsFeatureCallback(in IImsServiceFeatureCallback callback);
 
     /**
     * Returns the IImsRegistration associated with the slot and feature specified.
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 05a59ef..9a2def9 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -745,7 +745,7 @@
         </activity>
 
         <activity android:name="BlurActivity"
-                  android:label="Shaders/Blur"
+                  android:label="RenderEffect/Blur"
                   android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/tests/HwAccelerationTest/res/layout/image_filter_activity.xml b/tests/HwAccelerationTest/res/layout/image_filter_activity.xml
new file mode 100644
index 0000000..a0ee67a
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/image_filter_activity.xml
@@ -0,0 +1,28 @@
+<?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.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center">
+
+    <ImageView
+        android:id="@+id/image_filter_test_view"
+        android:background="#FF0000"
+        android:layout_width="200dp"
+        android:layout_height="200dp" />
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
index 033fb0e..e4ca788 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
@@ -18,11 +18,12 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.graphics.BlurShader;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.LinearGradient;
 import android.graphics.Paint;
+import android.graphics.RenderEffect;
+import android.graphics.RenderNode;
 import android.graphics.Shader;
 import android.os.Bundle;
 import android.view.Gravity;
@@ -51,16 +52,27 @@
     }
 
     public static class BlurGradientView extends View {
-        private BlurShader mBlurShader = null;
-        private Paint mPaint;
+        private final float mBlurRadius = 25f;
+        private final Paint mPaint;
+        private final RenderNode mRenderNode;
 
         public BlurGradientView(Context c) {
             super(c);
+            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            mRenderNode = new RenderNode("BlurGradientView");
+            mRenderNode.setRenderEffect(
+                    RenderEffect.createBlurEffect(
+                            mBlurRadius,
+                            mBlurRadius,
+                            null,
+                            Shader.TileMode.DECAL
+                    )
+            );
         }
 
         @Override
         protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-            if (changed || mBlurShader == null) {
+            if (changed) {
                 LinearGradient gradient = new LinearGradient(
                         0f,
                         0f,
@@ -70,41 +82,81 @@
                         Color.YELLOW,
                         Shader.TileMode.CLAMP
                 );
-                mBlurShader = new BlurShader(30f, 40f, gradient);
-                mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-                mPaint.setShader(mBlurShader);
+
+                mPaint.setShader(gradient);
+
+                final int width = right - left;
+                final int height = bottom - top;
+                mRenderNode.setPosition(0, 0, width, height);
+
+                Canvas canvas = mRenderNode.beginRecording();
+                canvas.drawRect(
+                        mBlurRadius * 2,
+                        mBlurRadius * 2,
+                        width - mBlurRadius * 2,
+                        height - mBlurRadius * 2,
+                        mPaint
+                );
+                mRenderNode.endRecording();
             }
         }
 
         @Override
         protected void onDraw(Canvas canvas) {
             super.onDraw(canvas);
-            canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
+            canvas.drawRenderNode(mRenderNode);
         }
     }
 
     public static class BlurView extends View {
 
-        private final BlurShader mBlurShader;
         private final Paint mPaint;
+        private final RenderNode mRenderNode;
+        private final float mBlurRadius = 20f;
 
         public BlurView(Context c) {
             super(c);
 
-            mBlurShader = new BlurShader(20f, 20f, null);
             mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-            mPaint.setShader(mBlurShader);
+            mRenderNode = new RenderNode("blurNode");
+            mRenderNode.setRenderEffect(
+                    RenderEffect.createBlurEffect(
+                            mBlurRadius,
+                            mBlurRadius,
+                            null,
+                            Shader.TileMode.DECAL
+                    )
+            );
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+            if (changed) {
+                int width = right - left;
+                int height = bottom - top;
+                mRenderNode.setPosition(0, 0, width, height);
+                Canvas canvas = mRenderNode.beginRecording(width, height);
+                mPaint.setColor(Color.BLUE);
+
+                canvas.drawRect(
+                        mBlurRadius * 2,
+                        mBlurRadius * 2,
+                        width - mBlurRadius * 2,
+                        height - mBlurRadius * 2,
+                        mPaint
+                );
+
+                mPaint.setColor(Color.RED);
+                canvas.drawCircle((right - left) / 2f, (bottom - top) / 2f, 50f, mPaint);
+
+                mRenderNode.endRecording();
+            }
         }
 
         @Override
         protected void onDraw(Canvas canvas) {
             super.onDraw(canvas);
-
-            mPaint.setColor(Color.BLUE);
-            canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
-
-            mPaint.setColor(Color.RED);
-            canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, 50f, mPaint);
+            canvas.drawRenderNode(mRenderNode);
         }
     }
 }
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
index 71175847..2f2578b 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
@@ -20,13 +20,13 @@
 import android.graphics.BitmapFactory
 import android.graphics.BitmapShader
 import android.graphics.BlendMode
-import android.graphics.BlurShader
 import android.graphics.Canvas
 import android.graphics.Color
 import android.graphics.Outline
 import android.graphics.Paint
-import android.graphics.RadialGradient
 import android.graphics.Rect
+import android.graphics.RenderEffect
+import android.graphics.RenderNode
 import android.graphics.Shader
 import android.hardware.Sensor
 import android.hardware.SensorEvent
@@ -36,7 +36,6 @@
 import android.view.View
 import android.view.ViewOutlineProvider
 import android.widget.FrameLayout
-import com.android.internal.graphics.ColorUtils
 import com.android.test.silkfx.R
 import kotlin.math.sin
 import kotlin.math.sqrt
@@ -152,10 +151,19 @@
     var blurRadius = 150f
     set(value) {
         field = value
-        blurPaint.shader = BlurShader(value, value, null)
+        renderNode.setRenderEffect(
+                RenderEffect.createBlurEffect(value, value, Shader.TileMode.CLAMP))
         invalidate()
     }
 
+    private var renderNodeIsDirty = true
+    private val renderNode = RenderNode("GlassRenderNode")
+
+    override fun invalidate() {
+        renderNodeIsDirty = true
+        super.invalidate()
+    }
+
     init {
         setWillNotDraw(false)
         materialPaint.blendMode = BlendMode.SOFT_LIGHT
@@ -164,7 +172,6 @@
         scrimPaint.alpha = (scrimOpacity * 255).toInt()
         noisePaint.alpha = (noiseOpacity * 255).toInt()
         materialPaint.alpha = (materialOpacity * 255).toInt()
-        blurPaint.shader = BlurShader(blurRadius, blurRadius, null)
         outlineProvider = object : ViewOutlineProvider() {
             override fun getOutline(view: View?, outline: Outline?) {
                 outline?.setRoundRect(Rect(0, 0, width, height), 100f)
@@ -184,20 +191,8 @@
     }
 
     override fun onDraw(canvas: Canvas?) {
-        src.set(-width / 2, -height / 2, width / 2, height / 2)
-        src.scale(1.0f + zoom)
-        val centerX = left + width / 2
-        val centerY = top + height / 2
-        val textureXOffset = (textureTranslationMultiplier * gyroYRotation).toInt()
-        val textureYOffset = (textureTranslationMultiplier * gyroXRotation).toInt()
-        src.set(src.left + centerX + textureXOffset, src.top + centerY + textureYOffset,
-                src.right + centerX + textureXOffset, src.bottom + centerY + textureYOffset)
-
-        dst.set(0, 0, width, height)
-        canvas?.drawBitmap(backgroundBitmap, src, dst, blurPaint)
-        canvas?.drawRect(dst, materialPaint)
-        canvas?.drawRect(dst, noisePaint)
-        canvas?.drawRect(dst, scrimPaint)
+        updateGlassRenderNode()
+        canvas?.drawRenderNode(renderNode)
     }
 
     fun resetGyroOffsets() {
@@ -205,4 +200,31 @@
         gyroYRotation = 0f
         invalidate()
     }
+
+    private fun updateGlassRenderNode() {
+        if (renderNodeIsDirty) {
+            renderNode.setPosition(0, 0, getWidth(), getHeight())
+
+            val canvas = renderNode.beginRecording()
+
+            src.set(-width / 2, -height / 2, width / 2, height / 2)
+            src.scale(1.0f + zoom)
+            val centerX = left + width / 2
+            val centerY = top + height / 2
+            val textureXOffset = (textureTranslationMultiplier * gyroYRotation).toInt()
+            val textureYOffset = (textureTranslationMultiplier * gyroXRotation).toInt()
+            src.set(src.left + centerX + textureXOffset, src.top + centerY + textureYOffset,
+                    src.right + centerX + textureXOffset, src.bottom + centerY + textureYOffset)
+
+            dst.set(0, 0, width, height)
+            canvas.drawBitmap(backgroundBitmap, src, dst, blurPaint)
+            canvas.drawRect(dst, materialPaint)
+            canvas.drawRect(dst, noisePaint)
+            canvas.drawRect(dst, scrimPaint)
+
+            renderNode.endRecording()
+
+            renderNodeIsDirty = false
+        }
+    }
 }
\ No newline at end of file
diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt
index fd45ebe..0f71ab4 100644
--- a/wifi/api/system-current.txt
+++ b/wifi/api/system-current.txt
@@ -509,7 +509,7 @@
     field public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0; // 0x0
     field public static final String EXTRA_CHANGE_REASON = "changeReason";
     field @Deprecated public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
-    field public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
+    field @Deprecated public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
     field public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
     field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
     field public static final String EXTRA_URL = "android.net.wifi.extra.URL";
@@ -517,7 +517,7 @@
     field public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
     field public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
     field public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
-    field public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
+    field @Deprecated public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
     field public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
     field public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
     field public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0; // 0x0
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 2219bfc..b4e4210 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -931,9 +931,6 @@
      * This can be as a result of adding/updating/deleting a network.
      * <br />
      * {@link #EXTRA_CHANGE_REASON} contains whether the configuration was added/changed/removed.
-     * {@link #EXTRA_WIFI_CONFIGURATION} is never set starting in Android 11.
-     * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set for backwards compatibility reasons, but
-     * its value is always true, even if only a single network changed.
      * <br />
      * The {@link android.Manifest.permission#ACCESS_WIFI_STATE ACCESS_WIFI_STATE} permission is
      * required to receive this broadcast.
@@ -947,17 +944,20 @@
      * The lookup key for a {@link android.net.wifi.WifiConfiguration} object representing
      * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION}
      * broadcast is sent.
-     * Note: this extra is never set starting in Android 11.
+     * @deprecated this extra is never set. Use {@link #getConfiguredNetworks} to get the full list
+     * of configured networks.
      * @hide
      */
+    @Deprecated
     @SystemApi
     public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
     /**
      * Multiple network configurations have changed.
      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
-     * Note: this extra is always true starting in Android 11.
+     * @deprecated this extra's value is always true.
      * @hide
      */
+    @Deprecated
     @SystemApi
     public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
     /**