Merge changes I221089d1,Ie3c7a665

* changes:
  Fix clipboard overlay in dark mode and RTL
  Rename attrs/files shared between clipboard and screenshots
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index ddcc746..13ecd25 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -3,6 +3,7 @@
 import android.annotation.CurrentTimeMillisLong;
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager.ProcessState;
 import android.app.usage.AppStandbyInfo;
 import android.app.usage.UsageStatsManager.ForcedReasons;
 import android.app.usage.UsageStatsManager.StandbyBuckets;
@@ -223,4 +224,12 @@
      * a broadcast.
      */
     long getBroadcastResponseWindowDurationMs();
+
+    /**
+     * Returns the process state threshold that should be used for deciding whether or not an app
+     * is in the background in the context of recording broadcast response stats. Apps whose
+     * process state is higher than this threshold state should be considered to be in background.
+     */
+    @ProcessState
+    int getBroadcastResponseFgThresholdState();
 }
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 050e3df..b843dca 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -356,6 +356,14 @@
             ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_WINDOW_DURATION_MS;
 
     /**
+     * Process state threshold that is used for deciding whether or not an app is in the background
+     * in the context of recording broadcast response stats. Apps whose process state is higher
+     * than this threshold state will be considered to be in background.
+     */
+    volatile int mBroadcastResponseFgThresholdState =
+            ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE;
+
+    /**
      * Whether we should allow apps into the
      * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket or not.
      * If false, any attempts to put an app into the bucket will put the app into the
@@ -1788,6 +1796,11 @@
     }
 
     @Override
+    public int getBroadcastResponseFgThresholdState() {
+        return mBroadcastResponseFgThresholdState;
+    }
+
+    @Override
     public void flushToDisk() {
         synchronized (mAppIdleLock) {
             mAppIdleHistory.writeAppIdleTimes(mInjector.elapsedRealtime());
@@ -2058,6 +2071,10 @@
         TimeUtils.formatDuration(mBroadcastResponseWindowDurationMillis, pw);
         pw.println();
 
+        pw.print("  mBroadcastResponseFgThresholdState=");
+        pw.print(ActivityManager.procStateToString(mBroadcastResponseFgThresholdState));
+        pw.println();
+
         pw.println();
         pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
         pw.print(" mAllowRestrictedBucket=");
@@ -2491,6 +2508,8 @@
         };
         private static final String KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS =
                 "broadcast_response_window_timeout_ms";
+        private static final String KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE =
+                "broadcast_response_fg_threshold_state";
         public static final long DEFAULT_CHECK_IDLE_INTERVAL_MS =
                 COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR;
         public static final long DEFAULT_STRONG_USAGE_TIMEOUT =
@@ -2522,6 +2541,8 @@
         public static final boolean DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS = true;
         public static final long DEFAULT_BROADCAST_RESPONSE_WINDOW_DURATION_MS =
                 2 * ONE_MINUTE;
+        public static final int DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE =
+                ActivityManager.PROCESS_STATE_TOP;
 
         ConstantsObserver(Handler handler) {
             super(handler);
@@ -2644,6 +2665,11 @@
                                     KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS,
                                     DEFAULT_BROADCAST_RESPONSE_WINDOW_DURATION_MS);
                             break;
+                        case KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE:
+                            mBroadcastResponseFgThresholdState = properties.getInt(
+                                    KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE,
+                                    DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE);
+                            break;
                         default:
                             if (!timeThresholdsUpdated
                                     && (name.startsWith(KEY_PREFIX_SCREEN_TIME_THRESHOLD)
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index d963e68..b4edd39 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -61,6 +61,9 @@
         "test_com.android.media",
     ],
     min_sdk_version: "29",
+    lint: {
+        strict_updatability_linting: true,
+    },
     visibility: [
         "//frameworks/av/apex:__subpackages__",
         "//frameworks/base", // For framework-all
diff --git a/apex/media/service/Android.bp b/apex/media/service/Android.bp
index 2714809..834e5cb 100644
--- a/apex/media/service/Android.bp
+++ b/apex/media/service/Android.bp
@@ -47,6 +47,9 @@
     jarjar_rules: "jarjar_rules.txt",
     sdk_version: "system_server_current",
     min_sdk_version: "29", // TODO: We may need to bump this at some point.
+    lint: {
+        strict_updatability_linting: true,
+    },
     apex_available: [
         "com.android.media",
     ],
diff --git a/core/api/current.txt b/core/api/current.txt
index e2325b0..74594d0 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -326,6 +326,9 @@
     field public static final int allowClearUserData = 16842757; // 0x1010005
     field public static final int allowClickWhenDisabled = 16844312; // 0x1010618
     field public static final int allowEmbedded = 16843765; // 0x10103f5
+    field public static final int allowGameAngleDriver;
+    field public static final int allowGameDownscaling;
+    field public static final int allowGameFpsOverride;
     field public static final int allowNativeHeapPointerTagging = 16844306; // 0x1010612
     field public static final int allowParallelSyncs = 16843570; // 0x1010332
     field public static final int allowSingleTap = 16843353; // 0x1010259
@@ -729,6 +732,10 @@
     field public static final int freezesText = 16843116; // 0x101016c
     field public static final int fromAlpha = 16843210; // 0x10101ca
     field public static final int fromDegrees = 16843187; // 0x10101b3
+    field public static final int fromExtendBottom;
+    field public static final int fromExtendLeft;
+    field public static final int fromExtendRight;
+    field public static final int fromExtendTop;
     field public static final int fromId = 16843850; // 0x101044a
     field public static final int fromScene = 16843741; // 0x10103dd
     field public static final int fromXDelta = 16843206; // 0x10101c6
@@ -1431,10 +1438,12 @@
     field public static final int summaryOn = 16843247; // 0x10101ef
     field public static final int supportedTypes;
     field public static final int supportsAssist = 16844016; // 0x10104f0
+    field public static final int supportsBatteryGameMode;
     field public static final int supportsInlineSuggestions = 16844301; // 0x101060d
     field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
     field public static final int supportsLocalInteraction = 16844047; // 0x101050f
     field public static final int supportsMultipleDisplays = 16844182; // 0x1010596
+    field public static final int supportsPerformanceGameMode;
     field public static final int supportsPictureInPicture = 16844023; // 0x10104f7
     field public static final int supportsRtl = 16843695; // 0x10103af
     field public static final int supportsStylusHandwriting;
@@ -1574,6 +1583,10 @@
     field public static final int titleTextStyle = 16843512; // 0x10102f8
     field public static final int toAlpha = 16843211; // 0x10101cb
     field public static final int toDegrees = 16843188; // 0x10101b4
+    field public static final int toExtendBottom;
+    field public static final int toExtendLeft;
+    field public static final int toExtendRight;
+    field public static final int toExtendTop;
     field public static final int toId = 16843849; // 0x1010449
     field public static final int toScene = 16843742; // 0x10103de
     field public static final int toXDelta = 16843207; // 0x10101c7
@@ -3122,6 +3135,11 @@
     field public static final int GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT = 13; // 0xd
     field public static final int GLOBAL_ACTION_BACK = 1; // 0x1
     field public static final int GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE = 15; // 0xf
+    field public static final int GLOBAL_ACTION_DPAD_CENTER = 20; // 0x14
+    field public static final int GLOBAL_ACTION_DPAD_DOWN = 17; // 0x11
+    field public static final int GLOBAL_ACTION_DPAD_LEFT = 18; // 0x12
+    field public static final int GLOBAL_ACTION_DPAD_RIGHT = 19; // 0x13
+    field public static final int GLOBAL_ACTION_DPAD_UP = 16; // 0x10
     field public static final int GLOBAL_ACTION_HOME = 2; // 0x2
     field public static final int GLOBAL_ACTION_KEYCODE_HEADSETHOOK = 10; // 0xa
     field public static final int GLOBAL_ACTION_LOCK_SCREEN = 8; // 0x8
@@ -31417,6 +31435,9 @@
     method @Nullable public byte[] createByteArray();
     method @Nullable public char[] createCharArray();
     method @Nullable public double[] createDoubleArray();
+    method @Nullable public <T> T createFixedArray(@NonNull Class<T>, @NonNull int...);
+    method @Nullable public <T, S extends android.os.IInterface> T createFixedArray(@NonNull Class<T>, @NonNull java.util.function.Function<android.os.IBinder,S>, @NonNull int...);
+    method @Nullable public <T, S extends android.os.Parcelable> T createFixedArray(@NonNull Class<T>, @NonNull android.os.Parcelable.Creator<S>, @NonNull int...);
     method @Nullable public float[] createFloatArray();
     method @Nullable public int[] createIntArray();
     method @Nullable public <T extends android.os.IInterface> T[] createInterfaceArray(@NonNull java.util.function.IntFunction<T[]>, @NonNull java.util.function.Function<android.os.IBinder,T>);
@@ -31458,6 +31479,9 @@
     method public void readException();
     method public void readException(int, String);
     method public android.os.ParcelFileDescriptor readFileDescriptor();
+    method public <T> void readFixedArray(@NonNull T);
+    method public <T, S extends android.os.IInterface> void readFixedArray(@NonNull T, @NonNull java.util.function.Function<android.os.IBinder,S>);
+    method public <T, S extends android.os.Parcelable> void readFixedArray(@NonNull T, @NonNull android.os.Parcelable.Creator<S>);
     method public float readFloat();
     method public void readFloatArray(@NonNull float[]);
     method @Deprecated @Nullable public java.util.HashMap readHashMap(@Nullable ClassLoader);
@@ -31518,6 +31542,7 @@
     method public void writeDoubleArray(@Nullable double[]);
     method public void writeException(@NonNull Exception);
     method public void writeFileDescriptor(@NonNull java.io.FileDescriptor);
+    method public <T> void writeFixedArray(@Nullable T, int, @NonNull int...);
     method public void writeFloat(float);
     method public void writeFloatArray(@Nullable float[]);
     method public void writeInt(int);
@@ -41213,6 +41238,7 @@
     field public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int";
     field public static final String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
     field public static final String KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL = "is_ims_conference_size_enforced_bool";
+    field public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL = "is_opportunistic_subscription_bool";
     field public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool";
     field public static final String KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY = "lte_rsrq_thresholds_int_array";
     field public static final String KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY = "lte_rssnr_thresholds_int_array";
@@ -41297,6 +41323,7 @@
     field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
     field public static final String KEY_SMDP_SERVER_ADDRESS_STRING = "smdp_server_address_string";
     field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
+    field public static final String KEY_SUBSCRIPTION_GROUP_UUID_STRING = "subscription_group_uuid_string";
     field public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool";
     field public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL = "supports_device_to_device_communication_using_dtmf_bool";
     field public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL = "supports_device_to_device_communication_using_rtp_bool";
@@ -41340,6 +41367,7 @@
     field public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING = "wfc_emergency_address_carrier_app_string";
     field public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
     field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
+    field public static final String REMOVE_GROUP_UUID_STRING = "00000000-0000-0000-0000-000000000000";
     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
@@ -51660,6 +51688,7 @@
     method public boolean isSelected();
     method public boolean isShowingHintText();
     method public boolean isTextEntryKey();
+    method public boolean isTextSelectable();
     method public boolean isVisibleToUser();
     method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
     method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int);
@@ -51723,6 +51752,7 @@
     method public void setStateDescription(@Nullable CharSequence);
     method public void setText(CharSequence);
     method public void setTextEntryKey(boolean);
+    method public void setTextSelectable(boolean);
     method public void setTextSelection(int, int);
     method public void setTooltipText(@Nullable CharSequence);
     method public void setTouchDelegateInfo(@NonNull android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index df61a96..520ca47 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -54,6 +54,21 @@
     method public void onCanceled(@NonNull android.app.PendingIntent);
   }
 
+  public class PropertyInvalidatedCache<Query, Result> {
+    ctor public PropertyInvalidatedCache(int, int, @NonNull String, @NonNull String, @NonNull android.app.PropertyInvalidatedCache.QueryHandler<Query,Result>);
+    method public final void disableForCurrentProcess();
+    method public final void invalidateCache();
+    method public static void invalidateCache(int, @NonNull String);
+    method @Nullable public final Result query(@NonNull Query);
+    field public static final int MODULE_BLUETOOTH = 2; // 0x2
+  }
+
+  public abstract static class PropertyInvalidatedCache.QueryHandler<Q, R> {
+    ctor public PropertyInvalidatedCache.QueryHandler();
+    method @Nullable public abstract R apply(@NonNull Q);
+    method public boolean shouldBypassCache(@NonNull Q);
+  }
+
   public class StatusBarManager {
     method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setExpansionDisabledForSimNetworkLock(boolean);
   }
@@ -126,6 +141,7 @@
 
   public abstract class PackageManager {
     method @NonNull public String getPermissionControllerPackageName();
+    method @NonNull public String getSupplementalProcessPackageName();
   }
 
 }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index b3dd7a7..fd716f3 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -76,6 +76,7 @@
     field public static final String BIND_TRANSLATION_SERVICE = "android.permission.BIND_TRANSLATION_SERVICE";
     field public static final String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
     field public static final String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
+    field public static final String BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE = "android.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE";
     field public static final String BLUETOOTH_MAP = "android.permission.BLUETOOTH_MAP";
     field public static final String BRICK = "android.permission.BRICK";
     field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
@@ -191,6 +192,7 @@
     field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
     field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS";
     field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
+    field public static final String MANAGE_WALLPAPER_EFFECTS_GENERATION = "android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION";
     field public static final String MANAGE_WEAK_ESCROW_TOKEN = "android.permission.MANAGE_WEAK_ESCROW_TOKEN";
     field public static final String MANAGE_WIFI_AUTO_JOIN = "android.permission.MANAGE_WIFI_AUTO_JOIN";
     field public static final String MANAGE_WIFI_COUNTRY_CODE = "android.permission.MANAGE_WIFI_COUNTRY_CODE";
@@ -1188,6 +1190,15 @@
     field public static final String WORK_PROFILE_PAUSED_TITLE = "MediaProvider.WORK_PROFILE_PAUSED_TITLE";
   }
 
+  public static final class DevicePolicyResources.Strings.PermissionController {
+    field public static final String BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE = "PermissionController.BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE";
+    field public static final String BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE = "PermissionController.BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE";
+    field public static final String FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE = "PermissionController.FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE";
+    field public static final String HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE = "PermissionController.HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE";
+    field public static final String LOCATION_AUTO_GRANTED_MESSAGE = "PermissionController.LOCATION_AUTO_GRANTED_MESSAGE";
+    field public static final String WORK_PROFILE_DEFAULT_APPS_TITLE = "PermissionController.WORK_PROFILE_DEFAULT_APPS_TITLE";
+  }
+
   public final class DevicePolicyStringResource implements android.os.Parcelable {
     ctor public DevicePolicyStringResource(@NonNull android.content.Context, @NonNull String, @StringRes int);
     method public int describeContents();
@@ -2545,6 +2556,107 @@
 
 }
 
+package android.app.wallpapereffectsgeneration {
+
+  public final class CameraAttributes implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public float[] getAnchorPointInOutputUvSpace();
+    method @NonNull public float[] getAnchorPointInWorldSpace();
+    method public float getCameraOrbitPitchDegrees();
+    method public float getCameraOrbitYawDegrees();
+    method public float getDollyDistanceInWorldSpace();
+    method public float getFrustumFarInWorldSpace();
+    method public float getFrustumNearInWorldSpace();
+    method public float getVerticalFovDegrees();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.wallpapereffectsgeneration.CameraAttributes> CREATOR;
+  }
+
+  public static final class CameraAttributes.Builder {
+    ctor public CameraAttributes.Builder(@NonNull float[], @NonNull float[]);
+    method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes build();
+    method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setCameraOrbitPitchDegrees(@FloatRange(from=-90.0F, to=90.0f) float);
+    method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setCameraOrbitYawDegrees(@FloatRange(from=-180.0F, to=180.0f) float);
+    method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setDollyDistanceInWorldSpace(float);
+    method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setFrustumFarInWorldSpace(@FloatRange(from=0.0f) float);
+    method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setFrustumNearInWorldSpace(@FloatRange(from=0.0f) float);
+    method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setVerticalFovDegrees(@FloatRange(from=0.0f, to=180.0f, fromInclusive=false) float);
+  }
+
+  public final class CinematicEffectRequest implements android.os.Parcelable {
+    ctor public CinematicEffectRequest(@NonNull String, @NonNull android.graphics.Bitmap);
+    method public int describeContents();
+    method @NonNull public android.graphics.Bitmap getBitmap();
+    method @NonNull public String getTaskId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.wallpapereffectsgeneration.CinematicEffectRequest> CREATOR;
+  }
+
+  public final class CinematicEffectResponse implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.app.wallpapereffectsgeneration.CameraAttributes getEndKeyFrame();
+    method public int getImageContentType();
+    method @Nullable public android.app.wallpapereffectsgeneration.CameraAttributes getStartKeyFrame();
+    method public int getStatusCode();
+    method @NonNull public String getTaskId();
+    method @NonNull public java.util.List<android.app.wallpapereffectsgeneration.TexturedMesh> getTexturedMeshes();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CINEMATIC_EFFECT_STATUS_ERROR = 2; // 0x2
+    field public static final int CINEMATIC_EFFECT_STATUS_NOT_READY = 3; // 0x3
+    field public static final int CINEMATIC_EFFECT_STATUS_OK = 1; // 0x1
+    field public static final int CINEMATIC_EFFECT_STATUS_PENDING = 4; // 0x4
+    field public static final int CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS = 5; // 0x5
+    field public static final int CINEMATIC_EFFECT_STATUS_UNKNOWN = 0; // 0x0
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.wallpapereffectsgeneration.CinematicEffectResponse> CREATOR;
+    field public static final int IMAGE_CONTENT_TYPE_LANDSCAPE = 2; // 0x2
+    field public static final int IMAGE_CONTENT_TYPE_OTHER = 3; // 0x3
+    field public static final int IMAGE_CONTENT_TYPE_PEOPLE_PORTRAIT = 1; // 0x1
+    field public static final int IMAGE_CONTENT_TYPE_UNKNOWN = 0; // 0x0
+  }
+
+  public static final class CinematicEffectResponse.Builder {
+    ctor public CinematicEffectResponse.Builder(int, @NonNull String);
+    method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse build();
+    method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse.Builder setEndKeyFrame(@Nullable android.app.wallpapereffectsgeneration.CameraAttributes);
+    method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse.Builder setImageContentType(int);
+    method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse.Builder setStartKeyFrame(@Nullable android.app.wallpapereffectsgeneration.CameraAttributes);
+    method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse.Builder setTexturedMeshes(@NonNull java.util.List<android.app.wallpapereffectsgeneration.TexturedMesh>);
+  }
+
+  public final class TexturedMesh implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.graphics.Bitmap getBitmap();
+    method @NonNull public int[] getIndices();
+    method @NonNull public int getIndicesLayoutType();
+    method @NonNull public float[] getVertices();
+    method @NonNull public int getVerticesLayoutType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.wallpapereffectsgeneration.TexturedMesh> CREATOR;
+    field public static final int INDICES_LAYOUT_TRIANGLES = 1; // 0x1
+    field public static final int INDICES_LAYOUT_UNDEFINED = 0; // 0x0
+    field public static final int VERTICES_LAYOUT_POSITION3_UV2 = 1; // 0x1
+    field public static final int VERTICES_LAYOUT_UNDEFINED = 0; // 0x0
+  }
+
+  public static final class TexturedMesh.Builder {
+    ctor public TexturedMesh.Builder(@NonNull android.graphics.Bitmap);
+    method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh build();
+    method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh.Builder setIndices(@NonNull int[]);
+    method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh.Builder setIndicesLayoutType(int);
+    method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh.Builder setVertices(@NonNull float[]);
+    method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh.Builder setVerticesLayoutType(int);
+  }
+
+  public final class WallpaperEffectsGenerationManager {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION) public void generateCinematicEffect(@NonNull android.app.wallpapereffectsgeneration.CinematicEffectRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager.CinematicEffectListener);
+  }
+
+  public static interface WallpaperEffectsGenerationManager.CinematicEffectListener {
+    method public void onCinematicEffectGenerated(@NonNull android.app.wallpapereffectsgeneration.CinematicEffectResponse);
+  }
+
+}
+
 package android.apphibernation {
 
   public class AppHibernationManager {
@@ -2733,6 +2845,7 @@
     field public static final String UI_TRANSLATION_SERVICE = "ui_translation";
     field public static final String UWB_SERVICE = "uwb";
     field public static final String VR_SERVICE = "vrmanager";
+    field public static final String WALLPAPER_EFFECTS_GENERATION_SERVICE = "wallpaper_effects_generation";
     field public static final String WIFI_NL80211_SERVICE = "wifinl80211";
     field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
     field public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
@@ -3704,6 +3817,7 @@
     method public void sendKeyEvent(int, boolean);
     method public void sendVendorCommand(int, byte[], boolean);
     method public void setVendorCommandListener(@NonNull android.hardware.hdmi.HdmiControlManager.VendorCommandListener);
+    method public void setVendorCommandListener(@NonNull android.hardware.hdmi.HdmiControlManager.VendorCommandListener, int);
   }
 
   public static interface HdmiClient.OnDeviceSelectedListener {
@@ -10285,6 +10399,8 @@
   }
 
   public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
+    method public static int getIntForUser(@NonNull android.content.ContentResolver, @NonNull String, int, int);
+    method @Nullable public static String getStringForUser(@NonNull android.content.ContentResolver, @NonNull String, int);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, @Nullable String, boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String);
     field @Deprecated public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED = "accessibility_display_magnification_navbar_enabled";
@@ -10636,6 +10752,8 @@
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method public abstract void onCancelAttentionCheck(@NonNull android.service.attention.AttentionService.AttentionCallback);
     method public abstract void onCheckAttention(@NonNull android.service.attention.AttentionService.AttentionCallback);
+    method public void onStartProximityUpdates(@NonNull android.service.attention.AttentionService.ProximityCallback);
+    method public void onStopProximityUpdates();
     field public static final int ATTENTION_FAILURE_CAMERA_PERMISSION_ABSENT = 6; // 0x6
     field public static final int ATTENTION_FAILURE_CANCELLED = 3; // 0x3
     field public static final int ATTENTION_FAILURE_PREEMPTED = 4; // 0x4
@@ -10643,6 +10761,7 @@
     field public static final int ATTENTION_FAILURE_UNKNOWN = 2; // 0x2
     field public static final int ATTENTION_SUCCESS_ABSENT = 0; // 0x0
     field public static final int ATTENTION_SUCCESS_PRESENT = 1; // 0x1
+    field public static final double PROXIMITY_UNKNOWN = -1.0;
     field public static final String SERVICE_INTERFACE = "android.service.attention.AttentionService";
   }
 
@@ -10651,6 +10770,10 @@
     method public void onSuccess(int, long);
   }
 
+  public static final class AttentionService.ProximityCallback {
+    method public void onProximityUpdate(double);
+  }
+
 }
 
 package android.service.autofill {
@@ -11074,6 +11197,7 @@
     method public void onCreate();
     method public void onDestroy();
     method public void onGameTaskFocusChanged(boolean);
+    method public void onTransientSystemBarVisibilityFromRevealGestureChanged(boolean);
     method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public final boolean restartGame();
     method public void setTaskOverlayView(@NonNull android.view.View, @NonNull android.view.ViewGroup.LayoutParams);
     method public void takeScreenshot(@NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSession.ScreenshotCallback);
@@ -11503,6 +11627,7 @@
     method @Deprecated public final void grantTrust(CharSequence, long, boolean);
     method public final void grantTrust(CharSequence, long, int);
     method public final void isEscrowTokenActive(long, android.os.UserHandle);
+    method public final void lockUser();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public boolean onConfigure(java.util.List<android.os.PersistableBundle>);
     method public void onDeviceLocked();
@@ -11513,13 +11638,16 @@
     method public void onEscrowTokenStateReceived(long, int);
     method public void onTrustTimeout();
     method public void onUnlockAttempt(boolean);
+    method public void onUserRequestedUnlock();
     method public final void removeEscrowToken(long, android.os.UserHandle);
     method public final void revokeTrust();
     method public final void setManagingTrust(boolean);
     method public final void showKeyguardErrorMessage(@NonNull CharSequence);
     method public final void unlockUserWithToken(long, byte[], android.os.UserHandle);
     field public static final int FLAG_GRANT_TRUST_DISMISS_KEYGUARD = 2; // 0x2
+    field public static final int FLAG_GRANT_TRUST_DISPLAY_MESSAGE = 8; // 0x8
     field public static final int FLAG_GRANT_TRUST_INITIATED_BY_USER = 1; // 0x1
+    field public static final int FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE = 4; // 0x4
     field public static final String SERVICE_INTERFACE = "android.service.trust.TrustAgentService";
     field public static final int TOKEN_STATE_ACTIVE = 1; // 0x1
     field public static final int TOKEN_STATE_INACTIVE = 0; // 0x0
@@ -11695,6 +11823,17 @@
 
 }
 
+package android.service.wallpapereffectsgeneration {
+
+  public abstract class WallpaperEffectsGenerationService extends android.app.Service {
+    ctor public WallpaperEffectsGenerationService();
+    method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
+    method public abstract void onGenerateCinematicEffect(@NonNull android.app.wallpapereffectsgeneration.CinematicEffectRequest);
+    method public final void returnCinematicEffectResponse(@NonNull android.app.wallpapereffectsgeneration.CinematicEffectResponse);
+  }
+
+}
+
 package android.service.watchdog {
 
   public abstract class ExplicitHealthCheckService extends android.app.Service {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 15148a9..bf57bf7 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2,7 +2,6 @@
 package android {
 
   public static final class Manifest.permission {
-    field public static final String ACCESS_KEYGUARD_SECURE_STORAGE = "android.permission.ACCESS_KEYGUARD_SECURE_STORAGE";
     field public static final String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
     field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
     field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
@@ -279,6 +278,7 @@
   }
 
   public final class GameManager {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE) public boolean isAngleEnabled(@NonNull String);
     method public void setGameServiceProvider(@Nullable String);
   }
 
@@ -288,8 +288,8 @@
   }
 
   public class KeyguardManager {
-    method @RequiresPermission(anyOf={android.Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS, android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE}) public boolean checkLock(int, @Nullable byte[]);
-    method @RequiresPermission(anyOf={android.Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS, android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE}) public boolean setLock(int, @Nullable byte[], int, @Nullable byte[]);
+    method @RequiresPermission(anyOf={android.Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS, "android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"}) public boolean checkLock(int, @Nullable byte[]);
+    method @RequiresPermission(anyOf={android.Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS, "android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"}) public boolean setLock(int, @Nullable byte[], int, @Nullable byte[]);
   }
 
   public class LocaleManager {
@@ -356,6 +356,32 @@
     ctor public PictureInPictureUiState(boolean);
   }
 
+  public class PropertyInvalidatedCache<Query, Result> {
+    ctor public PropertyInvalidatedCache(int, int, @NonNull String, @NonNull String, @NonNull android.app.PropertyInvalidatedCache.QueryHandler<Query,Result>);
+    method @NonNull public static String createPropertyName(int, @NonNull String);
+    method public final void disableForCurrentProcess();
+    method public static void disableForTestMode();
+    method public final void disableInstance();
+    method public final void disableSystemWide();
+    method public final void forgetDisableLocal();
+    method public boolean getDisabledState();
+    method public final void invalidateCache();
+    method public static void invalidateCache(int, @NonNull String);
+    method public final boolean isDisabled();
+    method @Nullable public final Result query(@NonNull Query);
+    method public static void setTestMode(boolean);
+    method public void testPropertyName();
+    field public static final int MODULE_BLUETOOTH = 2; // 0x2
+    field public static final int MODULE_SYSTEM = 1; // 0x1
+    field public static final int MODULE_TEST = 0; // 0x0
+  }
+
+  public abstract static class PropertyInvalidatedCache.QueryHandler<Q, R> {
+    ctor public PropertyInvalidatedCache.QueryHandler();
+    method @Nullable public abstract R apply(@NonNull Q);
+    method public boolean shouldBypassCache(@NonNull Q);
+  }
+
   public class StatusBarManager {
     method public void cancelRequestAddTile(@NonNull String);
     method public void clickNotification(@Nullable String, int, int, boolean);
@@ -585,15 +611,6 @@
 
 }
 
-package android.app.trust {
-
-  public class TrustManager {
-    method @RequiresPermission(android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE) public void enableTrustAgentForUserForTest(@NonNull android.content.ComponentName, int);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE) public void reportUserRequestedUnlock(int);
-  }
-
-}
-
 package android.app.usage {
 
   public class NetworkStatsManager {
@@ -784,6 +801,7 @@
     method @NonNull public String getPermissionControllerPackageName();
     method @NonNull public abstract String getServicesSystemSharedLibraryPackageName();
     method @NonNull public abstract String getSharedSystemSharedLibraryPackageName();
+    method @NonNull public String getSupplementalProcessPackageName();
     method @Nullable public String getSystemTextClassifierPackageName();
     method @Nullable public String getWellbeingPackageName();
     method public void holdLock(android.os.IBinder, int);
@@ -2374,14 +2392,6 @@
 
 }
 
-package android.service.trust {
-
-  public class TrustAgentService extends android.app.Service {
-    method public void onUserRequestedUnlock();
-  }
-
-}
-
 package android.service.voice {
 
   public class AlwaysOnHotwordDetector implements android.service.voice.HotwordDetector {
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 6b0aef8..42d2d28 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -571,6 +571,31 @@
      */
     public static final int GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE = 15;
 
+    /**
+     * Action to trigger dpad up keyevent.
+     */
+    public static final int GLOBAL_ACTION_DPAD_UP = 16;
+
+    /**
+     * Action to trigger dpad down keyevent.
+     */
+    public static final int GLOBAL_ACTION_DPAD_DOWN = 17;
+
+    /**
+     * Action to trigger dpad left keyevent.
+     */
+    public static final int GLOBAL_ACTION_DPAD_LEFT = 18;
+
+    /**
+     * Action to trigger dpad right keyevent.
+     */
+    public static final int GLOBAL_ACTION_DPAD_RIGHT = 19;
+
+    /**
+     * Action to trigger dpad center keyevent.
+     */
+    public static final int GLOBAL_ACTION_DPAD_CENTER = 20;
+
     private static final String LOG_TAG = "AccessibilityService";
 
     /**
@@ -2328,10 +2353,16 @@
      * @param action The action to perform.
      * @return Whether the action was successfully performed.
      *
+     * Perform actions using ids like the id constants referenced below:
      * @see #GLOBAL_ACTION_BACK
      * @see #GLOBAL_ACTION_HOME
      * @see #GLOBAL_ACTION_NOTIFICATIONS
      * @see #GLOBAL_ACTION_RECENTS
+     * @see #GLOBAL_ACTION_DPAD_UP
+     * @see #GLOBAL_ACTION_DPAD_DOWN
+     * @see #GLOBAL_ACTION_DPAD_LEFT
+     * @see #GLOBAL_ACTION_DPAD_RIGHT
+     * @see #GLOBAL_ACTION_DPAD_CENTER
      */
     public final boolean performGlobalAction(int action) {
         IAccessibilityServiceConnection connection =
diff --git a/core/java/android/accessibilityservice/TouchInteractionController.java b/core/java/android/accessibilityservice/TouchInteractionController.java
index bb2b8d4..735df80 100644
--- a/core/java/android/accessibilityservice/TouchInteractionController.java
+++ b/core/java/android/accessibilityservice/TouchInteractionController.java
@@ -376,7 +376,7 @@
             throw new IllegalStateException(
                     "State transitions are not allowed without first adding a callback.");
         }
-        if (mState != STATE_TOUCH_INTERACTING) {
+        if (mState != STATE_TOUCH_INTERACTING && mState != STATE_DRAGGING) {
             throw new IllegalStateException(
                     "State transitions are not allowed in " + stateToString(mState));
         }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index b1956ef..20ffa25 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -863,6 +863,18 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public String getSupplementalProcessPackageName() {
+        try {
+            return mPM.getSupplementalProcessPackageName();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     @Override
     public boolean addPermission(PermissionInfo info) {
         return getPermissionManager().addPermission(info, false);
diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java
index 289b348..040399e 100644
--- a/core/java/android/app/GameManager.java
+++ b/core/java/android/app/GameManager.java
@@ -181,14 +181,18 @@
     /**
      * Returns if ANGLE is enabled for a given package and user ID.
      * <p>
+     * ANGLE (Almost Native Graphics Layer Engine) can translate OpenGL ES commands to Vulkan
+     * commands. Enabling ANGLE may improve the performance and/or reduce the power consumption of
+     * applications.
      * The caller must have {@link android.Manifest.permission#MANAGE_GAME_MODE}.
      *
      * @hide
      */
+    @TestApi
     @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
-    public @GameMode boolean getAngleEnabled(@NonNull String packageName) {
+    public @GameMode boolean isAngleEnabled(@NonNull String packageName) {
         try {
-            return mService.getAngleEnabled(packageName, mContext.getUserId());
+            return mService.isAngleEnabled(packageName, mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/IGameManagerService.aidl b/core/java/android/app/IGameManagerService.aidl
index 3ea07676..7035ac0 100644
--- a/core/java/android/app/IGameManagerService.aidl
+++ b/core/java/android/app/IGameManagerService.aidl
@@ -26,7 +26,7 @@
     int getGameMode(String packageName, int userId);
     void setGameMode(String packageName, int gameMode, int userId);
     int[] getAvailableGameModes(String packageName);
-    boolean getAngleEnabled(String packageName, int userId);
+    boolean isAngleEnabled(String packageName, int userId);
     void setGameState(String packageName, in GameState gameState, int userId);
     GameModeInfo getGameModeInfo(String packageName, int userId);
     void setGameServiceProvider(String packageName);
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index ec8d989..715de14 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -16,7 +16,11 @@
 
 package android.app;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -27,9 +31,10 @@
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FastPrintWriter;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -104,17 +109,21 @@
  * <pre>
  * public class ActivityThread {
  *   ...
+ *   private final PropertyInvalidatedCache.QueryHandler&lt;Integer, Birthday&gt; mBirthdayQuery =
+ *       new PropertyInvalidatedCache.QueryHandler&lt;Integer, Birthday&gt;() {
+ *           {@literal @}Override
+ *           public Birthday apply(Integer) {
+ *              return GetService("birthdayd").getUserBirthday(userId);
+ *           }
+ *       };
  *   private static final int BDAY_CACHE_MAX = 8;  // Maximum birthdays to cache
  *   private static final String BDAY_CACHE_KEY = "cache_key.birthdayd";
  *   private final PropertyInvalidatedCache&lt;Integer, Birthday%&gt; mBirthdayCache = new
- *     PropertyInvalidatedCache&lt;Integer, Birthday%&gt;(BDAY_CACHE_MAX, BDAY_CACHE_KEY) {
- *       {@literal @}Override
- *       protected Birthday recompute(Integer userId) {
- *         return GetService("birthdayd").getUserBirthday(userId);
- *       }
- *     };
+ *     PropertyInvalidatedCache&lt;Integer, Birthday%&gt;(
+ *             BDAY_CACHE_MAX, MODULE_SYSTEM, "getUserBirthday", mBirthdayQuery);
+ *
  *   public void disableUserBirthdayCache() {
- *     mBirthdayCache.disableLocal();
+ *     mBirthdayCache.disableForCurrentProcess();
  *   }
  *   public void invalidateUserBirthdayCache() {
  *     mBirthdayCache.invalidateCache();
@@ -221,10 +230,124 @@
  *
  * @param <Query> The class used to index cache entries: must be hashable and comparable
  * @param <Result> The class holding cache entries; use a boxed primitive if possible
- *
- * {@hide}
+ * @hide
  */
-public abstract class PropertyInvalidatedCache<Query, Result> {
+@SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+@TestApi
+public class PropertyInvalidatedCache<Query, Result> {
+    /**
+     * This is a configuration class that customizes a cache instance.
+     * @hide
+     */
+    @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+    @TestApi
+    public static abstract class QueryHandler<Q,R> {
+        /**
+         * Compute a result given a query.  The semantics are those of Functor.
+         */
+        public abstract @Nullable R apply(@NonNull Q query);
+
+        /**
+         * Return true if a query should not use the cache.  The default implementation
+         * always uses the cache.
+         */
+        public boolean shouldBypassCache(@NonNull Q query) {
+            return false;
+        }
+    };
+
+    /**
+     * The system properties used by caches should be of the form <prefix>.<module>.<api>,
+     * where the prefix is "cache_key", the module is one of the constants below, and the
+     * api is any string.  The ability to write the property (which happens during
+     * invalidation) depends on SELinux rules; these rules are defined against
+     * <prefix>.<module>.  Therefore, the module chosen for a cache property must match
+     * the permissions granted to the processes that contain the corresponding caches.
+     * @hide
+     */
+    @IntDef(prefix = { "MODULE_" }, value = {
+                MODULE_TEST,
+                MODULE_SYSTEM,
+                MODULE_BLUETOOTH
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Module {}
+
+    /**
+     * The module used for unit tests and cts tests.  It is expected that no process in
+     * the system has permissions to write properties with this module.
+     * @hide
+     */
+    @TestApi
+    public static final int MODULE_TEST = 0;
+
+    /**
+     * The module used for system server/framework caches.  This is not visible outside
+     * the system processes.
+     * @hide
+     */
+    @TestApi
+    public static final int MODULE_SYSTEM = 1;
+
+    /**
+     * The module used for bluetooth caches.
+     * @hide
+     */
+    @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+    @TestApi
+    public static final int MODULE_BLUETOOTH = 2;
+
+    // A static array mapping module constants to strings.
+    private final static String[] sModuleNames =
+            { "test", "system_server", "bluetooth" };
+
+    /**
+     * Construct a system property that matches the rules described above.  The module is
+     * one of the permitted values above.  The API is a string that is a legal Java simple
+     * identifier.  The api is modified to conform to the system property style guide by
+     * replacing every upper case letter with an underscore and the lower case equivalent.
+     * There is no requirement that the apiName be the name of an actual API.
+     *
+     * Be aware that SystemProperties has a maximum length which is private to the
+     * implementation.  The current maximum is 92 characters. If this method creates a
+     * property name that is too long, SystemProperties.set() will fail without a good
+     * error message.
+     * @hide
+     */
+    @TestApi
+    public static @NonNull String createPropertyName(@Module int module, @NonNull String apiName) {
+        char[] api = apiName.toCharArray();
+        int upper = 0;
+        for (int i = 0; i < api.length; i++) {
+            if (Character.isUpperCase(api[i])) {
+                upper++;
+            }
+        }
+        char[] suffix = new char[api.length + upper];
+        int j = 0;
+        for (int i = 0; i < api.length; i++) {
+            if (Character.isJavaIdentifierPart(api[i])) {
+                if (Character.isUpperCase(api[i])) {
+                    suffix[j++] = '_';
+                    suffix[j++] = Character.toLowerCase(api[i]);
+                } else {
+                    suffix[j++] = api[i];
+                }
+            } else {
+                throw new IllegalArgumentException("invalid api name");
+            }
+        }
+
+        String moduleName = null;
+        try {
+            moduleName = sModuleNames[module];
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw new IllegalArgumentException("invalid module " + module);
+        }
+
+        return "cache_key." + moduleName + "." + new String(suffix);
+    }
+
     /**
      * Reserved nonce values.  Use isReservedNonce() to test for a reserved value.  Note
      * that all values cause the cache to be skipped.
@@ -335,6 +458,25 @@
      */
     private final String mCacheName;
 
+    /**
+     * The function that computes a Result, given a Query.  This function is called on a
+     * cache miss.
+     */
+    private QueryHandler<Query, Result> mComputer;
+
+    /**
+     * A default function that delegates to the deprecated recompute() method.
+     */
+    private static class DefaultComputer<Query, Result> extends QueryHandler<Query, Result> {
+        final PropertyInvalidatedCache<Query, Result> mCache;
+        DefaultComputer(PropertyInvalidatedCache<Query, Result> cache) {
+            mCache = cache;
+        }
+        public Result apply(Query query) {
+            return mCache.recompute(query);
+        }
+    }
+
     @GuardedBy("mLock")
     private final LinkedHashMap<Query, Result> mCache;
 
@@ -359,8 +501,13 @@
      * property name.  New clients should prefer the constructor that takes an explicit
      * cache name.
      *
+     * TODO(216112648): deprecate this as a public interface, in favor of the four-argument
+     * constructor.
+     *
      * @param maxEntries Maximum number of entries to cache; LRU discard
      * @param propertyName Name of the system property holding the cache invalidation nonce.
+     *
+     * @hide
      */
     public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) {
         this(maxEntries, propertyName, propertyName);
@@ -369,32 +516,73 @@
     /**
      * Make a new property invalidated cache.
      *
+     * TODO(216112648): deprecate this as a public interface, in favor of the four-argument
+     * constructor.
+     *
      * @param maxEntries Maximum number of entries to cache; LRU discard
      * @param propertyName Name of the system property holding the cache invalidation nonce
      * @param cacheName Name of this cache in debug and dumpsys
+     * @hide
      */
     public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName,
             @NonNull String cacheName) {
         mPropertyName = propertyName;
         mCacheName = cacheName;
         mMaxEntries = maxEntries;
-        mCache = new LinkedHashMap<Query, Result>(
+        mComputer = new DefaultComputer<>(this);
+        mCache = createMap();
+        registerCache();
+    }
+
+    /**
+     * Make a new property invalidated cache.  The key is computed from the module and api
+     * parameters.
+     *
+     * @param maxEntries Maximum number of entries to cache; LRU discard
+     * @param module The module under which the cache key should be placed.
+     * @param api The api this cache front-ends.  The api must be a Java identifier but
+     * need not be an actual api.
+     * @param cacheName Name of this cache in debug and dumpsys
+     * @param computer The code to compute values that are not in the cache.
+     * @hide
+     */
+    @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+    @TestApi
+    public PropertyInvalidatedCache(int maxEntries, @Module int module, @NonNull String api,
+            @NonNull String cacheName, @NonNull QueryHandler<Query, Result> computer) {
+        mPropertyName = createPropertyName(module, api);
+        mCacheName = cacheName;
+        mMaxEntries = maxEntries;
+        mComputer = computer;
+        mCache = createMap();
+        registerCache();
+    }
+
+    // Create a map.  This should be called only from the constructor.
+    private LinkedHashMap<Query, Result> createMap() {
+        return new LinkedHashMap<Query, Result>(
             2 /* start small */,
             0.75f /* default load factor */,
             true /* LRU access order */) {
+                @GuardedBy("mLock")
                 @Override
                 protected boolean removeEldestEntry(Map.Entry eldest) {
                     final int size = size();
                     if (size > mHighWaterMark) {
                         mHighWaterMark = size;
                     }
-                    if (size > maxEntries) {
+                    if (size > mMaxEntries) {
                         mMissOverflow++;
                         return true;
                     }
                     return false;
                 }
-            };
+        };
+    }
+
+    // Register the map in the global list.  If the cache is disabled globally, disable it
+    // now.
+    private void registerCache() {
         synchronized (sCorkLock) {
             sCaches.put(this, null);
             if (sDisabledKeys.contains(mCacheName)) {
@@ -418,8 +606,9 @@
     /**
      * Enable or disable testing.  The testing property map is cleared every time this
      * method is called.
+     * @hide
      */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    @TestApi
     public static void setTestMode(boolean mode) {
         sTesting = mode;
         synchronized (sTestingPropertyMap) {
@@ -431,13 +620,22 @@
      * Enable testing the specific cache key.  Only keys in the map are subject to testing.
      * There is no method to stop testing a property name.  Just disable the test mode.
      */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-    public static void testPropertyName(@NonNull String name) {
+    private static void testPropertyName(@NonNull String name) {
         synchronized (sTestingPropertyMap) {
             sTestingPropertyMap.put(name, (long) NONCE_UNSET);
         }
     }
 
+    /**
+     * Enable testing the specific cache key.  Only keys in the map are subject to testing.
+     * There is no method to stop testing a property name.  Just disable the test mode.
+     * @hide
+     */
+    @TestApi
+    public void testPropertyName() {
+        testPropertyName(mPropertyName);
+    }
+
     // Read the system property associated with the current cache.  This method uses the
     // handle for faster reading.
     private long getCurrentNonce() {
@@ -490,6 +688,9 @@
 
     /**
      * Forget all cached values.
+     * TODO(216112648) remove this as a public API.  Clients should invalidate caches, not clear
+     * them.
+     * @hide
      */
     public final void clear() {
         synchronized (mLock) {
@@ -505,22 +706,29 @@
      * Fetch a result from scratch in case it's not in the cache at all.  Called unlocked: may
      * block. If this function returns null, the result of the cache query is null. There is no
      * "negative cache" in the query: we don't cache null results at all.
+     * TODO(216112648): deprecate this as a public interface, in favor of an instance of
+     * QueryHandler.
+     * @hide
      */
-    public abstract @NonNull Result recompute(@NonNull Query query);
+    public Result recompute(@NonNull Query query) {
+        return mComputer.apply(query);
+    }
 
     /**
      * Return true if the query should bypass the cache.  The default behavior is to
      * always use the cache but the method can be overridden for a specific class.
+     * TODO(216112648): deprecate this as a public interface, in favor of an instance of
+     * QueryHandler.
+     * @hide
      */
     public boolean bypass(@NonNull Query query) {
-        return false;
+        return mComputer.shouldBypassCache(query);
     }
 
     /**
-     * Determines if a pair of responses are considered equal. Used to determine whether a
-     * cache is inadvertently returning stale results when VERIFY is set to true.  Some
-     * existing clients override this method, but it is now deprecated in favor of a valid
-     * equals() method on the Result class.
+     * Determines if a pair of responses are considered equal. Used to determine whether
+     * a cache is inadvertently returning stale results when VERIFY is set to true.
+     * @hide
      */
     public boolean resultEquals(Result cachedResult, Result fetchedResult) {
         // If a service crashes and returns a null result, the cached value remains valid.
@@ -541,6 +749,7 @@
      * the meantime (if the nonce has changed in the meantime, we drop the cache and try the
      * whole query again), or 3) null, which causes the old value to be removed from the cache
      * and null to be returned as the result of the cache query.
+     * @hide
      */
     protected Result refresh(Result oldResult, Query query) {
         return oldResult;
@@ -551,7 +760,7 @@
      * testing.  To disable a cache in normal code, use disableLocal().
      * @hide
      */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    @TestApi
     public final void disableInstance() {
         synchronized (mLock) {
             mDisabled = true;
@@ -580,9 +789,10 @@
      * disabled remain disabled (the "disabled" setting is sticky).  However, new caches
      * with this name will not be disabled.  It is not an error if the cache name is not
      * found in the list of disabled caches.
+     * @hide
      */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-    public final void clearDisableLocal() {
+    @TestApi
+    public final void forgetDisableLocal() {
         synchronized (sCorkLock) {
             sDisabledKeys.remove(mCacheName);
         }
@@ -592,25 +802,43 @@
      * Disable this cache in the current process, and all other caches that use the same
      * name.  This does not affect caches that have a different name but use the same
      * property.
+     * TODO(216112648) Remove this in favor of disableForCurrentProcess().
+     * @hide
      */
     public final void disableLocal() {
+        disableForCurrentProcess();
+    }
+
+    /**
+     * Disable this cache in the current process, and all other caches that use the same
+     * name.  This does not affect caches that have a different name but use the same
+     * property.
+     * @hide
+     */
+    @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+    @TestApi
+    public final void disableForCurrentProcess() {
         disableLocal(mCacheName);
     }
 
     /**
-     * Return whether the cache is disabled in this process.
+     * Return whether a cache instance is disabled.
+     * @hide
      */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-    public final boolean isDisabledLocal() {
+    @TestApi
+    public final boolean isDisabled() {
         return mDisabled || !sEnabled;
     }
 
     /**
      * Get a value from the cache or recompute it.
+     * @hide
      */
-    public @NonNull Result query(@NonNull Query query) {
+    @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+    @TestApi
+    public final @Nullable Result query(@NonNull Query query) {
         // Let access to mDisabled race: it's atomic anyway.
-        long currentNonce = (!isDisabledLocal()) ? getCurrentNonce() : NONCE_DISABLED;
+        long currentNonce = (!isDisabled()) ? getCurrentNonce() : NONCE_DISABLED;
         if (bypass(query)) {
             currentNonce = NONCE_BYPASS;
         }
@@ -724,8 +952,9 @@
      * When multiple caches share a single property value, using an instance method on one of
      * the cache objects to invalidate all of the cache objects becomes confusing and you should
      * just use the static version of this function.
+     * @hide
      */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    @TestApi
     public final void disableSystemWide() {
         disableSystemWide(mPropertyName);
     }
@@ -746,16 +975,33 @@
     /**
      * Non-static convenience version of invalidateCache() for situations in which only a single
      * PropertyInvalidatedCache is keyed on a particular property value.
+     * @hide
      */
+    @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+    @TestApi
     public final void invalidateCache() {
         invalidateCache(mPropertyName);
     }
 
     /**
+     * Invalidate caches in all processes that are keyed for the module and api.
+     * @hide
+     */
+    @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+    @TestApi
+    public static void invalidateCache(@Module int module, @NonNull String api) {
+        invalidateCache(createPropertyName(module, api));
+    }
+
+    /**
      * Invalidate PropertyInvalidatedCache caches in all processes that are keyed on
      * {@var name}. This function is synchronous: caches are invalidated upon return.
      *
+     * TODO(216112648) make this method private in favor of the two-argument (module, api)
+     * override.
+     *
      * @param name Name of the cache-key property to invalidate
+     * @hide
      */
     public static void invalidateCache(@NonNull String name) {
         if (!sEnabled) {
@@ -824,6 +1070,7 @@
      * corkInvalidations() and uncorkInvalidations() must be called in pairs.
      *
      * @param name Name of the cache-key property to cork
+     * @hide
      */
     public static void corkInvalidations(@NonNull String name) {
         if (!sEnabled) {
@@ -871,6 +1118,7 @@
      * transitioning it to normal operation (unless explicitly disabled system-wide).
      *
      * @param name Name of the cache-key property to uncork
+     * @hide
      */
     public static void uncorkInvalidations(@NonNull String name) {
         if (!sEnabled) {
@@ -916,6 +1164,7 @@
      * The auto-cork delay is configurable but it should not be too long.  The purpose of
      * the delay is to minimize the number of times a server writes to the system property
      * when invalidating the cache.  One write every 50ms does not hurt system performance.
+     * @hide
      */
     public static final class AutoCorker {
         public static final int DEFAULT_AUTO_CORK_DELAY_MS = 50;
@@ -1043,6 +1292,8 @@
      * Return the query as a string, to be used in debug messages.  New clients should not
      * override this, but should instead add the necessary toString() method to the Query
      * class.
+     * TODO(216112648) add a method in the QueryHandler and deprecate this API.
+     * @hide
      */
     protected @NonNull String queryToString(@NonNull Query query) {
         return Objects.toString(query);
@@ -1054,8 +1305,9 @@
      * process does not have privileges to write SystemProperties. Once disabled it is not
      * possible to re-enable caching in the current process.  If a client wants to
      * temporarily disable caching, use the corking mechanism.
+     * @hide
      */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    @TestApi
     public static void disableForTestMode() {
         Log.d(TAG, "disabling all caches in the process");
         sEnabled = false;
@@ -1064,10 +1316,11 @@
     /**
      * Report the disabled status of this cache instance.  The return value does not
      * reflect status of the property key.
+     * @hide
      */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    @TestApi
     public boolean getDisabledState() {
-        return isDisabledLocal();
+        return isDisabled();
     }
 
     /**
@@ -1133,7 +1386,8 @@
     }
 
     /**
-     * Dumps the contents of every cache in the process to the provided ParcelFileDescriptor.
+     * Dumps contents of every cache in the process to the provided ParcelFileDescriptor.
+     * @hide
      */
     public static void dumpCacheInfo(@NonNull ParcelFileDescriptor pfd, @NonNull String[] args) {
         ArrayList<PropertyInvalidatedCache> activeCaches;
@@ -1174,6 +1428,7 @@
 
     /**
      * Trim memory by clearing all the caches.
+     * @hide
      */
     public static void onTrimMemory() {
         for (PropertyInvalidatedCache pic : getActiveCaches()) {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index bbdd705..79180cb 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -51,6 +51,8 @@
 import android.app.usage.NetworkStatsManager;
 import android.app.usage.StorageStatsManager;
 import android.app.usage.UsageStatsManager;
+import android.app.wallpapereffectsgeneration.IWallpaperEffectsGenerationManager;
+import android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager;
 import android.apphibernation.AppHibernationManager;
 import android.appwidget.AppWidgetManager;
 import android.bluetooth.BluetoothFrameworkInitializer;
@@ -1297,6 +1299,20 @@
                     }
                 });
 
+        registerService(Context.WALLPAPER_EFFECTS_GENERATION_SERVICE,
+                WallpaperEffectsGenerationManager.class,
+                new CachedServiceFetcher<WallpaperEffectsGenerationManager>() {
+                    @Override
+                    public WallpaperEffectsGenerationManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        IBinder b = ServiceManager.getService(
+                                Context.WALLPAPER_EFFECTS_GENERATION_SERVICE);
+                        return b == null ? null :
+                                new WallpaperEffectsGenerationManager(
+                                        IWallpaperEffectsGenerationManager.Stub.asInterface(b));
+                    }
+                });
+
         registerService(Context.VR_SERVICE, VrManager.class, new CachedServiceFetcher<VrManager>() {
             @Override
             public VrManager createService(ContextImpl ctx) throws ServiceNotFoundException {
diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java
index cf349b0..ac39cb4 100644
--- a/core/java/android/app/admin/DevicePolicyResources.java
+++ b/core/java/android/app/admin/DevicePolicyResources.java
@@ -93,6 +93,12 @@
 import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.SWITCH_TO_PERSONAL_MESSAGE;
 import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.SWITCH_TO_WORK_MESSAGE;
 import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.WORK_PROFILE_PAUSED_MESSAGE;
+import static android.app.admin.DevicePolicyResources.Strings.PermissionController.BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE;
+import static android.app.admin.DevicePolicyResources.Strings.PermissionController.BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE;
+import static android.app.admin.DevicePolicyResources.Strings.PermissionController.FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE;
+import static android.app.admin.DevicePolicyResources.Strings.PermissionController.HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE;
+import static android.app.admin.DevicePolicyResources.Strings.PermissionController.LOCATION_AUTO_GRANTED_MESSAGE;
+import static android.app.admin.DevicePolicyResources.Strings.PermissionController.WORK_PROFILE_DEFAULT_APPS_TITLE;
 import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_PERSONAL;
 import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_WORK;
 import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_PERSONAL_ACCOUNT_TITLE;
@@ -117,8 +123,8 @@
 import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_LOCK_DEVICE;
 import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_APPS_WARNING;
 import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_BUG_REPORT_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_SECURITY_LOGS_WARNING;
 import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_NETWORK_LOGS_WARNING;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_SECURITY_LOGS_WARNING;
 import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_USAGE_WARNING;
 import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_WORK_DATA_WARNING;
 import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_WIPE_DEVICE;
@@ -500,7 +506,13 @@
             WORK_PROFILE_PRIVACY_POLICY_INFO, CONNECTED_APPS_SEARCH_KEYWORDS,
             WORK_PROFILE_UNIFICATION_SEARCH_KEYWORDS, ACCOUNTS_SEARCH_KEYWORDS,
             CONTROLLED_BY_ADMIN_SUMMARY, WORK_PROFILE_USER_LABEL, WORK_CATEGORY_HEADER,
-            PERSONAL_CATEGORY_HEADER
+            PERSONAL_CATEGORY_HEADER,
+
+            // PermissionController Strings
+            WORK_PROFILE_DEFAULT_APPS_TITLE, HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE,
+            BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE, BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE,
+            BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE, FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE,
+            LOCATION_AUTO_GRANTED_MESSAGE
     })
     public @interface UpdatableStringId {
     }
@@ -690,11 +702,13 @@
 
         private static Set<String> buildStringsSet() {
             Set<String> strings = new HashSet<>();
+            strings.addAll(Settings.buildStringsSet());
             strings.addAll(Launcher.buildStringsSet());
             strings.addAll(SystemUi.buildStringsSet());
             strings.addAll(Core.buildStringsSet());
             strings.addAll(DocumentsUi.buildStringsSet());
             strings.addAll(MediaProvider.buildStringsSet());
+            strings.addAll(PermissionController.buildStringsSet());
             return strings;
         }
 
@@ -2854,5 +2868,71 @@
                 return strings;
             }
         }
+
+        /**
+         * Class containing the identifiers used to update device management-related system strings
+         * in the PermissionController module.
+         */
+        public static final class PermissionController {
+
+            private PermissionController() {
+            }
+
+            private static final String PREFIX = "PermissionController.";
+
+            /**
+             * Title for settings page to show default apps for work.
+             */
+            public static final String WORK_PROFILE_DEFAULT_APPS_TITLE =
+                    PREFIX + "WORK_PROFILE_DEFAULT_APPS_TITLE";
+
+            /**
+             * Summary indicating that a home role holder app is missing work profile support.
+             */
+            public static final String HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE =
+                    PREFIX + "HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE";
+
+            /**
+             * Summary of a permission switch in Settings when the background access is denied by an
+             * admin.
+             */
+            public static final String BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE =
+                    PREFIX + "BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE";
+
+            /**
+             * Summary of a permission switch in Settings when the background access is enabled by
+             * an admin.
+             */
+            public static final String BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE =
+                    PREFIX + "BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE";
+
+            /**
+             * Summary of a permission switch in Settings when the foreground access is enabled by
+             * an admin.
+             */
+            public static final String FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE =
+                    PREFIX + "FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE";
+
+            /**
+             * Body of the notification shown to notify the user that the location permission has
+             * been granted to an app, accepts app name as a param.
+             */
+            public static final String LOCATION_AUTO_GRANTED_MESSAGE =
+                    PREFIX + "LOCATION_AUTO_GRANTED_MESSAGE";
+
+            /**
+             * @hide
+             */
+            static Set<String> buildStringsSet() {
+                Set<String> strings = new HashSet<>();
+                strings.add(WORK_PROFILE_DEFAULT_APPS_TITLE);
+                strings.add(HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE);
+                strings.add(BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE);
+                strings.add(BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE);
+                strings.add(FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE);
+                strings.add(LOCATION_AUTO_GRANTED_MESSAGE);
+                return strings;
+            }
+        }
     }
 }
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index 7956a35..edabccf 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -17,7 +17,6 @@
 package android.app.trust;
 
 import android.app.trust.ITrustListener;
-import android.content.ComponentName;
 import android.hardware.biometrics.BiometricSourceType;
 
 /**
@@ -30,7 +29,6 @@
     void reportUserRequestedUnlock(int userId);
     void reportUnlockLockout(int timeoutMs, int userId);
     void reportEnabledTrustAgentsChanged(int userId);
-    void enableTrustAgentForUserForTest(in ComponentName componentName, int userId);
     void registerTrustListener(in ITrustListener trustListener);
     void unregisterTrustListener(in ITrustListener trustListener);
     void reportKeyguardShowingChanged();
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index fba2d3e..70b7de0 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -16,14 +16,10 @@
 
 package android.app.trust;
 
-import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
-
-import android.annotation.NonNull;
+import android.Manifest;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
-import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
-import android.content.ComponentName;
 import android.content.Context;
 import android.hardware.biometrics.BiometricSourceType;
 import android.os.Handler;
@@ -37,17 +33,9 @@
 import java.util.List;
 
 /**
- * Interface to the system service managing trust.
- *
- * <p>This class is for internal use only. This class is marked {@code @TestApi} to
- * enable testing the trust system including {@link android.service.trust.TrustAgentService}.
- * Methods which are currently not used in tests are marked @hide.
- *
- * @see com.android.server.trust.TrustManagerService
- *
+ * See {@link com.android.server.trust.TrustManagerService}
  * @hide
  */
-@TestApi
 @SystemService(Context.TRUST_SERVICE)
 public class TrustManager {
 
@@ -63,8 +51,7 @@
     private final ITrustManager mService;
     private final ArrayMap<TrustListener, ITrustListener> mTrustListeners;
 
-    /** @hide */
-    public TrustManager(@NonNull IBinder b) {
+    public TrustManager(IBinder b) {
         mService = ITrustManager.Stub.asInterface(b);
         mTrustListeners = new ArrayMap<TrustListener, ITrustListener>();
     }
@@ -75,10 +62,8 @@
      *
      * @param userId The id for the user to be locked/unlocked.
      * @param locked The value for that user's locked state.
-     *
-     * @hide
      */
-    @RequiresPermission(ACCESS_KEYGUARD_SECURE_STORAGE)
+    @RequiresPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE)
     public void setDeviceLockedForUser(int userId, boolean locked) {
         try {
             mService.setDeviceLockedForUser(userId, locked);
@@ -93,11 +78,8 @@
      * @param successful if true, the unlock attempt was successful.
      *
      * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
-     *
-     * @hide
      */
     @UnsupportedAppUsage
-    @RequiresPermission(ACCESS_KEYGUARD_SECURE_STORAGE)
     public void reportUnlockAttempt(boolean successful, int userId) {
         try {
             mService.reportUnlockAttempt(successful, userId);
@@ -111,7 +93,6 @@
      *
      * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
      */
-    @RequiresPermission(ACCESS_KEYGUARD_SECURE_STORAGE)
     public void reportUserRequestedUnlock(int userId) {
         try {
             mService.reportUserRequestedUnlock(userId);
@@ -131,10 +112,7 @@
      *    attempt to unlock the device again.
      *
      * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
-     *
-     * @hide
      */
-    @RequiresPermission(ACCESS_KEYGUARD_SECURE_STORAGE)
     public void reportUnlockLockout(int timeoutMs, int userId) {
         try {
             mService.reportUnlockLockout(timeoutMs, userId);
@@ -147,10 +125,7 @@
      * Reports that the list of enabled trust agents changed for user {@param userId}.
      *
      * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
-     *
-     * @hide
      */
-    @RequiresPermission(ACCESS_KEYGUARD_SECURE_STORAGE)
     public void reportEnabledTrustAgentsChanged(int userId) {
         try {
             mService.reportEnabledTrustAgentsChanged(userId);
@@ -160,33 +135,10 @@
     }
 
     /**
-     * Enables a trust agent.
-     *
-     * <p>The agent is specified by {@code componentName} and must be a subclass of
-     * {@link android.service.trust.TrustAgentService} and otherwise meet the requirements
-     * to be a trust agent.
-     *
-     * <p>This method can only be used in tests.
-     *
-     * @param componentName the trust agent to enable
-     */
-    @RequiresPermission(ACCESS_KEYGUARD_SECURE_STORAGE)
-    public void enableTrustAgentForUserForTest(@NonNull ComponentName componentName, int userId) {
-        try {
-            mService.enableTrustAgentForUserForTest(componentName, userId);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Reports that the visibility of the keyguard has changed.
      *
      * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
-     *
-     * @hide
      */
-    @RequiresPermission(ACCESS_KEYGUARD_SECURE_STORAGE)
     public void reportKeyguardShowingChanged() {
         try {
             mService.reportKeyguardShowingChanged();
@@ -199,10 +151,7 @@
      * Registers a listener for trust events.
      *
      * Requires the {@link android.Manifest.permission#TRUST_LISTENER} permission.
-     *
-     * @hide
      */
-    @RequiresPermission(android.Manifest.permission.TRUST_LISTENER)
     public void registerTrustListener(final TrustListener trustListener) {
         try {
             ITrustListener.Stub iTrustListener = new ITrustListener.Stub() {
@@ -243,10 +192,7 @@
      * Unregisters a listener for trust events.
      *
      * Requires the {@link android.Manifest.permission#TRUST_LISTENER} permission.
-     *
-     * @hide
      */
-    @RequiresPermission(android.Manifest.permission.TRUST_LISTENER)
     public void unregisterTrustListener(final TrustListener trustListener) {
         ITrustListener iTrustListener = mTrustListeners.remove(trustListener);
         if (iTrustListener != null) {
@@ -261,8 +207,6 @@
     /**
      * @return whether {@param userId} has enabled and configured trust agents. Ignores short-term
      * unavailability of trust due to {@link LockPatternUtils.StrongAuthTracker}.
-     *
-     * @hide
      */
     @RequiresPermission(android.Manifest.permission.TRUST_LISTENER)
     public boolean isTrustUsuallyManaged(int userId) {
@@ -279,10 +223,8 @@
      * can be skipped.
      *
      * @param userId
-     *
-     * @hide
      */
-    @RequiresPermission(ACCESS_KEYGUARD_SECURE_STORAGE)
+    @RequiresPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE)
     public void unlockedByBiometricForUser(int userId, BiometricSourceType source) {
         try {
             mService.unlockedByBiometricForUser(userId, source);
@@ -293,10 +235,8 @@
 
     /**
      * Clears authentication by the specified biometric type for all users.
-     *
-     * @hide
      */
-    @RequiresPermission(ACCESS_KEYGUARD_SECURE_STORAGE)
+    @RequiresPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE)
     public void clearAllBiometricRecognized(BiometricSourceType source, int unlockedUser) {
         try {
             mService.clearAllBiometricRecognized(source, unlockedUser);
@@ -324,7 +264,6 @@
         }
     };
 
-    /** @hide */
     public interface TrustListener {
 
         /**
diff --git a/core/java/android/app/wallpapereffectsgeneration/CameraAttributes.java b/core/java/android/app/wallpapereffectsgeneration/CameraAttributes.java
new file mode 100644
index 0000000..dfbc7a4
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/CameraAttributes.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2022 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.app.wallpapereffectsgeneration;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Representing the position and other parameters of camera of a single frame.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CameraAttributes implements Parcelable {
+    /**
+     * The location of the anchor within the 3D scene.
+     * Expecting 3 floats representing the x, y, z coordinates
+     * of the anchor point.
+     */
+    @NonNull
+    private float[] mAnchorPointInWorldSpace;
+    /**
+     * Where the anchor point should project to in the output image.
+     * Expecting 2 floats representing the u,v coordinates of the
+     * anchor point.
+     */
+    @NonNull
+    private float[] mAnchorPointInOutputUvSpace;
+    /**
+     * Specifies the amount of yaw orbit rotation the camera should perform
+     * around the anchor point in world space.
+     */
+    private float mCameraOrbitYawDegrees;
+    /**
+     * Specifies the amount of pitch orbit rotation the camera should perform
+     * around the anchor point in world space.
+     */
+    private float mCameraOrbitPitchDegrees;
+    /**
+     * Specifies by how much the camera should be placed towards the anchor
+     * point in world space, which is also called dolly distance.
+     */
+    private float mDollyDistanceInWorldSpace;
+    /**
+     * Specifies the vertical fov degrees of the virtual image.
+     */
+    private float mVerticalFovDegrees;
+    /**
+     * The frustum of near plane.
+     */
+    private float mFrustumNearInWorldSpace;
+    /**
+     * The frustum of far plane.
+     */
+    private float mFrustumFarInWorldSpace;
+
+    private CameraAttributes(Parcel in) {
+        this.mCameraOrbitYawDegrees = in.readFloat();
+        this.mCameraOrbitPitchDegrees = in.readFloat();
+        this.mDollyDistanceInWorldSpace = in.readFloat();
+        this.mVerticalFovDegrees = in.readFloat();
+        this.mFrustumNearInWorldSpace = in.readFloat();
+        this.mFrustumFarInWorldSpace = in.readFloat();
+        this.mAnchorPointInWorldSpace = in.createFloatArray();
+        this.mAnchorPointInOutputUvSpace = in.createFloatArray();
+    }
+
+    private CameraAttributes(float[] anchorPointInWorldSpace, float[] anchorPointInOutputUvSpace,
+            float cameraOrbitYawDegrees, float cameraOrbitPitchDegrees,
+            float dollyDistanceInWorldSpace,
+            float verticalFovDegrees, float frustumNearInWorldSpace, float frustumFarInWorldSpace) {
+        mAnchorPointInWorldSpace = anchorPointInWorldSpace;
+        mAnchorPointInOutputUvSpace = anchorPointInOutputUvSpace;
+        mCameraOrbitYawDegrees = cameraOrbitYawDegrees;
+        mCameraOrbitPitchDegrees = cameraOrbitPitchDegrees;
+        mDollyDistanceInWorldSpace = dollyDistanceInWorldSpace;
+        mVerticalFovDegrees = verticalFovDegrees;
+        mFrustumNearInWorldSpace = frustumNearInWorldSpace;
+        mFrustumFarInWorldSpace = frustumFarInWorldSpace;
+    }
+
+    /**
+     * Get the location of the anchor within the 3D scene. The response float array contains
+     * 3 floats representing the x, y, z coordinates
+     */
+    @NonNull
+    public float[] getAnchorPointInWorldSpace() {
+        return mAnchorPointInWorldSpace;
+    }
+
+    /**
+     * Get where the anchor point should project to in the output image. The response float
+     * array contains 2 floats representing the u,v coordinates of the anchor point.
+     */
+    @NonNull
+    public float[] getAnchorPointInOutputUvSpace() {
+        return mAnchorPointInOutputUvSpace;
+    }
+
+    /**
+     * Get the camera yaw orbit rotation.
+     */
+    public float getCameraOrbitYawDegrees() {
+        return mCameraOrbitYawDegrees;
+    }
+
+    /**
+     * Get the camera pitch orbit rotation.
+     */
+    public float getCameraOrbitPitchDegrees() {
+        return mCameraOrbitPitchDegrees;
+    }
+
+    /**
+     * Get how many units the camera should be placed towards the anchor point in world space.
+     */
+    public float getDollyDistanceInWorldSpace() {
+        return mDollyDistanceInWorldSpace;
+    }
+
+    /**
+     * Get the camera vertical fov degrees.
+     */
+    public float getVerticalFovDegrees() {
+        return mVerticalFovDegrees;
+    }
+
+    /**
+     * Get the frustum in near plane.
+     */
+    public float getFrustumNearInWorldSpace() {
+        return mFrustumNearInWorldSpace;
+    }
+
+    /**
+     * Get the frustum in far plane.
+     */
+    public float getFrustumFarInWorldSpace() {
+        return mFrustumFarInWorldSpace;
+    }
+
+    @NonNull
+    public static final Creator<CameraAttributes> CREATOR = new Creator<CameraAttributes>() {
+        @Override
+        public CameraAttributes createFromParcel(Parcel in) {
+            return new CameraAttributes(in);
+        }
+
+        @Override
+        public CameraAttributes[] newArray(int size) {
+            return new CameraAttributes[size];
+        }
+    };
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeFloat(mCameraOrbitYawDegrees);
+        out.writeFloat(mCameraOrbitPitchDegrees);
+        out.writeFloat(mDollyDistanceInWorldSpace);
+        out.writeFloat(mVerticalFovDegrees);
+        out.writeFloat(mFrustumNearInWorldSpace);
+        out.writeFloat(mFrustumFarInWorldSpace);
+        out.writeFloatArray(mAnchorPointInWorldSpace);
+        out.writeFloatArray(mAnchorPointInOutputUvSpace);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Builder for {@link CameraAttributes}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+        @NonNull
+        private float[] mAnchorPointInWorldSpace;
+        @NonNull
+        private float[] mAnchorPointInOutputUvSpace;
+        private float mCameraOrbitYawDegrees;
+        private float mCameraOrbitPitchDegrees;
+        private float mDollyDistanceInWorldSpace;
+        private float mVerticalFovDegrees;
+        private float mFrustumNearInWorldSpace;
+        private float mFrustumFarInWorldSpace;
+
+        /**
+         * Constructor with anchor point in world space and anchor point in output image
+         * space.
+         *
+         * @param anchorPointInWorldSpace the location of the anchor within the 3D scene. The
+         *  float array contains 3 floats representing the x, y, z coordinates.
+         * @param anchorPointInOutputUvSpace where the anchor point should project to in the
+         *  output image. The  float array contains 2 floats representing the u,v coordinates
+         *  of the anchor point.
+         *
+         * @hide
+         */
+        @SystemApi
+        public Builder(@NonNull float[] anchorPointInWorldSpace,
+                @NonNull float[] anchorPointInOutputUvSpace) {
+            mAnchorPointInWorldSpace = anchorPointInWorldSpace;
+            mAnchorPointInOutputUvSpace = anchorPointInOutputUvSpace;
+        }
+
+        /**
+         * Sets the camera orbit yaw rotation.
+         */
+        @NonNull
+        public Builder setCameraOrbitYawDegrees(
+                @FloatRange(from = -180.0f, to = 180.0f) float cameraOrbitYawDegrees) {
+            mCameraOrbitYawDegrees = cameraOrbitYawDegrees;
+            return this;
+        }
+
+        /**
+         * Sets the camera orbit pitch rotation.
+         */
+        @NonNull
+        public Builder setCameraOrbitPitchDegrees(
+                @FloatRange(from = -90.0f, to = 90.0f) float cameraOrbitPitchDegrees) {
+            mCameraOrbitPitchDegrees = cameraOrbitPitchDegrees;
+            return this;
+        }
+
+        /**
+         * Sets the camera dolly distance.
+         */
+        @NonNull
+        public Builder setDollyDistanceInWorldSpace(float dollyDistanceInWorldSpace) {
+            mDollyDistanceInWorldSpace = dollyDistanceInWorldSpace;
+            return this;
+        }
+
+        /**
+         * Sets the camera vertical fov degree.
+         */
+        @NonNull
+        public Builder setVerticalFovDegrees(
+                @FloatRange(from = 0.0f, to = 180.0f, fromInclusive = false)
+                        float verticalFovDegrees) {
+            mVerticalFovDegrees = verticalFovDegrees;
+            return this;
+        }
+
+        /**
+         * Sets the frustum in near plane.
+         */
+        @NonNull
+        public Builder setFrustumNearInWorldSpace(
+                @FloatRange(from = 0.0f) float frustumNearInWorldSpace) {
+            mFrustumNearInWorldSpace = frustumNearInWorldSpace;
+            return this;
+        }
+
+        /**
+         * Sets the frustum in far plane.
+         */
+        @NonNull
+        public Builder setFrustumFarInWorldSpace(
+                @FloatRange(from = 0.0f) float frustumFarInWorldSpace) {
+            mFrustumFarInWorldSpace = frustumFarInWorldSpace;
+            return this;
+        }
+
+        /**
+         * Builds a new {@link CameraAttributes} instance.
+         */
+        @NonNull
+        public CameraAttributes build() {
+            return new CameraAttributes(mAnchorPointInWorldSpace,
+                    mAnchorPointInOutputUvSpace,
+                    mCameraOrbitYawDegrees,
+                    mCameraOrbitPitchDegrees,
+                    mDollyDistanceInWorldSpace,
+                    mVerticalFovDegrees,
+                    mFrustumNearInWorldSpace,
+                    mFrustumFarInWorldSpace);
+        }
+    }
+}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.aidl
similarity index 79%
rename from packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl
rename to core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.aidl
index cb602d79..2347746 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl
+++ b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2021, The Android Open Source Project
+ * Copyright (c) 2022, 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.
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net;
+package android.app.wallpapereffectsgeneration;
 
-parcelable NetworkStateSnapshot;
+parcelable CinematicEffectRequest;
\ No newline at end of file
diff --git a/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.java b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.java
new file mode 100644
index 0000000..f2e3313
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2022 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.app.wallpapereffectsgeneration;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * A {@link CinematicEffectRequest} is the data class having all the information
+ * passed to wallpaper effects generation service.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CinematicEffectRequest implements Parcelable {
+    /**
+     * Unique id of a cienmatic effect generation task.
+     */
+    @NonNull
+    private String mTaskId;
+
+    /**
+     * The bitmap to generate cinematic effect from.
+     */
+    @NonNull
+    private Bitmap mBitmap;
+
+    private CinematicEffectRequest(Parcel in) {
+        this.mTaskId = in.readString();
+        this.mBitmap = Bitmap.CREATOR.createFromParcel(in);
+    }
+
+    /**
+     * Constructor with task id and bitmap.
+     */
+    public CinematicEffectRequest(@NonNull String taskId, @NonNull Bitmap bitmap) {
+        mTaskId = taskId;
+        mBitmap = bitmap;
+    }
+
+    /**
+     * Returns the task id.
+     */
+    @NonNull
+    public String getTaskId() {
+        return mTaskId;
+    }
+
+    /**
+     * Returns the bitmap of this request.
+     */
+    @NonNull
+    public Bitmap getBitmap() {
+        return mBitmap;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        CinematicEffectRequest that = (CinematicEffectRequest) o;
+        return mTaskId.equals(that.mTaskId);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mTaskId);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeString(mTaskId);
+        mBitmap.writeToParcel(out, flags);
+    }
+
+    @NonNull
+    public static final Creator<CinematicEffectRequest> CREATOR =
+            new Creator<CinematicEffectRequest>() {
+                @Override
+                public CinematicEffectRequest createFromParcel(Parcel in) {
+                    return new CinematicEffectRequest(in);
+                }
+
+                @Override
+                public CinematicEffectRequest[] newArray(int size) {
+                    return new CinematicEffectRequest[size];
+                }
+            };
+}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.aidl
similarity index 79%
copy from packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl
copy to core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.aidl
index cb602d79..1bd1e1e 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl
+++ b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2021, The Android Open Source Project
+ * Copyright (c) 2022, 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.
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net;
+ package android.app.wallpapereffectsgeneration;
 
-parcelable NetworkStateSnapshot;
+ parcelable CinematicEffectResponse;
\ No newline at end of file
diff --git a/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.java b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.java
new file mode 100644
index 0000000..1254794
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2022 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.app.wallpapereffectsgeneration;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A {@link CinematicEffectResponse} include textured meshes
+ * and camera attributes of key frames.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CinematicEffectResponse implements Parcelable {
+    /** @hide */
+    @IntDef(prefix = {"CINEMATIC_EFFECT_STATUS_"},
+            value = {CINEMATIC_EFFECT_STATUS_UNKNOWN,
+                    CINEMATIC_EFFECT_STATUS_OK,
+                    CINEMATIC_EFFECT_STATUS_ERROR,
+                    CINEMATIC_EFFECT_STATUS_NOT_READY,
+                    CINEMATIC_EFFECT_STATUS_PENDING,
+                    CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CinematicEffectStatusCode {}
+
+    /** Cinematic effect generation unknown status. */
+    public static final int CINEMATIC_EFFECT_STATUS_UNKNOWN = 0;
+    /** Cinematic effect generation success. */
+    public static final int CINEMATIC_EFFECT_STATUS_OK = 1;
+    /** Cinematic effect generation failure. */
+    public static final int CINEMATIC_EFFECT_STATUS_ERROR = 2;
+    /** Service not ready for cinematic effect generation. */
+    public static final int CINEMATIC_EFFECT_STATUS_NOT_READY = 3;
+    /** Cienmatic effect generation process is pending. */
+    public static final int CINEMATIC_EFFECT_STATUS_PENDING = 4;
+    /** Too manay requests for server to handle. */
+    public static final int CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS = 5;
+
+    /** @hide */
+    @IntDef(prefix = {"IMAGE_CONTENT_TYPE_"},
+            value = {IMAGE_CONTENT_TYPE_UNKNOWN,
+                    IMAGE_CONTENT_TYPE_PEOPLE_PORTRAIT,
+                    IMAGE_CONTENT_TYPE_LANDSCAPE,
+                    IMAGE_CONTENT_TYPE_OTHER
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ImageContentType {}
+
+    /** Image content unknown. */
+    public static final int IMAGE_CONTENT_TYPE_UNKNOWN = 0;
+    /** Image content is people portrait. */
+    public static final int IMAGE_CONTENT_TYPE_PEOPLE_PORTRAIT = 1;
+    /** Image content is landscape. */
+    public static final int IMAGE_CONTENT_TYPE_LANDSCAPE = 2;
+    /** Image content is doesn't belong to other types. */
+    public static final int IMAGE_CONTENT_TYPE_OTHER = 3;
+
+
+    @CinematicEffectStatusCode
+    private int mStatusCode;
+
+    /** The id of the cinematic effect generation task. */
+    @NonNull
+    private String mTaskId;
+
+    @ImageContentType
+    private int mImageContentType;
+
+    /** The textured mesh required to render cinematic effect. */
+    @NonNull
+    private List<TexturedMesh> mTexturedMeshes;
+
+    /** The start camera position for animation. */
+    @Nullable
+    private CameraAttributes mStartKeyFrame;
+
+    /** The end camera position for animation. */
+    @Nullable
+    private CameraAttributes mEndKeyFrame;
+
+    private CinematicEffectResponse(Parcel in) {
+        mStatusCode = in.readInt();
+        mTaskId = in.readString();
+        mImageContentType = in.readInt();
+        mTexturedMeshes = new ArrayList<TexturedMesh>();
+        in.readTypedList(mTexturedMeshes, TexturedMesh.CREATOR);
+        mStartKeyFrame = in.readTypedObject(CameraAttributes.CREATOR);
+        mEndKeyFrame = in.readTypedObject(CameraAttributes.CREATOR);
+    }
+
+    private CinematicEffectResponse(@CinematicEffectStatusCode int statusCode,
+            String taskId,
+            @ImageContentType int imageContentType,
+            List<TexturedMesh> texturedMeshes,
+            CameraAttributes startKeyFrame,
+            CameraAttributes endKeyFrame) {
+        mStatusCode = statusCode;
+        mTaskId = taskId;
+        mImageContentType = imageContentType;
+        mStartKeyFrame = startKeyFrame;
+        mEndKeyFrame = endKeyFrame;
+        mTexturedMeshes = texturedMeshes;
+    }
+
+    /** Gets the cinematic effect generation status code. */
+    @CinematicEffectStatusCode
+    public int getStatusCode() {
+        return mStatusCode;
+    }
+
+    /** Get the task id. */
+    @NonNull
+    public String getTaskId() {
+        return mTaskId;
+    }
+
+    /**
+     * Get the image content type, which briefly classifies what's
+     * the content of image, like people portrait, landscape etc.
+     */
+    @ImageContentType
+    public int getImageContentType() {
+        return mImageContentType;
+    }
+
+    /** Get the textured meshes. */
+    @NonNull
+    public List<TexturedMesh> getTexturedMeshes() {
+        return mTexturedMeshes;
+    }
+
+    /**
+     * Get the camera attributes (position info and other parameters, see docs of
+     * {@link CameraAttributes}) of the start key frame on the animation path.
+     */
+    @Nullable
+    public CameraAttributes getStartKeyFrame() {
+        return mStartKeyFrame;
+    }
+
+    /**
+     * Get the camera attributes (position info and other parameters, see docs of
+     * {@link CameraAttributes}) of the end key frame on the animation path.
+     */
+    @Nullable
+    public CameraAttributes getEndKeyFrame() {
+        return mEndKeyFrame;
+    }
+
+    @NonNull
+    public static final Creator<CinematicEffectResponse> CREATOR =
+            new Creator<CinematicEffectResponse>() {
+                @Override
+                public CinematicEffectResponse createFromParcel(Parcel in) {
+                    return new CinematicEffectResponse(in);
+                }
+
+                @Override
+                public CinematicEffectResponse[] newArray(int size) {
+                    return new CinematicEffectResponse[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeInt(mStatusCode);
+        out.writeString(mTaskId);
+        out.writeInt(mImageContentType);
+        out.writeTypedList(mTexturedMeshes, flags);
+        out.writeTypedObject(mStartKeyFrame, flags);
+        out.writeTypedObject(mEndKeyFrame, flags);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        CinematicEffectResponse that = (CinematicEffectResponse) o;
+        return mTaskId.equals(that.mTaskId);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mTaskId);
+    }
+    /**
+     * Builder of {@link CinematicEffectResponse}
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+        @CinematicEffectStatusCode
+        private int mStatusCode;
+        @NonNull
+        private String mTaskId;
+        @ImageContentType
+        private int mImageContentType;
+        @NonNull
+        private List<TexturedMesh> mTexturedMeshes;
+        @Nullable
+        private CameraAttributes mStartKeyFrame;
+        @Nullable
+        private CameraAttributes mEndKeyFrame;
+
+        /**
+         * Constructor with task id and status code.
+         *
+         * @hide
+         */
+        @SystemApi
+        public Builder(@CinematicEffectStatusCode int statusCode, @NonNull String taskId) {
+            mStatusCode = statusCode;
+            mTaskId = taskId;
+        }
+
+        /**
+         * Sets the image content type.
+         */
+        @NonNull
+        public Builder setImageContentType(@ImageContentType int imageContentType) {
+            mImageContentType = imageContentType;
+            return this;
+        }
+
+
+        /**
+         * Sets the textured meshes.
+         */
+        @NonNull
+        public Builder setTexturedMeshes(@NonNull List<TexturedMesh> texturedMeshes) {
+            mTexturedMeshes = texturedMeshes;
+            return this;
+        }
+
+        /**
+         * Sets start key frame.
+         */
+        @NonNull
+        public Builder setStartKeyFrame(@Nullable CameraAttributes startKeyFrame) {
+            mStartKeyFrame = startKeyFrame;
+            return this;
+        }
+
+        /**
+         * Sets end key frame.
+         */
+        @NonNull
+        public Builder setEndKeyFrame(@Nullable CameraAttributes endKeyFrame) {
+            mEndKeyFrame = endKeyFrame;
+            return this;
+        }
+
+        /**
+         * Builds a {@link CinematicEffectResponse} instance.
+         */
+        @NonNull
+        public CinematicEffectResponse build() {
+            if (mTexturedMeshes == null) {
+                // Place holder because build doesn't allow list to be nullable.
+                mTexturedMeshes = new ArrayList<>(0);
+            }
+            return new CinematicEffectResponse(mStatusCode, mTaskId, mImageContentType,
+                    mTexturedMeshes, mStartKeyFrame, mEndKeyFrame);
+        }
+    }
+}
diff --git a/core/java/android/app/wallpapereffectsgeneration/ICinematicEffectListener.aidl b/core/java/android/app/wallpapereffectsgeneration/ICinematicEffectListener.aidl
new file mode 100644
index 0000000..c1a698d
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/ICinematicEffectListener.aidl
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2022, 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.app.wallpapereffectsgeneration;
+
+import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
+
+
+/**
+ * Callback used by system server to notify invoker of {@link WallpaperEffectsGenerationMAnager}
+ * of the cinematic effect generation result.
+ *
+ * @hide
+ */
+oneway interface ICinematicEffectListener {
+  void onCinematicEffectGenerated(in CinematicEffectResponse response);
+}
\ No newline at end of file
diff --git a/core/java/android/app/wallpapereffectsgeneration/IWallpaperEffectsGenerationManager.aidl b/core/java/android/app/wallpapereffectsgeneration/IWallpaperEffectsGenerationManager.aidl
new file mode 100644
index 0000000..706a89c
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/IWallpaperEffectsGenerationManager.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2022, 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.app.wallpapereffectsgeneration;
+
+import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
+import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
+import android.app.wallpapereffectsgeneration.ICinematicEffectListener;
+
+/**
+ * Used by {@link android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager}
+ * to to generate effects.
+ *
+ * @hide
+ */
+oneway interface IWallpaperEffectsGenerationManager {
+  void generateCinematicEffect(in CinematicEffectRequest request,
+        in ICinematicEffectListener listener);
+
+  void returnCinematicEffectResponse(in CinematicEffectResponse response);
+}
\ No newline at end of file
diff --git a/core/java/android/app/wallpapereffectsgeneration/TexturedMesh.java b/core/java/android/app/wallpapereffectsgeneration/TexturedMesh.java
new file mode 100644
index 0000000..630de45
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/TexturedMesh.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2022 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.app.wallpapereffectsgeneration;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * The textured mesh representation, including a texture (bitmap) to sample from when rendering,
+ * and a mesh consisting of primitives such as triangles. The mesh is represented by an indices
+ * array describing the set of primitives in the mesh, and a vertices array that the indices
+ * refer to.
+ *
+ * @hide
+ */
+@SystemApi
+public final class TexturedMesh implements Parcelable {
+    /**
+     * The texture to sample from when rendering mesh.
+     */
+    @NonNull
+    private Bitmap mBitmap;
+
+    /**
+     * The set of primitives as pointers into the vertices.
+     */
+    @NonNull
+    private int[] mIndices;
+
+    /**
+     * The specific vertices that the indices refer to.
+     */
+    @NonNull
+    private float[] mVertices;
+
+    /** @hide */
+    @IntDef(prefix = {"INDICES_LAYOUT_"}, value = {
+            INDICES_LAYOUT_UNDEFINED,
+            INDICES_LAYOUT_TRIANGLES})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface IndicesLayoutType {
+    }
+
+    /** Undefined indices layout */
+    public static final int INDICES_LAYOUT_UNDEFINED = 0;
+    /**
+     * Indices layout is triangle. Vertices are grouped into 3 and each
+     * group forms a triangle.
+     */
+    public static final int INDICES_LAYOUT_TRIANGLES = 1;
+
+    @IndicesLayoutType
+    private int mIndicesLayoutType;
+
+    /** @hide */
+    @IntDef(prefix = {"VERTICES_LAYOUT_"}, value = {
+            VERTICES_LAYOUT_UNDEFINED,
+            VERTICES_LAYOUT_POSITION3_UV2})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface VerticesLayoutType {
+    }
+
+    /**
+     * Undefined vertices layout.
+     */
+    public static final int VERTICES_LAYOUT_UNDEFINED = 0;
+    /**
+     * The vertices array uses 5 numbers to represent a point, in the format
+     * of [x1, y1, z1, u1, v1, x2, y2, z2, u2, v2, ...].
+     */
+    public static final int VERTICES_LAYOUT_POSITION3_UV2 = 1;
+
+    @VerticesLayoutType
+    private int mVerticesLayoutType;
+
+    private TexturedMesh(Parcel in) {
+        this.mIndicesLayoutType = in.readInt();
+        this.mVerticesLayoutType = in.readInt();
+        this.mBitmap = in.readTypedObject(Bitmap.CREATOR);
+        Parcel data = Parcel.obtain();
+        try {
+            byte[] bytes = in.readBlob();
+            data.unmarshall(bytes, 0, bytes.length);
+            data.setDataPosition(0);
+            this.mIndices = data.createIntArray();
+            this.mVertices = data.createFloatArray();
+        } finally {
+            data.recycle();
+        }
+    }
+
+    private TexturedMesh(@NonNull Bitmap bitmap, @NonNull int[] indices,
+            @NonNull float[] vertices, @IndicesLayoutType int indicesLayoutType,
+            @VerticesLayoutType int verticesLayoutType) {
+        mBitmap = bitmap;
+        mIndices = indices;
+        mVertices = vertices;
+        mIndicesLayoutType = indicesLayoutType;
+        mVerticesLayoutType = verticesLayoutType;
+    }
+
+    /** Get the bitmap, which is the texture to sample from when rendering. */
+    @NonNull
+    public Bitmap getBitmap() {
+        return mBitmap;
+    }
+
+    /**
+     * Get the indices as pointers to the vertices array. Depending on the getIndicesLayoutType(),
+     * the primitives may have different shapes. For example, with INDICES_LAYOUT_TRIANGLES,
+     * indices 0, 1, 2 forms a triangle, indices 3, 4, 5 form another triangle.
+     */
+    @NonNull
+    public int[] getIndices() {
+        return mIndices;
+    }
+
+    /**
+     * Get the vertices that the index array refers to. Depending on the getVerticesLayoutType()
+     * result, the vertices array can represent different per-vertex coordinates. For example,
+     * with VERTICES_LAYOUT_POSITION3_UV2 type, vertices are in the format of
+     * [x1, y1, z1, u1, v1, x2, y2, z2, u2, v2, ...].
+     */
+    @NonNull
+    public float[] getVertices() {
+        return mVertices;
+    }
+
+    /** Get the indices layout type. */
+    @IndicesLayoutType
+    @NonNull
+    public int getIndicesLayoutType() {
+        return mIndicesLayoutType;
+    }
+
+    /** Get the indices layout type. */
+    @VerticesLayoutType
+    @NonNull
+    public int getVerticesLayoutType() {
+        return mVerticesLayoutType;
+    }
+
+    @NonNull
+    public static final Creator<TexturedMesh> CREATOR = new Creator<TexturedMesh>() {
+        @Override
+        public TexturedMesh createFromParcel(Parcel in) {
+            return new TexturedMesh(in);
+        }
+
+        @Override
+        public TexturedMesh[] newArray(int size) {
+            return new TexturedMesh[size];
+        }
+    };
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeInt(mIndicesLayoutType);
+        out.writeInt(mVerticesLayoutType);
+        out.writeTypedObject(mBitmap, flags);
+
+        // Indices and vertices can reach 5MB. Write the data as a Blob,
+        // which will be written to ashmem if too large.
+        Parcel data = Parcel.obtain();
+        try {
+            data.writeIntArray(mIndices);
+            data.writeFloatArray(mVertices);
+            out.writeBlob(data.marshall());
+        } finally {
+            data.recycle();
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * A builder for {@link TexturedMesh}
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+        private Bitmap mBitmap;
+        private int[] mIndices;
+        private float[] mVertices;
+        @IndicesLayoutType
+        private int mIndicesLayoutType;
+        @VerticesLayoutType
+        private int mVerticesLayouttype;
+
+        /**
+         * Constructor with bitmap.
+         *
+         * @hide
+         */
+        @SystemApi
+        public Builder(@NonNull Bitmap bitmap) {
+            mBitmap = bitmap;
+        }
+
+        /**
+         * Set the required indices. The indices should represent the primitives. For example,
+         * with INDICES_LAYOUT_TRIANGLES, indices 0, 1, 2 forms a triangle, indices 3, 4, 5
+         * form another triangle.
+         */
+        @NonNull
+        public Builder setIndices(@NonNull int[] indices) {
+            mIndices = indices;
+            return this;
+        }
+
+        /**
+         * Set the required vertices. The vertices array should represent per-vertex coordinates.
+         * For example, with VERTICES_LAYOUT_POSITION3_UV2 type, vertices are in the format of
+         * [x1, y1, z1, u1, v1, x2, y2, z2, u2, v2, ...].
+         *
+         */
+        @NonNull
+        public Builder setVertices(@NonNull float[] vertices) {
+            mVertices = vertices;
+            return this;
+        }
+
+        /**
+         * Set the required indices layout type.
+         */
+        @NonNull
+        public Builder setIndicesLayoutType(@IndicesLayoutType int indicesLayoutType) {
+            mIndicesLayoutType = indicesLayoutType;
+            return this;
+        }
+
+        /**
+         * Set the required vertices layout type.
+         */
+        @NonNull
+        public Builder setVerticesLayoutType(@VerticesLayoutType int verticesLayoutype) {
+            mVerticesLayouttype = verticesLayoutype;
+            return this;
+        }
+
+        /** Builds a TexturedMesh based on the given parameters. */
+        @NonNull
+        public TexturedMesh build() {
+            return new TexturedMesh(mBitmap, mIndices, mVertices, mIndicesLayoutType,
+                    mVerticesLayouttype);
+        }
+    }
+}
diff --git a/core/java/android/app/wallpapereffectsgeneration/WallpaperEffectsGenerationManager.java b/core/java/android/app/wallpapereffectsgeneration/WallpaperEffectsGenerationManager.java
new file mode 100644
index 0000000..5a1d27d
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/WallpaperEffectsGenerationManager.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 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.app.wallpapereffectsgeneration;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+
+import java.util.concurrent.Executor;
+
+/**
+ * A {@link WallpaperEffectsGenerationManager} is the class that passes wallpaper effects
+ * generation requests to wallpaper effect generation service. For example, create a cinematic
+ * and render a cinematic live wallpaper with the response.
+ *
+ * Usage:
+ * <pre>{@code
+ *      mWallpaperEffectsGenerationManager =
+ *          context.getSystemService(WallpaperEffectsGenerationManager.class);
+ *      mWallpaperEffectsGenerationManager.
+ *          generateCinematicEffect(cinematicEffectRequest, response->{
+ *              // proceed cinematic effect response.
+ *          });
+ * }</pre>
+ *
+ * @hide
+ */
+@SystemApi
+@SystemService(Context.WALLPAPER_EFFECTS_GENERATION_SERVICE)
+public final class WallpaperEffectsGenerationManager {
+    /**
+     * Interface for the cinematic effect listener.
+     */
+    public interface CinematicEffectListener {
+        /**
+         * Async call when the cinematic effect response is generated.
+         * Client needs to check the status code of {@link CinematicEffectResponse}
+         * to determine if the effect generation is successful.
+         *
+         * @param response The generated cinematic effect response.
+         */
+        void onCinematicEffectGenerated(@NonNull CinematicEffectResponse response);
+    }
+
+    private final IWallpaperEffectsGenerationManager mService;
+
+    /** @hide */
+    public WallpaperEffectsGenerationManager(
+            @NonNull IWallpaperEffectsGenerationManager service) {
+        mService = service;
+    }
+
+    /**
+     * Execute a {@link android.app.wallpapereffectsgeneration.CinematicEffectRequest} from
+     * the given parameters to the wallpaper effects generation service. After the cinematic
+     * effect response is ready, the given listener is invoked by the system with the response.
+     * The listener may never receive a callback if unexpected error happened when proceeding
+     * request.
+     *
+     * @param request  request to generate cinematic effect.
+     * @param executor where the listener is invoked.
+     * @param listener listener invoked when the cinematic effect response is available.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION)
+    public void generateCinematicEffect(@NonNull CinematicEffectRequest request,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull CinematicEffectListener listener) {
+        try {
+            mService.generateCinematicEffect(request,
+                    new CinematicEffectListenerWrapper(listener, executor));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private static final class CinematicEffectListenerWrapper
+            extends ICinematicEffectListener.Stub {
+        @NonNull
+        private final CinematicEffectListener mListener;
+        @NonNull
+        private final Executor mExecutor;
+
+        CinematicEffectListenerWrapper(@NonNull CinematicEffectListener listener,
+                @NonNull Executor executor) {
+            mListener = listener;
+            mExecutor = executor;
+        }
+
+        @Override
+        public void onCinematicEffectGenerated(CinematicEffectResponse response) {
+            mExecutor.execute(() -> mListener.onCinematicEffectGenerated(response));
+        }
+    }
+}
diff --git a/core/java/android/attention/AttentionManagerInternal.java b/core/java/android/attention/AttentionManagerInternal.java
index 941e9e2e..4e00da1 100644
--- a/core/java/android/attention/AttentionManagerInternal.java
+++ b/core/java/android/attention/AttentionManagerInternal.java
@@ -46,6 +46,25 @@
      */
     public abstract void cancelAttentionCheck(AttentionCallbackInternal callback);
 
+    /**
+     * Requests the continuous updates of proximity signal via the provided callback,
+     * until the given callback is unregistered. Currently, AttentionManagerService only
+     * anticipates one client and updates one client at a time. If a new client wants to
+     * onboard to receiving Proximity updates, please make a feature request to make proximity
+     * feature multi-client before depending on this feature.
+     *
+     * @param callback      a callback that receives the proximity updates
+     * @return {@code true} if the registration should succeed.
+     */
+    public abstract boolean onStartProximityUpdates(ProximityCallbackInternal callback);
+
+    /**
+     * Requests to stop providing continuous updates until the callback is registered.
+     *
+     * @param callback a callback that was used in {@link #onStartProximityUpdates}
+     */
+    public abstract void onStopProximityUpdates(ProximityCallbackInternal callback);
+
     /** Internal interface for attention callback. */
     public abstract static class AttentionCallbackInternal {
         /**
@@ -64,4 +83,13 @@
          */
         public abstract void onFailure(int error);
     }
+
+    /** Internal interface for proximity callback. */
+    public abstract static class ProximityCallbackInternal {
+        /**
+         * @param distance the estimated distance of the user (in meter)
+         * The distance will be PROXIMITY_UNKNOWN if the proximity sensing was inconclusive.
+         */
+        public abstract void onProximityUpdate(double distance);
+    }
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a0864d6..52681630 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5031,6 +5031,20 @@
     public static final String SOUND_TRIGGER_MIDDLEWARE_SERVICE = "soundtrigger_middleware";
 
     /**
+     * Used for getting the wallpaper effects generation service.
+     *
+     * <p><b>NOTE: </b> this service is optional; callers of
+     * {@code Context.getSystemServiceName(WALLPAPER_EFFECTS_GENERATION_SERVICE)} should check for
+     * {@code null}.
+     *
+     * @hide
+     * @see #getSystemService(String)
+     */
+    @SystemApi
+    public static final String WALLPAPER_EFFECTS_GENERATION_SERVICE =
+            "wallpaper_effects_generation";
+
+    /**
      * Used to access {@link MusicRecognitionManagerService}.
      *
      * @hide
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 1c82b38..30aed8b 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -653,6 +653,7 @@
 
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     String getPermissionControllerPackageName();
+    String getSupplementalProcessPackageName();
 
     ParceledListSlice getInstantApps(int userId);
     byte[] getInstantAppCookie(String packageName, int userId);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e5c31d7..aa64700 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5691,6 +5691,20 @@
     }
 
     /**
+     * Returns the package name of the component implementing supplemental process service.
+     *
+     * @return the package name of the component implementing supplemental process service
+     *
+     * @hide
+     */
+    @NonNull
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @TestApi
+    public String getSupplementalProcessPackageName() {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * Add a new dynamic permission to the system.  For this to work, your
      * package must have defined a permission tree through the
      * {@link android.R.styleable#AndroidManifestPermissionTree
diff --git a/core/java/android/hardware/hdmi/HdmiClient.java b/core/java/android/hardware/hdmi/HdmiClient.java
index cee6a5b..b96e4f8 100644
--- a/core/java/android/hardware/hdmi/HdmiClient.java
+++ b/core/java/android/hardware/hdmi/HdmiClient.java
@@ -21,6 +21,8 @@
 public abstract class HdmiClient {
     private static final String TAG = "HdmiClient";
 
+    private static final int UNKNOWN_VENDOR_ID = 0xFFFFFF;
+
     /* package */ final IHdmiControlService mService;
 
     private IHdmiVendorCommandListener mIHdmiVendorCommandListener;
@@ -156,11 +158,25 @@
     }
 
     /**
-     * Sets a listener used to receive incoming vendor-specific command.
+     * Sets a listener used to receive incoming vendor-specific command. This listener will only
+     * receive {@code <Vendor Command>} but will not receive any {@code <Vendor Command with ID>}
+     * messages.
      *
      * @param listener listener object
      */
     public void setVendorCommandListener(@NonNull VendorCommandListener listener) {
+        // Set the vendor ID to INVALID_VENDOR_ID.
+        setVendorCommandListener(listener, UNKNOWN_VENDOR_ID);
+    }
+
+    /**
+     * Sets a listener used to receive incoming vendor-specific command.
+     *
+     * @param listener listener object
+     * @param vendorId The listener is interested in {@code <Vendor Command with ID>} received with
+     *     this vendorId and all {@code <Vendor Command>} messages.
+     */
+    public void setVendorCommandListener(@NonNull VendorCommandListener listener, int vendorId) {
         if (listener == null) {
             throw new IllegalArgumentException("listener cannot be null");
         }
@@ -169,7 +185,7 @@
         }
         try {
             IHdmiVendorCommandListener wrappedListener = getListenerWrapper(listener);
-            mService.addVendorCommandListener(wrappedListener, getDeviceType());
+            mService.addVendorCommandListener(wrappedListener, vendorId);
             mIHdmiVendorCommandListener = wrappedListener;
         } catch (RemoteException e) {
             Log.e(TAG, "failed to set vendor command listener: ", e);
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index ec55e12..9235ba1 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -564,6 +564,32 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface TvSendStandbyOnSleep {}
 
+    // -- Whether a playback device should act on an incoming {@code <Set Menu Language>} message.
+    /**
+     * Confirmation dialog should be shown upon receiving the CEC message.
+     *
+     * @see HdmiControlManager#CEC_SETTING_NAME_SET_MENU_LANGUAGE
+     * @hide
+     */
+    public static final int SET_MENU_LANGUAGE_ENABLED = 1;
+    /**
+     * The message should be ignored.
+     *
+     * @see HdmiControlManager#CEC_SETTING_NAME_SET_MENU_LANGUAGE
+     * @hide
+     */
+    public static final int SET_MENU_LANGUAGE_DISABLED = 0;
+    /**
+     * @see HdmiControlManager#CEC_SETTING_NAME_SET_MENU_LANGUAGE
+     * @hide
+     */
+    @IntDef(prefix = { "SET_MENU_LANGUAGE_" }, value = {
+            SET_MENU_LANGUAGE_ENABLED,
+            SET_MENU_LANGUAGE_DISABLED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SetMenuLanguage {}
+
     // -- The RC profile of a TV panel.
     /**
      * RC profile none.
@@ -818,6 +844,13 @@
     public static final String CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP =
             "tv_send_standby_on_sleep";
     /**
+     * Name of a setting deciding whether {@code <Set Menu Language>} message should be
+     * handled by the framework or ignored.
+     *
+     * @hide
+     */
+    public static final String CEC_SETTING_NAME_SET_MENU_LANGUAGE = "set_menu_language";
+    /**
      * Name of a setting representing the RC profile of a TV panel.
      *
      * @hide
@@ -983,6 +1016,7 @@
         CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
         CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
         CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+        CEC_SETTING_NAME_SET_MENU_LANGUAGE,
         CEC_SETTING_NAME_RC_PROFILE_TV,
         CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
         CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
diff --git a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
index 16adee9..818554d 100644
--- a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
+++ b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
@@ -221,8 +221,8 @@
         }
 
         @Override
-        public void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {
-            HdmiControlServiceWrapper.this.addVendorCommandListener(listener, deviceType);
+        public void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) {
+            HdmiControlServiceWrapper.this.addVendorCommandListener(listener, vendorId);
         }
 
         @Override
@@ -481,7 +481,7 @@
             boolean hasVendorId) {}
 
     /** @hide */
-    public void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {}
+    public void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) {}
 
     /** @hide */
     public void sendStandby(int deviceType, int deviceId) {}
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 6613397..35dd9ed 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -76,7 +76,7 @@
     void askRemoteDeviceToBecomeActiveSource(int physicalAddress);
     void sendVendorCommand(int deviceType, int targetAddress, in byte[] params,
             boolean hasVendorId);
-    void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType);
+    void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId);
     void sendStandby(int deviceType, int deviceId);
     void setHdmiRecordListener(IHdmiRecordListener callback);
     void startOneTouchRecord(int recorderAddress, in byte[] recordSource);
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 27403ec..e1ffd4a 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -112,7 +112,7 @@
     oneway void requestPointerCapture(IBinder inputChannelToken, boolean enabled);
 
     /** Create an input monitor for gestures. */
-    InputMonitor monitorGestureInput(String name, int displayId);
+    InputMonitor monitorGestureInput(IBinder token, String name, int displayId);
 
     // Add a runtime association between the input port and the display port. This overrides any
     // static associations.
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 979e9dd..2fd79cf 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -35,6 +35,7 @@
 import android.hardware.lights.LightState;
 import android.hardware.lights.LightsManager;
 import android.hardware.lights.LightsRequest;
+import android.os.Binder;
 import android.os.BlockUntrustedTouchesMode;
 import android.os.Build;
 import android.os.CombinedVibration;
@@ -1211,7 +1212,7 @@
      */
     public InputMonitor monitorGestureInput(String name, int displayId) {
         try {
-            return mIm.monitorGestureInput(name, displayId);
+            return mIm.monitorGestureInput(new Binder(), name, displayId);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 223b8cc..fc2fbc3 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -346,7 +346,7 @@
      */
     @AnyThread
     public static boolean canImeRenderGesturalNavButtons() {
-        return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, false);
+        return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, true);
     }
 
     /**
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index aa4b83a..0c3514f 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -165,7 +165,7 @@
     private boolean isAngleEnabledByGameMode(Context context, String packageName) {
         try {
             final boolean gameModeEnabledAngle =
-                    (mGameManager != null) && mGameManager.getAngleEnabled(packageName);
+                    (mGameManager != null) && mGameManager.isAngleEnabled(packageName);
             Log.v(TAG, "ANGLE GameManagerService for " + packageName + ": " + gameModeEnabledAngle);
             return gameModeEnabledAngle;
         } catch (SecurityException e) {
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 3bc3ec8..321b364 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -2088,6 +2088,102 @@
     }
 
     /**
+     * Flatten a homogeneous multi-dimensional array with fixed-size.  This delegates to other
+     * APIs to write a one-dimensional array.  Use {@link #readFixedArray(Object)} or
+     * {@link #createFixedArray(Class, int[])} with the same dimensions to unmarshal.
+     *
+     * @param val The array to be written.
+     * @param parcelableFlags Contextual flags as per
+     *   {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}.
+     *   Used only if val is an array of Parcelable objects.
+     * @param dimensions an array of int representing length of each dimension. The array should be
+     *   sized with the exact size of dimensions.
+     *
+     * @see #readFixedArray
+     * @see #createFixedArray
+     * @see #writeBooleanArray
+     * @see #writeByteArray
+     * @see #writeCharArray
+     * @see #writeIntArray
+     * @see #writeLongArray
+     * @see #writeFloatArray
+     * @see #writeDoubleArray
+     * @see #writeBinderArray
+     * @see #writeInterfaceArray
+     * @see #writeTypedArray
+     * @throws BadParcelableException If the array's component type is not supported or if its
+     *   size doesn't match with the given dimensions.
+     */
+    public <T> void writeFixedArray(@Nullable T val, int parcelableFlags,
+            @NonNull int... dimensions) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+        writeFixedArrayInternal(val, parcelableFlags, /*index=*/0, dimensions);
+    }
+
+    private <T> void writeFixedArrayInternal(T val, int parcelableFlags, int index,
+            int[] dimensions) {
+        if (index >= dimensions.length) {
+            throw new BadParcelableException("Array has more dimensions than expected: "
+                + dimensions.length);
+        }
+
+        int length = dimensions[index];
+
+        // val should be an array of length N
+        if (val == null) {
+            throw new BadParcelableException("Non-null array shouldn't have a null array.");
+        }
+        if (!val.getClass().isArray()) {
+            throw new BadParcelableException("Not an array: " + val);
+        }
+        if (Array.getLength(val) != length) {
+            throw new BadParcelableException("bad length: expected " + length + ", but got "
+                + Array.getLength(val));
+        }
+
+        // Delegates to other writers if this is a one-dimensional array.
+        // Otherwise, write component arrays with recursive calls.
+
+        final Class<?> componentType = val.getClass().getComponentType();
+        if (!componentType.isArray() && index + 1 != dimensions.length) {
+            throw new BadParcelableException("Array has fewer dimensions than expected: "
+                + dimensions.length);
+        }
+        if (componentType == boolean.class) {
+            writeBooleanArray((boolean[]) val);
+        } else if (componentType == byte.class) {
+            writeByteArray((byte[]) val);
+        } else if (componentType == char.class) {
+            writeCharArray((char[]) val);
+        } else if (componentType == int.class) {
+            writeIntArray((int[]) val);
+        } else if (componentType == long.class) {
+            writeLongArray((long[]) val);
+        } else if (componentType == float.class) {
+            writeFloatArray((float[]) val);
+        } else if (componentType == double.class) {
+            writeDoubleArray((double[]) val);
+        } else if (componentType == IBinder.class) {
+            writeBinderArray((IBinder[]) val);
+        } else if (IInterface.class.isAssignableFrom(componentType)) {
+            writeInterfaceArray((IInterface[]) val);
+        } else if (Parcelable.class.isAssignableFrom(componentType)) {
+            writeTypedArray((Parcelable[]) val, parcelableFlags);
+        } else if (componentType.isArray()) {
+            writeInt(length);
+            for (int i = 0; i < length; i++) {
+                writeFixedArrayInternal(Array.get(val, i), parcelableFlags, index + 1,
+                        dimensions);
+            }
+        } else {
+            throw new BadParcelableException("unknown type for fixed-size array: " + componentType);
+        }
+    }
+
+    /**
      * Flatten a generic object in to a parcel.  The given Object value may
      * currently be one of the following types:
      *
@@ -3788,6 +3884,317 @@
     }
 
     /**
+     * Read a new multi-dimensional array from a parcel.  If you want to read Parcelable or
+     * IInterface values, use {@link #readFixedArray(Object, Parcelable.Creator)} or
+     * {@link #readFixedArray(Object, Function)}.
+     * @param val the destination array to hold the read values.
+     *
+     * @see #writeTypedArray
+     * @see #readBooleanArray
+     * @see #readByteArray
+     * @see #readCharArray
+     * @see #readIntArray
+     * @see #readLongArray
+     * @see #readFloatArray
+     * @see #readDoubleArray
+     * @see #readBinderArray
+     * @see #readInterfaceArray
+     * @see #readTypedArray
+     */
+    public <T> void readFixedArray(@NonNull T val) {
+        Class<?> componentType = val.getClass().getComponentType();
+        if (componentType == boolean.class) {
+            readBooleanArray((boolean[]) val);
+        } else if (componentType == byte.class) {
+            readByteArray((byte[]) val);
+        } else if (componentType == char.class) {
+            readCharArray((char[]) val);
+        } else if (componentType == int.class) {
+            readIntArray((int[]) val);
+        } else if (componentType == long.class) {
+            readLongArray((long[]) val);
+        } else if (componentType == float.class) {
+            readFloatArray((float[]) val);
+        } else if (componentType == double.class) {
+            readDoubleArray((double[]) val);
+        } else if (componentType == IBinder.class) {
+            readBinderArray((IBinder[]) val);
+        } else if (componentType.isArray()) {
+            int length = readInt();
+            if (length != Array.getLength(val)) {
+                throw new BadParcelableException("Bad length: expected " + Array.getLength(val)
+                    + ", but got " + length);
+            }
+            for (int i = 0; i < length; i++) {
+                readFixedArray(Array.get(val, i));
+            }
+        } else {
+            throw new BadParcelableException("Unknown type for fixed-size array: " + componentType);
+        }
+    }
+
+    /**
+     * Read a new multi-dimensional array of typed interfaces from a parcel.
+     * If you want to read Parcelable values, use
+     * {@link #readFixedArray(Object, Parcelable.Creator)}. For values of other types, use
+     * {@link #readFixedArray(Object)}.
+     * @param val the destination array to hold the read values.
+     */
+    public <T, S extends IInterface> void readFixedArray(@NonNull T val,
+            @NonNull Function<IBinder, S> asInterface) {
+        Class<?> componentType = val.getClass().getComponentType();
+        if (IInterface.class.isAssignableFrom(componentType)) {
+            readInterfaceArray((S[]) val, asInterface);
+        } else if (componentType.isArray()) {
+            int length = readInt();
+            if (length != Array.getLength(val)) {
+                throw new BadParcelableException("Bad length: expected " + Array.getLength(val)
+                    + ", but got " + length);
+            }
+            for (int i = 0; i < length; i++) {
+                readFixedArray(Array.get(val, i), asInterface);
+            }
+        } else {
+            throw new BadParcelableException("Unknown type for fixed-size array: " + componentType);
+        }
+    }
+
+    /**
+     * Read a new multi-dimensional array of typed parcelables from a parcel.
+     * If you want to read IInterface values, use
+     * {@link #readFixedArray(Object, Function)}. For values of other types, use
+     * {@link #readFixedArray(Object)}.
+     * @param val the destination array to hold the read values.
+     */
+    public <T, S extends Parcelable> void readFixedArray(@NonNull T val,
+            @NonNull Parcelable.Creator<S> c) {
+        Class<?> componentType = val.getClass().getComponentType();
+        if (Parcelable.class.isAssignableFrom(componentType)) {
+            readTypedArray((S[]) val, c);
+        } else if (componentType.isArray()) {
+            int length = readInt();
+            if (length != Array.getLength(val)) {
+                throw new BadParcelableException("Bad length: expected " + Array.getLength(val)
+                    + ", but got " + length);
+            }
+            for (int i = 0; i < length; i++) {
+                readFixedArray(Array.get(val, i), c);
+            }
+        } else {
+            throw new BadParcelableException("Unknown type for fixed-size array: " + componentType);
+        }
+    }
+
+    private void ensureClassHasExpectedDimensions(@NonNull Class<?> cls, int numDimension) {
+        if (numDimension <= 0) {
+            throw new BadParcelableException("Fixed-size array should have dimensions.");
+        }
+
+        for (int i = 0; i < numDimension; i++) {
+            if (!cls.isArray()) {
+                throw new BadParcelableException("Array has fewer dimensions than expected: "
+                    + numDimension);
+            }
+            cls = cls.getComponentType();
+        }
+        if (cls.isArray()) {
+            throw new BadParcelableException("Array has more dimensions than expected: "
+                + numDimension);
+        }
+    }
+
+    /**
+     * Read and return a new multi-dimensional array from a parcel.  Returns null if the
+     * previously written array object is null.  If you want to read Parcelable or
+     * IInterface values, use {@link #createFixedArray(Class, Parcelable.Creator, int[])} or
+     * {@link #createFixedArray(Class, Function, int[])}.
+     * @param cls  the Class object for the target array type. (e.g. int[][].class)
+     * @param dimensions an array of int representing length of each dimension.
+     *
+     * @see #writeTypedArray
+     * @see #createBooleanArray
+     * @see #createByteArray
+     * @see #createCharArray
+     * @see #createIntArray
+     * @see #createLongArray
+     * @see #createFloatArray
+     * @see #createDoubleArray
+     * @see #createBinderArray
+     * @see #createInterfaceArray
+     * @see #createTypedArray
+     */
+    @Nullable
+    public <T> T createFixedArray(@NonNull Class<T> cls, @NonNull int... dimensions) {
+        // Check if type matches with dimensions
+        // If type is one-dimensional array, delegate to other creators
+        // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray
+
+        ensureClassHasExpectedDimensions(cls, dimensions.length);
+
+        T val = null;
+        final Class<?> componentType = cls.getComponentType();
+        if (componentType == boolean.class) {
+            val = (T) createBooleanArray();
+        } else if (componentType == byte.class) {
+            val = (T) createByteArray();
+        } else if (componentType == char.class) {
+            val = (T) createCharArray();
+        } else if (componentType == int.class) {
+            val = (T) createIntArray();
+        } else if (componentType == long.class) {
+            val = (T) createLongArray();
+        } else if (componentType == float.class) {
+            val = (T) createFloatArray();
+        } else if (componentType == double.class) {
+            val = (T) createDoubleArray();
+        } else if (componentType == IBinder.class) {
+            val = (T) createBinderArray();
+        } else if (componentType.isArray()) {
+            int length = readInt();
+            if (length < 0) {
+                return null;
+            }
+            if (length != dimensions[0]) {
+                throw new BadParcelableException("Bad length: expected " + dimensions[0]
+                    + ", but got " + length);
+            }
+
+            // Create a multi-dimensional array with an innermost component type and dimensions
+            Class<?> innermost = componentType.getComponentType();
+            while (innermost.isArray()) {
+                innermost = innermost.getComponentType();
+            }
+            val = (T) Array.newInstance(innermost, dimensions);
+            for (int i = 0; i < length; i++) {
+                readFixedArray(Array.get(val, i));
+            }
+            return val;
+        } else {
+            throw new BadParcelableException("Unknown type for fixed-size array: " + componentType);
+        }
+
+        // Check if val is null (which is OK) or has the expected size.
+        // This check doesn't have to be multi-dimensional because multi-dimensional arrays
+        // are created with expected dimensions.
+        if (val != null && Array.getLength(val) != dimensions[0]) {
+            throw new BadParcelableException("Bad length: expected " + dimensions[0] + ", but got "
+                + Array.getLength(val));
+        }
+        return val;
+    }
+
+    /**
+     * Read and return a new multi-dimensional array of typed interfaces from a parcel.
+     * Returns null if the previously written array object is null.  If you want to read
+     * Parcelable values, use {@link #createFixedArray(Class, Parcelable.Creator, int[])}.
+     * For values of other types use {@link #createFixedArray(Class, int[])}.
+     * @param cls  the Class object for the target array type. (e.g. IFoo[][].class)
+     * @param dimensions an array of int representing length of each dimension.
+     */
+    @Nullable
+    public <T, S extends IInterface> T createFixedArray(@NonNull Class<T> cls,
+            @NonNull Function<IBinder, S> asInterface, @NonNull int... dimensions) {
+        // Check if type matches with dimensions
+        // If type is one-dimensional array, delegate to other creators
+        // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray
+
+        ensureClassHasExpectedDimensions(cls, dimensions.length);
+
+        T val = null;
+        final Class<?> componentType = cls.getComponentType();
+        if (IInterface.class.isAssignableFrom(componentType)) {
+            val = (T) createInterfaceArray(n -> (S[]) Array.newInstance(componentType, n),
+                    asInterface);
+        } else if (componentType.isArray()) {
+            int length = readInt();
+            if (length < 0) {
+                return null;
+            }
+            if (length != dimensions[0]) {
+                throw new BadParcelableException("Bad length: expected " + dimensions[0]
+                    + ", but got " + length);
+            }
+
+            // Create a multi-dimensional array with an innermost component type and dimensions
+            Class<?> innermost = componentType.getComponentType();
+            while (innermost.isArray()) {
+                innermost = innermost.getComponentType();
+            }
+            val = (T) Array.newInstance(innermost, dimensions);
+            for (int i = 0; i < length; i++) {
+                readFixedArray(Array.get(val, i), asInterface);
+            }
+            return val;
+        } else {
+            throw new BadParcelableException("Unknown type for fixed-size array: " + componentType);
+        }
+
+        // Check if val is null (which is OK) or has the expected size.
+        // This check doesn't have to be multi-dimensional because multi-dimensional arrays
+        // are created with expected dimensions.
+        if (val != null && Array.getLength(val) != dimensions[0]) {
+            throw new BadParcelableException("Bad length: expected " + dimensions[0] + ", but got "
+                + Array.getLength(val));
+        }
+        return val;
+    }
+
+    /**
+     * Read and return a new multi-dimensional array of typed parcelables from a parcel.
+     * Returns null if the previously written array object is null.  If you want to read
+     * IInterface values, use {@link #createFixedArray(Class, Function, int[])}.
+     * For values of other types use {@link #createFixedArray(Class, int[])}.
+     * @param cls  the Class object for the target array type. (e.g. Foo[][].class)
+     * @param dimensions an array of int representing length of each dimension.
+     */
+    @Nullable
+    public <T, S extends Parcelable> T createFixedArray(@NonNull Class<T> cls,
+            @NonNull Parcelable.Creator<S> c, @NonNull int... dimensions) {
+        // Check if type matches with dimensions
+        // If type is one-dimensional array, delegate to other creators
+        // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray
+
+        ensureClassHasExpectedDimensions(cls, dimensions.length);
+
+        T val = null;
+        final Class<?> componentType = cls.getComponentType();
+        if (Parcelable.class.isAssignableFrom(componentType)) {
+            val = (T) createTypedArray(c);
+        } else if (componentType.isArray()) {
+            int length = readInt();
+            if (length < 0) {
+                return null;
+            }
+            if (length != dimensions[0]) {
+                throw new BadParcelableException("Bad length: expected " + dimensions[0]
+                    + ", but got " + length);
+            }
+
+            // Create a multi-dimensional array with an innermost component type and dimensions
+            Class<?> innermost = componentType.getComponentType();
+            while (innermost.isArray()) {
+                innermost = innermost.getComponentType();
+            }
+            val = (T) Array.newInstance(innermost, dimensions);
+            for (int i = 0; i < length; i++) {
+                readFixedArray(Array.get(val, i), c);
+            }
+            return val;
+        } else {
+            throw new BadParcelableException("Unknown type for fixed-size array: " + componentType);
+        }
+
+        // Check if val is null (which is OK) or has the expected size.
+        // This check doesn't have to be multi-dimensional because multi-dimensional arrays
+        // are created with expected dimensions.
+        if (val != null && Array.getLength(val) != dimensions[0]) {
+            throw new BadParcelableException("Bad length: expected " + dimensions[0] + ", but got "
+                + Array.getLength(val));
+        }
+        return val;
+    }
+
+    /**
      * Write a heterogeneous array of Parcelable objects into the Parcel.
      * Each object in the array is written along with its class name, so
      * that the correct class can later be instantiated.  As a result, this
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 8f50860..78f1cb1 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -546,18 +546,22 @@
     @VibrationEffectSupport
     public final int areAllEffectsSupported(
             @NonNull @VibrationEffect.EffectType int... effectIds) {
-        int support = VIBRATION_EFFECT_SUPPORT_YES;
-        for (int supported : areEffectsSupported(effectIds)) {
-            if (supported == VIBRATION_EFFECT_SUPPORT_NO) {
-                return VIBRATION_EFFECT_SUPPORT_NO;
-            } else if (supported == VIBRATION_EFFECT_SUPPORT_UNKNOWN) {
-                support = VIBRATION_EFFECT_SUPPORT_UNKNOWN;
+        VibratorInfo info = getInfo();
+        int allSupported = VIBRATION_EFFECT_SUPPORT_YES;
+        for (int effectId : effectIds) {
+            switch (info.isEffectSupported(effectId)) {
+                case VIBRATION_EFFECT_SUPPORT_NO:
+                    return VIBRATION_EFFECT_SUPPORT_NO;
+                case VIBRATION_EFFECT_SUPPORT_YES:
+                    continue;
+                default: // VIBRATION_EFFECT_SUPPORT_UNKNOWN
+                    allSupported = VIBRATION_EFFECT_SUPPORT_UNKNOWN;
+                    break;
             }
         }
-        return support;
+        return allSupported;
     }
 
-
     /**
      * Query whether the vibrator supports the given primitives.
      *
@@ -598,8 +602,9 @@
      */
     public final boolean areAllPrimitivesSupported(
             @NonNull @VibrationEffect.Composition.PrimitiveType int... primitiveIds) {
-        for (boolean supported : arePrimitivesSupported(primitiveIds)) {
-            if (!supported) {
+        VibratorInfo info = getInfo();
+        for (int primitiveId : primitiveIds) {
+            if (!info.isPrimitiveSupported(primitiveId)) {
                 return false;
             }
         }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c4fe1a4..ee6f9c0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6094,9 +6094,11 @@
         }
 
         /** @hide */
-        @UnsupportedAppUsage
-        public static String getStringForUser(ContentResolver resolver, String name,
-                int userHandle) {
+        @SystemApi
+        @Nullable
+        @SuppressLint("VisiblySynchronized")
+        public static String getStringForUser(@NonNull ContentResolver resolver,
+                @NonNull String name, int userHandle) {
             if (MOVED_TO_GLOBAL.contains(name)) {
                 Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure"
                         + " to android.provider.Settings.Global.");
@@ -6328,8 +6330,9 @@
         }
 
         /** @hide */
-        @UnsupportedAppUsage
-        public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) {
+        @SystemApi
+        public static int getIntForUser(@NonNull ContentResolver cr, @NonNull String name,
+                int def, int userHandle) {
             String v = getStringForUser(cr, name, userHandle);
             return parseIntSettingWithDefault(v, def);
         }
diff --git a/core/java/android/service/attention/AttentionService.java b/core/java/android/service/attention/AttentionService.java
index 49ab5db..f5c59b5 100644
--- a/core/java/android/service/attention/AttentionService.java
+++ b/core/java/android/service/attention/AttentionService.java
@@ -24,11 +24,14 @@
 import android.content.Intent;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.util.Slog;
 
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+import java.util.Objects;
 
 
 /**
@@ -51,6 +54,7 @@
  */
 @SystemApi
 public abstract class AttentionService extends Service {
+    private static final String LOG_TAG = "AttentionService";
     /**
      * The {@link Intent} that must be declared as handled by the service. To be supported, the
      * service must also require the {@link android.Manifest.permission#BIND_ATTENTION_SERVICE}
@@ -80,6 +84,9 @@
     /** Camera permission is not granted. */
     public static final int ATTENTION_FAILURE_CAMERA_PERMISSION_ABSENT = 6;
 
+    /** Users’ proximity is unknown (proximity sensing was inconclusive and is unsupported). */
+    public static final double PROXIMITY_UNKNOWN = -1;
+
     /**
      * Result codes for when attention check was successful.
      *
@@ -118,6 +125,20 @@
             Preconditions.checkNotNull(callback);
             AttentionService.this.onCancelAttentionCheck(new AttentionCallback(callback));
         }
+
+        /** {@inheritDoc} */
+        @Override
+        public void onStartProximityUpdates(IProximityCallback callback) {
+            Objects.requireNonNull(callback);
+            AttentionService.this.onStartProximityUpdates(new ProximityCallback(callback));
+
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void onStopProximityUpdates() {
+            AttentionService.this.onStopProximityUpdates();
+        }
     };
 
     @Nullable
@@ -143,6 +164,23 @@
      */
     public abstract void onCancelAttentionCheck(@NonNull AttentionCallback callback);
 
+    /**
+     * Requests the continuous updates of proximity signal via the provided callback,
+     * until the given callback is unregistered.
+     *
+     * @param callback the callback to return the result to
+     */
+    public void onStartProximityUpdates(@NonNull ProximityCallback callback) {
+        Slog.w(LOG_TAG, "Override this method.");
+    }
+
+    /**
+     * Requests to stop providing continuous updates until the callback is registered.
+     */
+    public void onStopProximityUpdates() {
+        Slog.w(LOG_TAG, "Override this method.");
+    }
+
     /** Callbacks for AttentionService results. */
     public static final class AttentionCallback {
         @NonNull private final IAttentionCallback mCallback;
@@ -174,4 +212,26 @@
             }
         }
     }
+
+    /** Callbacks for ProximityCallback results. */
+    public static final class ProximityCallback {
+        @NonNull private final WeakReference<IProximityCallback> mCallback;
+
+        private ProximityCallback(@NonNull IProximityCallback callback) {
+            mCallback = new WeakReference<>(callback);
+        }
+
+        /**
+         * @param distance the estimated distance of the user (in meter)
+         * The distance will be PROXIMITY_UNKNOWN if the proximity sensing was inconclusive.
+         *
+         */
+        public void onProximityUpdate(double distance) {
+            try {
+                mCallback.get().onProximityUpdate(distance);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
+    }
 }
diff --git a/core/java/android/service/attention/IAttentionService.aidl b/core/java/android/service/attention/IAttentionService.aidl
index 99e7997..8bb881b 100644
--- a/core/java/android/service/attention/IAttentionService.aidl
+++ b/core/java/android/service/attention/IAttentionService.aidl
@@ -17,6 +17,7 @@
 package android.service.attention;
 
 import android.service.attention.IAttentionCallback;
+import android.service.attention.IProximityCallback;
 
 /**
  * Interface for a concrete implementation to provide to the AttentionManagerService.
@@ -26,4 +27,6 @@
 oneway interface IAttentionService {
     void checkAttention(IAttentionCallback callback);
     void cancelAttentionCheck(IAttentionCallback callback);
+    void onStartProximityUpdates(IProximityCallback callback);
+    void onStopProximityUpdates();
 }
\ No newline at end of file
diff --git a/core/java/android/service/attention/IProximityCallback.aidl b/core/java/android/service/attention/IProximityCallback.aidl
new file mode 100644
index 0000000..9ecf9bc
--- /dev/null
+++ b/core/java/android/service/attention/IProximityCallback.aidl
@@ -0,0 +1,10 @@
+package android.service.attention;
+
+/**
+ * Callback for onStartProximityUpdates request.
+ *
+ * @hide
+ */
+oneway interface IProximityCallback {
+    void onProximityUpdate(double distance);
+}
diff --git a/core/java/android/service/games/GameSession.java b/core/java/android/service/games/GameSession.java
index 9590933..e33f180 100644
--- a/core/java/android/service/games/GameSession.java
+++ b/core/java/android/service/games/GameSession.java
@@ -84,6 +84,15 @@
         }
 
         @Override
+        public void onTransientSystemBarVisibilityFromRevealGestureChanged(
+                boolean visibleDueToGesture) {
+            Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
+                    GameSession::dispatchTransientSystemBarVisibilityFromRevealGestureChanged,
+                    GameSession.this,
+                    visibleDueToGesture));
+        }
+
+        @Override
         public void onTaskFocusChanged(boolean focused) {
             Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
                     GameSession::moveToState, GameSession.this,
@@ -109,6 +118,7 @@
     }
 
     private LifecycleState mLifecycleState = LifecycleState.INITIALIZED;
+    private boolean mAreTransientInsetsVisibleDueToGesture = false;
     private IGameSessionController mGameSessionController;
     private int mTaskId;
     private GameSessionRootView mGameSessionRootView;
@@ -138,11 +148,23 @@
     }
 
     @Hide
-    void doDestroy() {
+    private void doDestroy() {
         mSurfaceControlViewHost.release();
         moveToState(LifecycleState.DESTROYED);
     }
 
+    /** @hide */
+    @VisibleForTesting
+    @MainThread
+    public void dispatchTransientSystemBarVisibilityFromRevealGestureChanged(
+            boolean visibleDueToGesture) {
+        boolean didValueChange = mAreTransientInsetsVisibleDueToGesture != visibleDueToGesture;
+        mAreTransientInsetsVisibleDueToGesture = visibleDueToGesture;
+        if (didValueChange) {
+            onTransientSystemBarVisibilityFromRevealGestureChanged(visibleDueToGesture);
+        }
+    }
+
     /**
      * @hide
      */
@@ -252,7 +274,23 @@
      *
      * @param focused True if the game task is focused, false if the game task is unfocused.
      */
-    public void onGameTaskFocusChanged(boolean focused) {}
+    public void onGameTaskFocusChanged(boolean focused) {
+    }
+
+    /**
+     * Called when the visibility of the transient system bars changed due to the user performing
+     * the reveal gesture. The reveal gesture is defined as a swipe to reveal the transient system
+     * bars that originates from the system bars.
+     *
+     * @param visibleDueToGesture if the transient bars triggered by the reveal gesture are visible.
+     *                            This is {@code true} when the transient system bars become visible
+     *                            due to user performing the reveal gesture. This is {@code false}
+     *                            when the transient system bars are hidden or become permanently
+     *                            visible.
+     */
+    public void onTransientSystemBarVisibilityFromRevealGestureChanged(
+            boolean visibleDueToGesture) {
+    }
 
     /**
      * Sets the task overlay content to an explicit view. This view is placed directly into the game
@@ -344,12 +382,14 @@
 
         /**
          * Called when taking the screenshot failed.
+         *
          * @param statusCode Indicates the reason for failure.
          */
         void onFailure(@ScreenshotFailureStatus int statusCode);
 
         /**
          * Called when taking the screenshot succeeded.
+         *
          * @param bitmap The screenshot.
          */
         void onSuccess(@NonNull Bitmap bitmap);
diff --git a/core/java/android/service/games/IGameSession.aidl b/core/java/android/service/games/IGameSession.aidl
index 71da630..49c36c6 100644
--- a/core/java/android/service/games/IGameSession.aidl
+++ b/core/java/android/service/games/IGameSession.aidl
@@ -21,5 +21,6 @@
  */
 oneway interface IGameSession {
     void onDestroyed();
+    void onTransientSystemBarVisibilityFromRevealGestureChanged(boolean visibleDueToGesture);
     void onTaskFocusChanged(boolean focused);
 }
diff --git a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
index 220e498..6b11e74 100644
--- a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
+++ b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
@@ -26,6 +26,7 @@
 oneway interface ITrustAgentServiceCallback {
     void grantTrust(CharSequence message, long durationMs, int flags);
     void revokeTrust();
+    void lockUser();
     void setManagingTrust(boolean managingTrust);
     void onConfigureCompleted(boolean result, IBinder token);
     void addEscrowToken(in byte[] token, int userId);
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 5bd4235..8f6e1e0 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -21,7 +21,6 @@
 import android.annotation.NonNull;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.app.Service;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
@@ -120,16 +119,15 @@
      * automatically remove trust after some conditions are met (detailed below) with the option for
      * the agent to renew the trust again later.
      *
-     * <p>After this is called, the agent will grant trust until the platform thinks an active user
-     * is no longer using that trust. For example, if the user dismisses keyguard, the platform will
-     * remove trust (this does not automatically lock the device).
+     * <p>After this is called, the agent will grant trust until the platform thinks an active
+     * user is no longer using that trust. This can happen for any reason as determined by the
+     * platform. For example, if the user dismisses keyguard, the platform will remove trust;
+     * since this does not automatically lock the device, this results in the device locking the
+     * next time the screen turns off.
      *
      * <p>When the platform internally removes the agent's trust in this manner, an agent can
      * re-grant it (via a call to grantTrust) without the user having to unlock the device through
      * another method (e.g. PIN). This renewable state only persists for a limited time.
-     *
-     * TODO(b/213631675): Remove @hide
-     * @hide
      */
     public static final int FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE = 1 << 2;
 
@@ -140,9 +138,6 @@
      * Without this flag, the message passed to {@code grantTrust} is only used for debugging
      * purposes. With the flag, it may be displayed to the user as the reason why the device is
      * unlocked.
-     *
-     * TODO(b/213911325): Remove @hide
-     * @hide
      */
     public static final int FLAG_GRANT_TRUST_DISPLAY_MESSAGE = 1 << 3;
 
@@ -310,11 +305,7 @@
      * {@link #grantTrust(CharSequence, long, int)}.
      *
      * @see #FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE
-     *
-     * TODO(b/213631672): Remove @hide and @TestApi
-     * @hide
      */
-    @TestApi
     public void onUserRequestedUnlock() {
     }
 
@@ -626,11 +617,15 @@
      *
      * If the user has no auth method specified, then keyguard will still be shown but can be
      * dismissed normally.
-     *
-     * TODO(b/213631675): Implement & make public
-     * @hide
      */
     public final void lockUser() {
+        if (mCallback != null) {
+            try {
+                mCallback.lockUser();
+            } catch (RemoteException e) {
+                onError("calling lockUser");
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/service/wallpapereffectsgeneration/IWallpaperEffectsGenerationService.aidl b/core/java/android/service/wallpapereffectsgeneration/IWallpaperEffectsGenerationService.aidl
new file mode 100644
index 0000000..ca75d2e
--- /dev/null
+++ b/core/java/android/service/wallpapereffectsgeneration/IWallpaperEffectsGenerationService.aidl
@@ -0,0 +1,28 @@
+
+/*
+ * Copyright (C) 2022 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.service.wallpapereffectsgeneration;
+
+import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
+/**
+ * Interface from the system to WallpaperEffectsGeneration service.
+ *
+ * @hide
+ */
+oneway interface IWallpaperEffectsGenerationService {
+  void onGenerateCinematicEffect(in CinematicEffectRequest request);
+}
\ No newline at end of file
diff --git a/core/java/android/service/wallpapereffectsgeneration/WallpaperEffectsGenerationService.java b/core/java/android/service/wallpapereffectsgeneration/WallpaperEffectsGenerationService.java
new file mode 100644
index 0000000..18b654e
--- /dev/null
+++ b/core/java/android/service/wallpapereffectsgeneration/WallpaperEffectsGenerationService.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 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.service.wallpapereffectsgeneration;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
+import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
+import android.app.wallpapereffectsgeneration.IWallpaperEffectsGenerationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.util.Slog;
+
+/**
+ * A service for handling wallpaper effects generation tasks. It must implement
+ * (onGenerateCinematicEffect} method to generate response and call returnCinematicEffectResponse
+ * to send the response.
+ *
+ * <p>To extend this service, you must declare the service in your manifest file with the
+ * {@link android.Manifest.permission#BIND_WALLPAPER_EFFECTS_GENERATION} permission and includes
+ * an intent filter with the {@link #SERVICE_INTERFACE} action. For example: </p>
+ * <pre>
+ *     <application>
+ *         <service android:name=".CtsWallpaperEffectsGenerationService"
+ *             android:exported="true"
+ *             android:label="CtsWallpaperEffectsGenerationService"
+ *             android:permission="android.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE">
+ *             <intent-filter>
+ *                 <action android:name="android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService"
+ />
+ *             </intent-filter>
+ *         </service>
+ *         <uses-library android:name="android.test.runner"/>
+ *     </application>
+ * </pre>
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class WallpaperEffectsGenerationService extends Service {
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     *
+     * <p>The service must also require the
+     * {@link android.permission#MANAGE_WALLPAPER_EFFECTS_GENERATION}
+     * permission.
+     *
+     * @hide
+     */
+    public static final String SERVICE_INTERFACE =
+            "android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService";
+    private static final boolean DEBUG = false;
+    private static final String TAG = "WallpaperEffectsGenerationService";
+    private Handler mHandler;
+    private IWallpaperEffectsGenerationManager mService;
+
+    private final IWallpaperEffectsGenerationService  mInterface =
+            new IWallpaperEffectsGenerationService.Stub() {
+                @Override
+                public void onGenerateCinematicEffect(CinematicEffectRequest request) {
+                    mHandler.sendMessage(
+                            obtainMessage(
+                                    WallpaperEffectsGenerationService::onGenerateCinematicEffect,
+                                    WallpaperEffectsGenerationService.this, request));
+                }
+            };
+
+    /**
+     * Called when the OS receives a request for generating cinematic effect. On receiving the
+     * request, it extract cinematic information from the input and call
+     * {@link #returnCinematicEffectResponse} with the textured mesh
+     * and metadata wrapped in CinematicEffectResponse.
+     *
+     * @param request the cinematic effect request passed from the client.
+     */
+    public abstract void onGenerateCinematicEffect(@NonNull CinematicEffectRequest request);
+
+    /**
+     * Returns the cinematic effect response. Must be called when cinematic effect
+     * response is generated and ready to be sent back. Otherwise the response won't be
+     * returned.
+     *
+     * @param response the cinematic effect response returned from service provider.
+     */
+    public final void returnCinematicEffectResponse(@NonNull CinematicEffectResponse response) {
+        try {
+            mService.returnCinematicEffectResponse(response);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @CallSuper
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        if (DEBUG) {
+            Log.d(TAG, "onCreate WallpaperEffectsGenerationService");
+        }
+        mHandler = new Handler(Looper.getMainLooper(), null, true);
+        IBinder b = ServiceManager.getService(Context.WALLPAPER_EFFECTS_GENERATION_SERVICE);
+        mService = IWallpaperEffectsGenerationManager.Stub.asInterface(b);
+    }
+
+    @NonNull
+    @Override
+    public final IBinder onBind(@NonNull Intent intent) {
+        if (DEBUG) {
+            Log.d(TAG, "onBind WallpaperEffectsGenerationService");
+        }
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            return mInterface.asBinder();
+        }
+        Slog.w(TAG,
+                "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent);
+        return null;
+    }
+}
diff --git a/core/java/android/view/InputMonitor.java b/core/java/android/view/InputMonitor.java
index ad1f201..8801fe0 100644
--- a/core/java/android/view/InputMonitor.java
+++ b/core/java/android/view/InputMonitor.java
@@ -79,13 +79,17 @@
 
 
 
-    // Code below generated by codegen v1.0.7.
+    // Code below generated by codegen v1.0.23.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
     // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/InputMonitor.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
 
 
     @DataClass.Generated.Member
@@ -126,7 +130,7 @@
 
     @Override
     @DataClass.Generated.Member
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
@@ -141,7 +145,7 @@
     /** @hide */
     @SuppressWarnings({"unchecked", "RedundantCast"})
     @DataClass.Generated.Member
-    /* package-private */ InputMonitor(Parcel in) {
+    /* package-private */ InputMonitor(@NonNull Parcel in) {
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
@@ -167,17 +171,21 @@
         }
 
         @Override
-        public InputMonitor createFromParcel(Parcel in) {
+        public InputMonitor createFromParcel(@NonNull Parcel in) {
             return new InputMonitor(in);
         }
     };
 
     @DataClass.Generated(
-            time = 1571177265149L,
-            codegenVersion = "1.0.7",
+            time = 1637697281750L,
+            codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/view/InputMonitor.java",
             inputSignatures = "private static final  java.lang.String TAG\nprivate static final  boolean DEBUG\nprivate final @android.annotation.NonNull android.view.InputChannel mInputChannel\nprivate final @android.annotation.NonNull android.view.IInputMonitorHost mHost\npublic  void pilferPointers()\npublic  void dispose()\nclass InputMonitor extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true)")
     @Deprecated
     private void __metadata() {}
 
+
+    //@formatter:on
+    // End of generated code
+
 }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 0a33d6c..a31cacf 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -710,6 +710,8 @@
 
     private static final int BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY = 0x0400000;
 
+    private static final int BOOLEAN_PROPERTY_IS_TEXT_SELECTABLE = 0x0800000;
+
     /**
      * Bits that provide the id of a virtual descendant of a view.
      */
@@ -2276,6 +2278,38 @@
     }
 
     /**
+     * Gets if the node has selectable text.
+     *
+     * <p>
+     *     Services should use {@link #ACTION_SET_SELECTION} for selection. Editable text nodes must
+     *     also be selectable. But not all UIs will populate this field, so services should consider
+     *     'isTextSelectable | isEditable' to ensure they don't miss nodes with selectable text.
+     * </p>
+     *
+     * @see #isEditable
+     * @return True if the node has selectable text.
+     */
+    public boolean isTextSelectable() {
+        return getBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_SELECTABLE);
+    }
+
+    /**
+     * Sets if the node has selectable text.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param selectableText True if the node has selectable text, false otherwise.
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public void setTextSelectable(boolean selectableText) {
+        setBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_SELECTABLE, selectableText);
+    }
+
+    /**
      * Gets if the node is editable.
      *
      * @return True if the node is editable, false otherwise.
@@ -4327,8 +4361,12 @@
                 return "ACTION_CANCEL_DRAG";
             case R.id.accessibilityActionDragDrop:
                 return "ACTION_DROP";
-            default:
+            default: {
+                if (action == R.id.accessibilityActionShowSuggestions) {
+                    return "ACTION_SHOW_SUGGESTIONS";
+                }
                 return "ACTION_UNKNOWN";
+            }
         }
     }
 
@@ -4462,6 +4500,7 @@
         builder.append("; importantForAccessibility: ").append(isImportantForAccessibility());
         builder.append("; visible: ").append(isVisibleToUser());
         builder.append("; actions: ").append(mActions);
+        builder.append("; isTextSelectable: ").append(isTextSelectable());
 
         return builder.toString();
     }
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index ab749ee..3914a3c 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -865,6 +865,15 @@
     }
 
     /**
+     * @return if a window animation has outsets applied to it.
+     *
+     * @hide
+     */
+    public boolean hasExtension() {
+        return false;
+    }
+
+    /**
      * If showBackground is {@code true} and this animation is applied on a window, then the windows
      * in the animation will animate with the background associated with this window behind them.
      *
@@ -942,6 +951,21 @@
     }
 
     /**
+     * Gets the transformation to apply a specific point in time. Implementations of this method
+     * should always be kept in sync with getTransformation.
+     *
+     * @param normalizedTime time between 0 and 1 where 0 is the start of the animation and 1 the
+     *                       end.
+     * @param outTransformation A transformation object that is provided by the
+     *        caller and will be filled in by the animation.
+     * @hide
+     */
+    public void getTransformationAt(float normalizedTime, Transformation outTransformation) {
+        final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
+        applyTransformation(interpolatedTime, outTransformation);
+    }
+
+    /**
      * Gets the transformation to apply at a specified point in time. Implementations of this
      * method should always replace the specified Transformation or document they are doing
      * otherwise.
@@ -987,8 +1011,7 @@
                 normalizedTime = 1.0f - normalizedTime;
             }
 
-            final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
-            applyTransformation(interpolatedTime, outTransformation);
+            getTransformationAt(normalizedTime, outTransformation);
         }
 
         if (expired) {
diff --git a/core/java/android/view/animation/AnimationSet.java b/core/java/android/view/animation/AnimationSet.java
index 03c6ca6..a2f3544 100644
--- a/core/java/android/view/animation/AnimationSet.java
+++ b/core/java/android/view/animation/AnimationSet.java
@@ -363,6 +363,26 @@
      * The transformation of an animation set is the concatenation of all of its
      * component animations.
      *
+     * @see android.view.animation.Animation#getTransformationAt
+     * @hide
+     */
+    @Override
+    public void getTransformationAt(float interpolatedTime, Transformation t) {
+        final Transformation temp = mTempTransformation;
+
+        for (int i = mAnimations.size() - 1; i >= 0; --i) {
+            final Animation a = mAnimations.get(i);
+
+            temp.clear();
+            a.getTransformationAt(interpolatedTime, t);
+            t.compose(temp);
+        }
+    }
+
+    /**
+     * The transformation of an animation set is the concatenation of all of its
+     * component animations.
+     *
      * @see android.view.animation.Animation#getTransformation
      */
     @Override
@@ -517,4 +537,15 @@
     public boolean willChangeBounds() {
         return (mFlags & PROPERTY_CHANGE_BOUNDS_MASK) == PROPERTY_CHANGE_BOUNDS_MASK;
     }
+
+    /** @hide */
+    @Override
+    public boolean hasExtension() {
+        for (Animation animation : mAnimations) {
+            if (animation.hasExtension()) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index 7ce0f45..7d1dc76 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -190,6 +190,8 @@
                 anim = new TranslateAnimation(c, attrs);
             } else if (name.equals("cliprect")) {
                 anim = new ClipRectAnimation(c, attrs);
+            } else if (name.equals("extend")) {
+                anim = new ExtendAnimation(c, attrs);
             } else {
                 throw new RuntimeException("Unknown animation name: " + parser.getName());
             }
diff --git a/core/java/android/view/animation/ExtendAnimation.java b/core/java/android/view/animation/ExtendAnimation.java
new file mode 100644
index 0000000..fd627e5
--- /dev/null
+++ b/core/java/android/view/animation/ExtendAnimation.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.animation;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Insets;
+import android.util.AttributeSet;
+
+/**
+ * An animation that controls the outset of an object.
+ *
+ * @hide
+ */
+public class ExtendAnimation extends Animation {
+    protected Insets mFromInsets = Insets.NONE;
+    protected Insets mToInsets = Insets.NONE;
+
+    private int mFromLeftType = ABSOLUTE;
+    private int mFromTopType = ABSOLUTE;
+    private int mFromRightType = ABSOLUTE;
+    private int mFromBottomType = ABSOLUTE;
+
+    private int mToLeftType = ABSOLUTE;
+    private int mToTopType = ABSOLUTE;
+    private int mToRightType = ABSOLUTE;
+    private int mToBottomType = ABSOLUTE;
+
+    private float mFromLeftValue;
+    private float mFromTopValue;
+    private float mFromRightValue;
+    private float mFromBottomValue;
+
+    private float mToLeftValue;
+    private float mToTopValue;
+    private float mToRightValue;
+    private float mToBottomValue;
+
+    /**
+     * Constructor used when an ExtendAnimation is loaded from a resource.
+     *
+     * @param context Application context to use
+     * @param attrs Attribute set from which to read values
+     */
+    public ExtendAnimation(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.ExtendAnimation);
+
+        Description d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ExtendAnimation_fromExtendLeft));
+        mFromLeftType = d.type;
+        mFromLeftValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ExtendAnimation_fromExtendTop));
+        mFromTopType = d.type;
+        mFromTopValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ExtendAnimation_fromExtendRight));
+        mFromRightType = d.type;
+        mFromRightValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ExtendAnimation_fromExtendBottom));
+        mFromBottomType = d.type;
+        mFromBottomValue = d.value;
+
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ExtendAnimation_toExtendLeft));
+        mToLeftType = d.type;
+        mToLeftValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ExtendAnimation_toExtendTop));
+        mToTopType = d.type;
+        mToTopValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ExtendAnimation_toExtendRight));
+        mToRightType = d.type;
+        mToRightValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ExtendAnimation_toExtendBottom));
+        mToBottomType = d.type;
+        mToBottomValue = d.value;
+
+        a.recycle();
+    }
+
+    /**
+     * Constructor to use when building an ExtendAnimation from code
+     *
+     * @param fromInsets the insets to animate from
+     * @param toInsets the insets to animate to
+     */
+    public ExtendAnimation(Insets fromInsets, Insets toInsets) {
+        if (fromInsets == null || toInsets == null) {
+            throw new RuntimeException("Expected non-null animation outsets");
+        }
+        mFromLeftValue = -fromInsets.left;
+        mFromTopValue = -fromInsets.top;
+        mFromRightValue = -fromInsets.right;
+        mFromBottomValue = -fromInsets.bottom;
+
+        mToLeftValue = -toInsets.left;
+        mToTopValue = -toInsets.top;
+        mToRightValue = -toInsets.right;
+        mToBottomValue = -toInsets.bottom;
+    }
+
+    /**
+     * Constructor to use when building an ExtendAnimation from code
+     */
+    public ExtendAnimation(int fromL, int fromT, int fromR, int fromB,
+            int toL, int toT, int toR, int toB) {
+        this(Insets.of(-fromL, -fromT, -fromR, -fromB), Insets.of(-toL, -toT, -toR, -toB));
+    }
+
+    @Override
+    protected void applyTransformation(float it, Transformation tr) {
+        int l = mFromInsets.left + (int) ((mToInsets.left - mFromInsets.left) * it);
+        int t = mFromInsets.top + (int) ((mToInsets.top - mFromInsets.top) * it);
+        int r = mFromInsets.right + (int) ((mToInsets.right - mFromInsets.right) * it);
+        int b = mFromInsets.bottom + (int) ((mToInsets.bottom - mFromInsets.bottom) * it);
+        tr.setInsets(l, t, r, b);
+    }
+
+    @Override
+    public boolean willChangeTransformationMatrix() {
+        return false;
+    }
+
+    /** @hide */
+    @Override
+    public boolean hasExtension() {
+        return mFromInsets.left < 0 || mFromInsets.top < 0 || mFromInsets.right < 0
+                || mFromInsets.bottom < 0;
+    }
+
+    @Override
+    public void initialize(int width, int height, int parentWidth, int parentHeight) {
+        super.initialize(width, height, parentWidth, parentHeight);
+        // We remove any negative extension (i.e. positive insets) and set those to 0
+        mFromInsets = Insets.min(Insets.of(
+                    -(int) resolveSize(mFromLeftType, mFromLeftValue, width, parentWidth),
+                    -(int) resolveSize(mFromTopType, mFromTopValue, height, parentHeight),
+                    -(int) resolveSize(mFromRightType, mFromRightValue, width, parentWidth),
+                    -(int) resolveSize(mFromBottomType, mFromBottomValue, height, parentHeight)
+                ), Insets.NONE);
+        mToInsets = Insets.min(Insets.of(
+                    -(int) resolveSize(mToLeftType, mToLeftValue, width, parentWidth),
+                    -(int) resolveSize(mToTopType, mToTopValue, height, parentHeight),
+                    -(int) resolveSize(mToRightType, mToRightValue, width, parentWidth),
+                    -(int) resolveSize(mToBottomType, mToBottomValue, height, parentHeight)
+                ), Insets.NONE);
+    }
+}
diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java
index b35a66e..bd62308 100644
--- a/core/java/android/view/animation/Transformation.java
+++ b/core/java/android/view/animation/Transformation.java
@@ -18,6 +18,7 @@
 
 import android.annotation.FloatRange;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 
@@ -53,6 +54,8 @@
     private boolean mHasClipRect;
     private Rect mClipRect = new Rect();
 
+    private Insets mInsets = Insets.NONE;
+
     /**
      * Creates a new transformation with alpha = 1 and the identity matrix.
      */
@@ -132,8 +135,9 @@
                 setClipRect(bounds);
             }
         }
+        setInsets(Insets.add(getInsets(), t.getInsets()));
     }
-    
+
     /**
      * Like {@link #compose(Transformation)} but does this.postConcat(t) of
      * the transformation matrix.
@@ -160,7 +164,7 @@
     public Matrix getMatrix() {
         return mMatrix;
     }
-    
+
     /**
      * Sets the degree of transparency
      * @param alpha 1.0 means fully opaqe and 0.0 means fully transparent
@@ -170,6 +174,13 @@
     }
 
     /**
+     * @return The degree of transparency
+     */
+    public float getAlpha() {
+        return mAlpha;
+    }
+
+    /**
      * Sets the current Transform's clip rect
      * @hide
      */
@@ -203,12 +214,29 @@
     }
 
     /**
-     * @return The degree of transparency
+     * Sets the current Transform's insets
+     * @hide
      */
-    public float getAlpha() {
-        return mAlpha;
+    public void setInsets(Insets insets) {
+        mInsets = insets;
     }
-    
+
+    /**
+     * Sets the current Transform's insets
+     * @hide
+     */
+    public void setInsets(int left, int top, int right, int bottom) {
+        mInsets = Insets.of(left, top, right, bottom);
+    }
+
+    /**
+     * Returns the current Transform's outset rect
+     * @hide
+     */
+    public Insets getInsets() {
+        return mInsets;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder(64);
@@ -216,7 +244,7 @@
         toShortString(sb);
         return sb.toString();
     }
-    
+
     /**
      * Return a string representation of the transformation in a compact form.
      */
@@ -225,7 +253,7 @@
         toShortString(sb);
         return sb.toString();
     }
-    
+
     /**
      * @hide
      */
@@ -234,7 +262,7 @@
         sb.append(" matrix="); sb.append(mMatrix.toShortString());
         sb.append('}');
     }
-    
+
     /**
      * Print short string, to optimize dumping.
      * @hide
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7c939ac..0fe2ed5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -12289,6 +12289,7 @@
                     EXTRA_DATA_RENDERING_INFO_KEY,
                     EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
             ));
+            info.setTextSelectable(isTextSelectable());
         } else {
             info.setAvailableExtraData(Arrays.asList(
                     EXTRA_DATA_RENDERING_INFO_KEY
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index ece6f2f3..37c96e7 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -98,6 +98,10 @@
 
     private static final String DEFAULT_PACKAGE = "android";
 
+    // TODO (b/215515255): remove once we full migrate to shell transitions
+    private static final boolean SHELL_TRANSITIONS_ENABLED =
+            SystemProperties.getBoolean("persist.debug.shell_transit", false);
+
     private final Context mContext;
     private final String mTag;
 
@@ -252,6 +256,9 @@
                 resId = ent.array.getResourceId(animAttr, 0);
             }
         }
+        if (!SHELL_TRANSITIONS_ENABLED) {
+            resId = updateToLegacyIfNeeded(resId);
+        }
         resId = updateToTranslucentAnimIfNeeded(resId, transit);
         if (ResourceId.isValid(resId)) {
             return loadAnimationSafely(context, resId, mTag);
@@ -259,6 +266,24 @@
         return null;
     }
 
+    /**
+     * Replace animations that are not compatible with the legacy transition system with ones that
+     * are compatible with it.
+     * TODO (b/215515255): remove once we full migrate to shell transitions
+     */
+    private int updateToLegacyIfNeeded(int anim) {
+        if (anim == R.anim.activity_open_enter) {
+            return R.anim.activity_open_enter_legacy;
+        } else if (anim == R.anim.activity_open_exit) {
+            return R.anim.activity_open_exit_legacy;
+        } else if (anim == R.anim.activity_close_enter) {
+            return R.anim.activity_close_enter_legacy;
+        } else if (anim == R.anim.activity_close_exit) {
+            return R.anim.activity_close_exit_legacy;
+        }
+        return anim;
+    }
+
     /** Load animation by attribute Id from a specific AnimationStyle resource. */
     @Nullable
     public Animation loadAnimationAttr(String packageName, int animStyleResId, int animAttr,
diff --git a/core/proto/android/server/Android.bp b/core/proto/android/server/Android.bp
new file mode 100644
index 0000000..362daa7
--- /dev/null
+++ b/core/proto/android/server/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2021 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+filegroup {
+  name: "srcs_bluetooth_manager_service_proto",
+  srcs: [
+      "bluetooth_manager_service.proto",
+  ],
+  visibility: ["//packages/modules/Bluetooth:__subpackages__"],
+}
+
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9bcd7d2..85504ce 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4125,6 +4125,16 @@
     <permission android:name="android.permission.BIND_CONTENT_SUGGESTIONS_SERVICE"
                 android:protectionLevel="signature" />
 
+    <!-- Must be required by a
+         android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService,
+         to ensure that only the system can bind to it.
+         @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+         <p>Protection level: signature
+   -->
+    <permission android:name="android.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE"
+        android:protectionLevel="signature" />
+
+
     <!-- Must be declared by a android.service.musicrecognition.MusicRecognitionService,
          to ensure that only the system can bind to it.
          @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
@@ -5378,7 +5388,7 @@
                 android:protectionLevel="signature|setup|role" />
 
     <!-- Allows access to keyguard secure storage.  Only allowed for system processes.
-         @hide @TestApi -->
+        @hide -->
     <permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
         android:protectionLevel="signature|setup" />
 
@@ -5824,6 +5834,13 @@
     <permission android:name="android.permission.MANAGE_SMARTSPACE"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows an application to manage the wallpaper effects
+     generation service.
+        @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION"
+        android:protectionLevel="signature" />
+
+
     <!-- Allows an app to set the theme overlay in /vendor/overlay
          being used.
          @hide  <p>Not for use by third-party applications.</p> -->
@@ -5923,6 +5940,10 @@
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND"
         android:protectionLevel="signature" />
+    <!-- @hide Permission that suppresses the notification when the clipboard is accessed.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.SUPPRESS_CLIPBOARD_ACCESS_NOTIFICATION"
+                android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows modifying accessibility state.
          @hide -->
diff --git a/core/res/res/anim/activity_close_enter.xml b/core/res/res/anim/activity_close_enter.xml
index 9fa7c54..0fefb51 100644
--- a/core/res/res/anim/activity_close_enter.xml
+++ b/core/res/res/anim/activity_close_enter.xml
@@ -19,16 +19,37 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false">
-    <scale
-        android:fromXScale="1.1"
-        android:toXScale="1"
-        android:fromYScale="1.1"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
+
+    <alpha
+        android:fromAlpha="1.0"
+        android:toAlpha="1.0"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/linear"
+        android:startOffset="0"
+        android:duration="450" />
+
+    <translate
+        android:fromXDelta="-10%"
+        android:toXDelta="0"
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
         android:interpolator="@interpolator/fast_out_extra_slow_in"
-        android:duration="400"/>
+        android:startOffset="0"
+        android:duration="450" />
+
+    <extend
+        android:fromExtendLeft="0"
+        android:fromExtendTop="0"
+        android:fromExtendRight="10%"
+        android:fromExtendBottom="0"
+        android:toExtendLeft="0"
+        android:toExtendTop="0"
+        android:toExtendRight="10%"
+        android:toExtendBottom="0"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="450" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/activity_close_enter_legacy.xml b/core/res/res/anim/activity_close_enter_legacy.xml
new file mode 100644
index 0000000..9fa7c54
--- /dev/null
+++ b/core/res/res/anim/activity_close_enter_legacy.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="false">
+    <scale
+        android:fromXScale="1.1"
+        android:toXScale="1"
+        android:fromYScale="1.1"
+        android:toYScale="1"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:duration="400"/>
+</set>
\ No newline at end of file
diff --git a/core/res/res/anim/activity_close_exit.xml b/core/res/res/anim/activity_close_exit.xml
index 1599ae8..f807c26 100644
--- a/core/res/res/anim/activity_close_exit.xml
+++ b/core/res/res/anim/activity_close_exit.xml
@@ -18,27 +18,38 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false"
-    android:zAdjustment="top">
+    android:shareInterpolator="false">
+
     <alpha
-        android:fromAlpha="1"
+        android:fromAlpha="1.0"
         android:toAlpha="0.0"
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
         android:interpolator="@interpolator/linear"
-        android:startOffset="33"
-        android:duration="50"/>
-    <scale
-        android:fromXScale="1"
-        android:toXScale="0.9"
-        android:fromYScale="1"
-        android:toYScale="0.9"
-        android:pivotX="50%"
-        android:pivotY="50%"
+        android:startOffset="35"
+        android:duration="83" />
+
+    <translate
+        android:fromXDelta="0"
+        android:toXDelta="10%"
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
         android:interpolator="@interpolator/fast_out_extra_slow_in"
-        android:duration="400"/>
+        android:startOffset="0"
+        android:duration="450" />
+
+    <extend
+        android:fromExtendLeft="10%"
+        android:fromExtendTop="0"
+        android:fromExtendRight="0"
+        android:fromExtendBottom="0"
+        android:toExtendLeft="10%"
+        android:toExtendTop="0"
+        android:toExtendRight="0"
+        android:toExtendBottom="0"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="450" />
 </set>
diff --git a/core/res/res/anim/activity_close_exit_legacy.xml b/core/res/res/anim/activity_close_exit_legacy.xml
new file mode 100644
index 0000000..1599ae8
--- /dev/null
+++ b/core/res/res/anim/activity_close_exit_legacy.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="false"
+    android:zAdjustment="top">
+    <alpha
+        android:fromAlpha="1"
+        android:toAlpha="0.0"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/linear"
+        android:startOffset="33"
+        android:duration="50"/>
+    <scale
+        android:fromXScale="1"
+        android:toXScale="0.9"
+        android:fromYScale="1"
+        android:toYScale="0.9"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:duration="400"/>
+</set>
diff --git a/core/res/res/anim/activity_open_enter.xml b/core/res/res/anim/activity_open_enter.xml
index 38d3e8ed..1674dab 100644
--- a/core/res/res/anim/activity_open_enter.xml
+++ b/core/res/res/anim/activity_open_enter.xml
@@ -18,6 +18,7 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false">
+
     <alpha
         android:fromAlpha="0"
         android:toAlpha="1.0"
@@ -26,17 +27,27 @@
         android:fillAfter="true"
         android:interpolator="@interpolator/linear"
         android:startOffset="50"
-        android:duration="50"/>
-    <scale
-        android:fromXScale="0.85"
-        android:toXScale="1"
-        android:fromYScale="0.85"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
+        android:duration="83" />
+
+    <translate
+        android:fromXDelta="10%"
+        android:toXDelta="0"
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
         android:interpolator="@interpolator/fast_out_extra_slow_in"
-        android:duration="400"/>
+        android:duration="450" />
+
+    <extend
+        android:fromExtendLeft="10%"
+        android:fromExtendTop="0"
+        android:fromExtendRight="0"
+        android:fromExtendBottom="0"
+        android:toExtendLeft="10%"
+        android:toExtendTop="0"
+        android:toExtendRight="0"
+        android:toExtendBottom="0"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="450" />
 </set>
diff --git a/core/res/res/anim/activity_open_enter_legacy.xml b/core/res/res/anim/activity_open_enter_legacy.xml
new file mode 100644
index 0000000..38d3e8ed
--- /dev/null
+++ b/core/res/res/anim/activity_open_enter_legacy.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+/*
+** Copyright 2009, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="false">
+    <alpha
+        android:fromAlpha="0"
+        android:toAlpha="1.0"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/linear"
+        android:startOffset="50"
+        android:duration="50"/>
+    <scale
+        android:fromXScale="0.85"
+        android:toXScale="1"
+        android:fromYScale="0.85"
+        android:toYScale="1"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:duration="400"/>
+</set>
diff --git a/core/res/res/anim/activity_open_exit.xml b/core/res/res/anim/activity_open_exit.xml
index 3865d21..372f2c8 100644
--- a/core/res/res/anim/activity_open_exit.xml
+++ b/core/res/res/anim/activity_open_exit.xml
@@ -19,27 +19,36 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false">
 
-    <!-- Fade out, over a black surface, which simulates a black scrim -->
     <alpha
-        android:fromAlpha="1"
-        android:toAlpha="0.4"
+        android:fromAlpha="1.0"
+        android:toAlpha="1.0"
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
-        android:interpolator="@interpolator/linear"
-        android:startOffset="83"
-        android:duration="167"/>
+        android:interpolator="@interpolator/standard_accelerate"
+        android:startOffset="0"
+        android:duration="450" />
 
-    <scale
-        android:fromXScale="1"
-        android:toXScale="1.05"
-        android:fromYScale="1"
-        android:toYScale="1.05"
-        android:pivotX="50%"
-        android:pivotY="50%"
+    <translate
+        android:fromXDelta="0"
+        android:toXDelta="-10%"
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
         android:interpolator="@interpolator/fast_out_extra_slow_in"
-        android:duration="400"/>
+        android:startOffset="0"
+        android:duration="450" />
+
+    <extend
+        android:fromExtendLeft="0"
+        android:fromExtendTop="0"
+        android:fromExtendRight="10%"
+        android:fromExtendBottom="0"
+        android:toExtendLeft="0"
+        android:toExtendTop="0"
+        android:toExtendRight="10%"
+        android:toExtendBottom="0"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="450" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/activity_open_exit_legacy.xml b/core/res/res/anim/activity_open_exit_legacy.xml
new file mode 100644
index 0000000..3865d21
--- /dev/null
+++ b/core/res/res/anim/activity_open_exit_legacy.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+/*
+** Copyright 2009, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="false">
+
+    <!-- Fade out, over a black surface, which simulates a black scrim -->
+    <alpha
+        android:fromAlpha="1"
+        android:toAlpha="0.4"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/linear"
+        android:startOffset="83"
+        android:duration="167"/>
+
+    <scale
+        android:fromXScale="1"
+        android:toXScale="1.05"
+        android:fromYScale="1"
+        android:toYScale="1.05"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:duration="400"/>
+</set>
\ No newline at end of file
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 7916ef4..afe0f1b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2885,7 +2885,7 @@
              <code>public void sayHello(View v)</code> method of your context
              (typically, your Activity).
              {@deprecated View actually traverses the Context
-             hierarchy looking for the relevant method, which is fragile (an intermediate 
+             hierarchy looking for the relevant method, which is fragile (an intermediate
              ContextWrapper adding a same-named method would change behavior) and restricts
              bytecode optimizers such as R8. Instead, use View.setOnClickListener.}-->
         <attr name="onClick" format="string" />
@@ -6975,6 +6975,34 @@
         <attr name="toBottom" format="fraction" />
     </declare-styleable>
 
+    <!-- Defines the ExtendAnimation used to extend windows during animations -->
+    <declare-styleable name="ExtendAnimation">
+        <!-- Defines the amount a window should be extended outward from the left at
+             the start of the animation. -->
+        <attr name="fromExtendLeft" format="float|fraction" />
+        <!-- Defines the amount a window should be extended outward from the top at
+             the start of the animation. -->
+        <attr name="fromExtendTop" format="float|fraction" />
+        <!-- Defines the amount a window should be extended outward from the right at
+             the start of the animation. -->
+        <attr name="fromExtendRight" format="float|fraction" />
+        <!-- Defines the amount a window should be extended outward from the bottom at
+             the start of the animation. -->
+        <attr name="fromExtendBottom" format="float|fraction" />
+        <!-- Defines the amount a window should be extended outward from the left by
+             the end of the animation by transitioning from the fromExtendLeft amount. -->
+        <attr name="toExtendLeft" format="float|fraction" />
+        <!-- Defines the amount a window should be extended outward from the top by
+             the end of the animation by transitioning from the fromExtendTop amount. -->
+        <attr name="toExtendTop" format="float|fraction" />
+        <!-- Defines the amount a window should be extended outward from the right by
+             the end of the animation by transitioning from the fromExtendRight amount. -->
+        <attr name="toExtendRight" format="float|fraction" />
+        <!-- Defines the amount a window should be extended outward from the bottom by
+             the end of the animation by transitioning from the fromExtendBottom amount. -->
+        <attr name="toExtendBottom" format="float|fraction" />
+    </declare-styleable>
+
     <declare-styleable name="LayoutAnimation">
         <!-- Fraction of the animation duration used to delay the beginning of
          the animation of each child. -->
@@ -7827,7 +7855,7 @@
 
         <!-- Name of a method on the Context used to inflate the menu that will be
              called when the item is clicked.
-             {@deprecated Menu actually traverses the Context hierarchy looking for the 
+             {@deprecated Menu actually traverses the Context hierarchy looking for the
              relevant method, which is fragile (an intermediate ContextWrapper adding a
              same-named method would change behavior) and restricts bytecode optimizers
              such as R8. Instead, use MenuItem.setOnMenuItemClickListener.} -->
@@ -8847,6 +8875,22 @@
         <attr name="gameSessionService" format="string" />
     </declare-styleable>
 
+    <!-- Use <code>game-mode-config</code> as the root tag of the XML resource that
+         describes a GameModeConfig.
+         Described here are the attributes that can be included in that tag. -->
+    <declare-styleable name="GameModeConfig">
+        <!-- Set true to opt in BATTERY mode. -->
+        <attr name="supportsBatteryGameMode" format="boolean" />
+        <!-- Set true to opt in PERFORMANCE mode. -->
+        <attr name="supportsPerformanceGameMode" format="boolean" />
+        <!-- Set true to enable ANGLE. -->
+        <attr name="allowGameAngleDriver" format="boolean" />
+        <!-- Set true to allow resolution downscaling intervention. -->
+        <attr name="allowGameDownscaling" format="boolean" />
+        <!-- Set true to allow FPS override intervention. -->
+        <attr name="allowGameFpsOverride" format="boolean" />
+    </declare-styleable>
+
     <!-- Use <code>voice-enrollment-application</code>
          as the root tag of the XML resource that escribes the supported keyphrases (hotwords)
          by the enrollment application.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a06b2cb..902d5e0 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4173,6 +4173,15 @@
 
     <string name="config_defaultMusicRecognitionService" translatable="false"></string>
 
+    <!-- The package name for the system's wallpaper effects generation service.
+    This service returns wallpaper effects results.
+    This service must be trusted, as it can be activated without explicit consent of the user.
+    If no service with the specified name exists on the device, wallpaper effects
+    generation service will be disabled.
+    Example: "com.android.intelligence/.WallpaperEffectsGenerationService"
+-->
+    <string name="config_defaultWallpaperEffectsGenerationService" translatable="false"></string>
+
     <!-- The package name for the default retail demo app.
          This package must be trusted, as it has the permissions to query the usage stats on the
          device.
@@ -5267,6 +5276,12 @@
     <bool name="config_cecTvSendStandbyOnSleepDisabled_allowed">true</bool>
     <bool name="config_cecTvSendStandbyOnSleepDisabled_default">false</bool>
 
+    <bool name="config_cecSetMenuLanguage_userConfigurable">true</bool>
+    <bool name="config_cecSetMenuLanguageEnabled_allowed">true</bool>
+    <bool name="config_cecSetMenuLanguageEnabled_default">true</bool>
+    <bool name="config_cecSetMenuLanguageDisabled_allowed">true</bool>
+    <bool name="config_cecSetMenuLanguageDisabled_default">false</bool>
+
     <bool name="config_cecRcProfileTv_userConfigurable">true</bool>
     <bool name="config_cecRcProfileTvNone_allowed">true</bool>
     <bool name="config_cecRcProfileTvNone_default">true</bool>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2e96c65..d57f5ba 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3255,11 +3255,24 @@
     <public name="showClockAndComplications" />
     <!-- @hide @SystemApi -->
     <public name="gameSessionService" />
+    <public name="supportsBatteryGameMode" />
+    <public name="supportsPerformanceGameMode" />
+    <public name="allowGameAngleDriver" />
+    <public name="allowGameDownscaling" />
+    <public name="allowGameFpsOverride" />
     <public name="localeConfig" />
     <public name="showBackground" />
     <public name="inheritKeyStoreKeys" />
     <public name="preferKeepClear" />
     <public name="autoHandwritingEnabled" />
+    <public name="fromExtendLeft" />
+    <public name="fromExtendTop" />
+    <public name="fromExtendRight" />
+    <public name="fromExtendBottom" />
+    <public name="toExtendLeft" />
+    <public name="toExtendTop" />
+    <public name="toExtendRight" />
+    <public name="toExtendBottom" />
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01de0000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 610c6a6..2e4b783a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5857,6 +5857,8 @@
     <string name="accessibility_system_action_lock_screen_label">Lock Screen</string>
     <!-- Label for taking screenshot action [CHAR LIMIT=NONE] -->
     <string name="accessibility_system_action_screenshot_label">Screenshot</string>
+    <!-- Label for headset hook action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_headset_hook_label">Headset Hook</string>
     <!-- Label for triggering on-screen accessibility shortcut action [CHAR LIMIT=NONE] -->
     <string name="accessibility_system_action_on_screen_a11y_shortcut_label">On-screen Accessibility Shortcut</string>
     <!-- Label for showing on-screen accessibility shortcut chooser action [CHAR LIMIT=NONE] -->
@@ -5865,6 +5867,16 @@
     <string name="accessibility_system_action_hardware_a11y_shortcut_label">Accessibility Shortcut</string>
     <!-- Label for dismissing the notification shade [CHAR LIMIT=NONE] -->
     <string name="accessibility_system_action_dismiss_notification_shade">Dismiss Notification Shade</string>
+    <!-- Label for Dpad up action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_dpad_up_label">Dpad Up</string>
+    <!-- Label for Dpad down action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_dpad_down_label">Dpad Down</string>
+    <!-- Label for Dpad left action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_dpad_left_label">Dpad Left</string>
+    <!-- Label for Dpad right action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_dpad_right_label">Dpad Right</string>
+    <!-- Label for Dpad center action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_dpad_center_label">Dpad Center</string>
     <!-- Accessibility description of caption view -->
     <string name="accessibility_freeform_caption">Caption bar of <xliff:g id="app_name">%1$s</xliff:g>.</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4c1cc4d..30a1963 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1697,7 +1697,13 @@
   <java-symbol type="anim" name="activity_translucent_open_enter" />
   <java-symbol type="anim" name="activity_translucent_close_exit" />
   <java-symbol type="anim" name="activity_open_enter" />
+  <java-symbol type="anim" name="activity_open_exit" />
+  <java-symbol type="anim" name="activity_close_enter" />
   <java-symbol type="anim" name="activity_close_exit" />
+  <java-symbol type="anim" name="activity_open_enter_legacy" />
+  <java-symbol type="anim" name="activity_open_exit_legacy" />
+  <java-symbol type="anim" name="activity_close_enter_legacy" />
+  <java-symbol type="anim" name="activity_close_exit_legacy" />
   <java-symbol type="anim" name="task_fragment_close_enter" />
   <java-symbol type="anim" name="task_fragment_close_exit" />
   <java-symbol type="anim" name="task_fragment_open_enter" />
@@ -3673,6 +3679,7 @@
   <java-symbol type="string" name="config_defaultContentSuggestionsService" />
   <java-symbol type="string" name="config_defaultSearchUiService" />
   <java-symbol type="string" name="config_defaultSmartspaceService" />
+  <java-symbol type="string" name="config_defaultWallpaperEffectsGenerationService" />
   <java-symbol type="string" name="config_defaultMusicRecognitionService" />
   <java-symbol type="string" name="config_defaultAttentionService" />
   <java-symbol type="string" name="config_defaultRotationResolverService" />
@@ -4129,10 +4136,16 @@
   <java-symbol type="string" name="accessibility_system_action_quick_settings_label" />
   <java-symbol type="string" name="accessibility_system_action_recents_label" />
   <java-symbol type="string" name="accessibility_system_action_screenshot_label" />
+  <java-symbol type="string" name="accessibility_system_action_headset_hook_label" />
   <java-symbol type="string" name="accessibility_system_action_on_screen_a11y_shortcut_label" />
   <java-symbol type="string" name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" />
   <java-symbol type="string" name="accessibility_system_action_hardware_a11y_shortcut_label" />
   <java-symbol type="string" name="accessibility_system_action_dismiss_notification_shade" />
+  <java-symbol type="string" name="accessibility_system_action_dpad_up_label" />
+  <java-symbol type="string" name="accessibility_system_action_dpad_down_label" />
+  <java-symbol type="string" name="accessibility_system_action_dpad_left_label" />
+  <java-symbol type="string" name="accessibility_system_action_dpad_right_label" />
+  <java-symbol type="string" name="accessibility_system_action_dpad_center_label" />
 
   <java-symbol type="string" name="accessibility_freeform_caption" />
 
@@ -4453,6 +4466,12 @@
   <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepDisabled_allowed" />
   <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepDisabled_default" />
 
+  <java-symbol type="bool" name="config_cecSetMenuLanguage_userConfigurable" />
+  <java-symbol type="bool" name="config_cecSetMenuLanguageEnabled_allowed" />
+  <java-symbol type="bool" name="config_cecSetMenuLanguageEnabled_default" />
+  <java-symbol type="bool" name="config_cecSetMenuLanguageDisabled_allowed" />
+  <java-symbol type="bool" name="config_cecSetMenuLanguageDisabled_default" />
+
   <java-symbol type="bool" name="config_cecRcProfileTv_userConfigurable" />
   <java-symbol type="bool" name="config_cecRcProfileTvNone_allowed" />
   <java-symbol type="bool" name="config_cecRcProfileTvNone_default" />
diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
index d3e8bb0..5338d04 100644
--- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
+++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
@@ -37,9 +37,9 @@
 @SmallTest
 public class PropertyInvalidatedCacheTests {
 
-    // This property is never set.  The test process does not have permission to set any
-    // properties.
-    static final String CACHE_PROPERTY = "cache_key.cache_test_a";
+    // Configuration for creating caches
+    private static final int MODULE = PropertyInvalidatedCache.MODULE_TEST;
+    private static final String API = "testApi";
 
     // This class is a proxy for binder calls.  It contains a counter that increments
     // every time the class is queried.
@@ -64,6 +64,25 @@
         }
     }
 
+    // The functions for querying the server.
+    private static class ServerQuery
+            extends PropertyInvalidatedCache.QueryHandler<Integer, Boolean> {
+        private final ServerProxy mServer;
+
+        ServerQuery(ServerProxy server) {
+            mServer = server;
+        }
+
+        @Override
+        public Boolean apply(Integer x) {
+            return mServer.query(x);
+        }
+        @Override
+        public boolean shouldBypassCache(Integer x) {
+            return x % 13 == 0;
+        }
+    }
+
     // Clear the test mode after every test, in case this process is used for other
     // tests. This also resets the test property map.
     @After
@@ -82,19 +101,11 @@
 
         // Create a cache that uses simple arithmetic to computer its values.
         PropertyInvalidatedCache<Integer, Boolean> testCache =
-                new PropertyInvalidatedCache<>(4, CACHE_PROPERTY) {
-                    @Override
-                    public Boolean recompute(Integer x) {
-                        return tester.query(x);
-                    }
-                    @Override
-                    public boolean bypass(Integer x) {
-                        return x % 13 == 0;
-                    }
-                };
+                new PropertyInvalidatedCache<>(4, MODULE, API, "cache1",
+                        new ServerQuery(tester));
 
         PropertyInvalidatedCache.setTestMode(true);
-        PropertyInvalidatedCache.testPropertyName(CACHE_PROPERTY);
+        testCache.testPropertyName();
 
         tester.verify(0);
         assertEquals(tester.value(3), testCache.query(3));
@@ -136,26 +147,14 @@
 
         // Three caches, all using the same system property but one uses a different name.
         PropertyInvalidatedCache<Integer, Boolean> cache1 =
-                new PropertyInvalidatedCache<>(4, CACHE_PROPERTY) {
-                    @Override
-                    public Boolean recompute(Integer x) {
-                        return tester.query(x);
-                    }
-                };
+            new PropertyInvalidatedCache<>(4, MODULE, API, "cache1",
+                        new ServerQuery(tester));
         PropertyInvalidatedCache<Integer, Boolean> cache2 =
-                new PropertyInvalidatedCache<>(4, CACHE_PROPERTY) {
-                    @Override
-                    public Boolean recompute(Integer x) {
-                        return tester.query(x);
-                    }
-                };
+            new PropertyInvalidatedCache<>(4, MODULE, API, "cache1",
+                        new ServerQuery(tester));
         PropertyInvalidatedCache<Integer, Boolean> cache3 =
-                new PropertyInvalidatedCache<>(4, CACHE_PROPERTY, "cache3") {
-                    @Override
-                    public Boolean recompute(Integer x) {
-                        return tester.query(x);
-                    }
-                };
+            new PropertyInvalidatedCache<>(4, MODULE, API, "cache3",
+                        new ServerQuery(tester));
 
         // Caches are enabled upon creation.
         assertEquals(false, cache1.getDisabledState());
@@ -176,45 +175,29 @@
         assertEquals(false, cache3.getDisabledState());
 
         // Create a new cache1.  Verify that the new instance is disabled.
-        cache1 = new PropertyInvalidatedCache<>(4, CACHE_PROPERTY) {
-                    @Override
-                    public Boolean recompute(Integer x) {
-                        return tester.query(x);
-                    }
-                };
+        cache1 = new PropertyInvalidatedCache<>(4, MODULE, API, "cache1",
+                new ServerQuery(tester));
         assertEquals(true, cache1.getDisabledState());
 
         // Remove the record of caches being locally disabled.  This is a clean-up step.
-        cache1.clearDisableLocal();
+        cache1.forgetDisableLocal();
         assertEquals(true, cache1.getDisabledState());
         assertEquals(true, cache2.getDisabledState());
         assertEquals(false, cache3.getDisabledState());
 
         // Create a new cache1.  Verify that the new instance is not disabled.
-        cache1 = new PropertyInvalidatedCache<>(4, CACHE_PROPERTY) {
-                    @Override
-                    public Boolean recompute(Integer x) {
-                        return tester.query(x);
-                    }
-                };
+        cache1 = new PropertyInvalidatedCache<>(4, MODULE, API, "cache1",
+                new ServerQuery(tester));
         assertEquals(false, cache1.getDisabledState());
     }
 
-    private static final String UNSET_KEY = "Aiw7woh6ie4toh7W";
+    private static class TestQuery
+            extends PropertyInvalidatedCache.QueryHandler<Integer, String> {
 
-    private static class TestCache extends PropertyInvalidatedCache<Integer, String> {
-        TestCache() {
-            this(CACHE_PROPERTY);
-        }
-
-        TestCache(String key) {
-            super(4, key);
-            setTestMode(true);
-            testPropertyName(key);
-        }
+        private int mRecomputeCount = 0;
 
         @Override
-        public String recompute(Integer qv) {
+        public String apply(Integer qv) {
             mRecomputeCount += 1;
             return "foo" + qv.toString();
         }
@@ -222,15 +205,40 @@
         int getRecomputeCount() {
             return mRecomputeCount;
         }
+    }
 
-        private int mRecomputeCount = 0;
+    private static class TestCache extends PropertyInvalidatedCache<Integer, String> {
+        private final TestQuery mQuery;
+
+        TestCache() {
+            this(MODULE, API);
+        }
+
+        TestCache(int module, String api) {
+            this(module, api, new TestQuery());
+            setTestMode(true);
+            testPropertyName();
+        }
+
+        TestCache(int module, String api, TestQuery query) {
+            super(4, module, api, api, query);
+            mQuery = query;
+            setTestMode(true);
+            testPropertyName();
+        }
+
+        public int getRecomputeCount() {
+            return mQuery.getRecomputeCount();
+        }
+
+
     }
 
     @Test
     public void testCacheRecompute() {
         TestCache cache = new TestCache();
         cache.invalidateCache();
-        assertEquals(cache.isDisabledLocal(), false);
+        assertEquals(cache.isDisabled(), false);
         assertEquals("foo5", cache.query(5));
         assertEquals(1, cache.getRecomputeCount());
         assertEquals("foo5", cache.query(5));
@@ -241,6 +249,11 @@
         assertEquals("foo5", cache.query(5));
         assertEquals("foo5", cache.query(5));
         assertEquals(3, cache.getRecomputeCount());
+        // Invalidate the cache with a direct call to the property.
+        PropertyInvalidatedCache.invalidateCache(MODULE, API);
+        assertEquals("foo5", cache.query(5));
+        assertEquals("foo5", cache.query(5));
+        assertEquals(4, cache.getRecomputeCount());
     }
 
     @Test
@@ -257,7 +270,8 @@
 
     @Test
     public void testCachePropertyUnset() {
-        TestCache cache = new TestCache(UNSET_KEY);
+        final String UNSET_API = "otherApi";
+        TestCache cache = new TestCache(MODULE, UNSET_API);
         assertEquals("foo5", cache.query(5));
         assertEquals("foo5", cache.query(5));
         assertEquals(2, cache.getRecomputeCount());
@@ -327,17 +341,40 @@
     @Test
     public void testLocalProcessDisable() {
         TestCache cache = new TestCache();
-        assertEquals(cache.isDisabledLocal(), false);
+        assertEquals(cache.isDisabled(), false);
         cache.invalidateCache();
         assertEquals("foo5", cache.query(5));
         assertEquals(1, cache.getRecomputeCount());
         assertEquals("foo5", cache.query(5));
         assertEquals(1, cache.getRecomputeCount());
-        assertEquals(cache.isDisabledLocal(), false);
+        assertEquals(cache.isDisabled(), false);
         cache.disableLocal();
-        assertEquals(cache.isDisabledLocal(), true);
+        assertEquals(cache.isDisabled(), true);
         assertEquals("foo5", cache.query(5));
         assertEquals("foo5", cache.query(5));
         assertEquals(3, cache.getRecomputeCount());
     }
+
+    @Test
+    public void testPropertyNames() {
+        String n1;
+        n1 = PropertyInvalidatedCache.createPropertyName(
+            PropertyInvalidatedCache.MODULE_SYSTEM, "getPackageInfo");
+        assertEquals(n1, "cache_key.system_server.get_package_info");
+        n1 = PropertyInvalidatedCache.createPropertyName(
+            PropertyInvalidatedCache.MODULE_SYSTEM, "get_package_info");
+        assertEquals(n1, "cache_key.system_server.get_package_info");
+        try {
+            n1 = PropertyInvalidatedCache.createPropertyName(
+                PropertyInvalidatedCache.MODULE_SYSTEM - 1, "get package_info");
+            // n1 is an invalid api name.
+            assertEquals(false, true);
+        } catch (IllegalArgumentException e) {
+            // An exception is expected here.
+        }
+
+        n1 = PropertyInvalidatedCache.createPropertyName(
+            PropertyInvalidatedCache.MODULE_BLUETOOTH, "getState");
+        assertEquals(n1, "cache_key.bluetooth.get_state");
+    }
 }
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 2018836..99670d9 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -58,7 +58,7 @@
 
     // The number of flags held in boolean properties. Their values should also be double-checked
     // in the methods above.
-    private static final int NUM_BOOLEAN_PROPERTIES = 23;
+    private static final int NUM_BOOLEAN_PROPERTIES = 24;
 
     @Test
     public void testStandardActions_serializationFlagIsValid() {
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index f04a9f7..e16a2f8 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -288,9 +288,8 @@
         }
 
         @Override
-        public void addVendorCommandListener(final IHdmiVendorCommandListener listener,
-                final int deviceType) {
-        }
+        public void addVendorCommandListener(
+                final IHdmiVendorCommandListener listener, final int vendorId) {}
 
         @Override
         public void sendVendorCommand(final int deviceType, final int targetAddress,
diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml
index ddcab6e..5dcc599 100644
--- a/data/etc/com.android.settings.xml
+++ b/data/etc/com.android.settings.xml
@@ -61,5 +61,6 @@
         <permission name="android.permission.READ_DREAM_SUPPRESSION"/>
         <permission name="android.permission.RESTART_WIFI_SUBSYSTEM"/>
         <permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
+        <permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index b3dcc34..d002601 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -581,6 +581,7 @@
         <permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/>
         <permission name="android.permission.BIND_CELL_BROADCAST_SERVICE"/>
         <permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
+        <permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.bips">
diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java
index cdf746f..f440b69 100644
--- a/identity/java/android/security/identity/IdentityCredential.java
+++ b/identity/java/android/security/identity/IdentityCredential.java
@@ -454,7 +454,8 @@
      * @param challenge is a non-empty byte array whose contents should be unique, fresh and
      *                  provided by the issuing authority. The value provided is embedded in the
      *                  generated CBOR and enables the issuing authority to verify that the
-     *                  returned proof is fresh.
+     *                  returned proof is fresh. Implementations are required to support
+     *                  challenges at least 32 bytes of length.
      * @return the COSE_Sign1 data structure above
      */
     public @NonNull byte[] proveOwnership(@NonNull byte[] challenge)  {
@@ -485,7 +486,8 @@
      * @param challenge is a non-empty byte array whose contents should be unique, fresh and
      *                  provided by the issuing authority. The value provided is embedded in the
      *                  generated CBOR and enables the issuing authority to verify that the
-     *                  returned proof is fresh.
+     *                  returned proof is fresh. Implementations are required to support
+     *                  challenges at least 32 bytes of length.
      * @return the COSE_Sign1 data structure above
      */
     public @NonNull byte[] delete(@NonNull byte[] challenge)  {
diff --git a/identity/java/android/security/identity/WritableIdentityCredential.java b/identity/java/android/security/identity/WritableIdentityCredential.java
index 305d0ea..6d56964 100644
--- a/identity/java/android/security/identity/WritableIdentityCredential.java
+++ b/identity/java/android/security/identity/WritableIdentityCredential.java
@@ -59,7 +59,8 @@
      * @param challenge is a non-empty byte array whose contents should be unique, fresh and
      *                  provided by the issuing authority. The value provided is embedded in the
      *                  attestation extension and enables the issuing authority to verify that the
-     *                  attestation certificate is fresh.
+     *                  attestation certificate is fresh. Implementations are required to support
+     *                  challenges at least 32 bytes of length.
      * @return the X.509 certificate for this credential's CredentialKey.
      */
     public abstract @NonNull Collection<X509Certificate> getCredentialKeyCertificateChain(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 17005ea..6b0d7f5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -867,6 +867,10 @@
     }
 
     private void fadeExistingPip(boolean show) {
+        if (mLeash == null || !mLeash.isValid()) {
+            Log.w(TAG, "Invalid leash on fadeExistingPip: " + mLeash);
+            return;
+        }
         final float alphaStart = show ? 0 : 1;
         final float alphaEnd = show ? 1 : 0;
         mPipAnimationController
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 27b6dc5..ddf01a8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -67,7 +67,11 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Insets;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -78,6 +82,7 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.view.Choreographer;
+import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.WindowManager;
@@ -103,6 +108,8 @@
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
 import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
 
 /** The default handler that handles anything not already handled. */
 public class DefaultTransitionHandler implements Transitions.TransitionHandler {
@@ -331,6 +338,9 @@
             finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
         };
 
+        final List<Consumer<SurfaceControl.Transaction>> postStartTransactionCallbacks =
+                new ArrayList<>();
+
         @ColorInt int backgroundColorForTransition = 0;
         final int wallpaperTransit = getWallpaperTransitType(info);
         for (int i = info.getChanges().size() - 1; i >= 0; --i) {
@@ -402,13 +412,15 @@
                     }
                 }
 
-                float cornerRadius = 0;
+                final float cornerRadius;
                 if (a.hasRoundedCorners() && isTask) {
                     // hasRoundedCorners is currently only enabled for tasks
                     final Context displayContext =
                             mDisplayController.getDisplayContext(change.getTaskInfo().displayId);
                     cornerRadius =
                             ScreenDecorationsUtils.getWindowCornerRadius(displayContext);
+                } else {
+                    cornerRadius = 0;
                 }
 
                 if (a.getShowBackground()) {
@@ -424,12 +436,37 @@
                     }
                 }
 
+                boolean delayedEdgeExtension = false;
+                if (!isTask && a.hasExtension()) {
+                    if (!Transitions.isOpeningType(change.getMode())) {
+                        // Can screenshot now (before startTransaction is applied)
+                        edgeExtendWindow(change, a, startTransaction, finishTransaction);
+                    } else {
+                        // Need to screenshot after startTransaction is applied otherwise activity
+                        // may not be visible or ready yet.
+                        postStartTransactionCallbacks
+                                .add(t -> edgeExtendWindow(change, a, t, finishTransaction));
+                        delayedEdgeExtension = true;
+                    }
+                }
+
                 final Rect clipRect = Transitions.isClosingType(change.getMode())
                         ? mRotator.getEndBoundsInStartRotation(change)
                         : change.getEndAbsBounds();
-                startSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
-                        mTransactionPool, mMainExecutor, mAnimExecutor, null /* position */,
-                        cornerRadius, clipRect);
+
+                if (delayedEdgeExtension) {
+                    // If the edge extension needs to happen after the startTransition has been
+                    // applied, then we want to only start the animation after the edge extension
+                    // postStartTransaction callback has been run
+                    postStartTransactionCallbacks.add(t ->
+                            startSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
+                                    mTransactionPool, mMainExecutor, mAnimExecutor,
+                                    null /* position */, cornerRadius, clipRect));
+                } else {
+                    startSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
+                            mTransactionPool, mMainExecutor, mAnimExecutor, null /* position */,
+                            cornerRadius, clipRect);
+                }
 
                 if (info.getAnimationOptions() != null) {
                     attachThumbnail(animations, onAnimFinish, change, info.getAnimationOptions(),
@@ -443,7 +480,20 @@
                     startTransaction, finishTransaction);
         }
 
-        startTransaction.apply();
+        // postStartTransactionCallbacks require that the start transaction is already
+        // applied to run otherwise they may result in flickers and UI inconsistencies.
+        boolean waitForStartTransactionApply = postStartTransactionCallbacks.size() > 0;
+        startTransaction.apply(waitForStartTransactionApply);
+
+        // Run tasks that require startTransaction to already be applied
+        for (Consumer<SurfaceControl.Transaction> postStartTransactionCallback :
+                postStartTransactionCallbacks) {
+            final SurfaceControl.Transaction t = mTransactionPool.acquire();
+            postStartTransactionCallback.accept(t);
+            t.apply();
+            mTransactionPool.release(t);
+        }
+
         mRotator.cleanUp(finishTransaction);
         TransitionMetrics.getInstance().reportAnimationStart(transition);
         // run finish now in-case there are no animations
@@ -451,6 +501,117 @@
         return true;
     }
 
+    private void edgeExtendWindow(TransitionInfo.Change change,
+            Animation a, SurfaceControl.Transaction startTransaction,
+            SurfaceControl.Transaction finishTransaction) {
+        final Transformation transformationAtStart = new Transformation();
+        a.getTransformationAt(0, transformationAtStart);
+        final Transformation transformationAtEnd = new Transformation();
+        a.getTransformationAt(1, transformationAtEnd);
+
+        // We want to create an extension surface that is the maximal size and the animation will
+        // take care of cropping any part that overflows.
+        final Insets maxExtensionInsets = Insets.min(
+                transformationAtStart.getInsets(), transformationAtEnd.getInsets());
+
+        final int targetSurfaceHeight = Math.max(change.getStartAbsBounds().height(),
+                change.getEndAbsBounds().height());
+        final int targetSurfaceWidth = Math.max(change.getStartAbsBounds().width(),
+                change.getEndAbsBounds().width());
+        if (maxExtensionInsets.left < 0) {
+            final Rect edgeBounds = new Rect(0, 0, 1, targetSurfaceHeight);
+            final Rect extensionRect = new Rect(0, 0,
+                    -maxExtensionInsets.left, targetSurfaceHeight);
+            final int xPos = maxExtensionInsets.left;
+            final int yPos = 0;
+            createExtensionSurface(change.getLeash(), edgeBounds, extensionRect, xPos, yPos,
+                    "Left Edge Extension", startTransaction, finishTransaction);
+        }
+
+        if (maxExtensionInsets.top < 0) {
+            final Rect edgeBounds = new Rect(0, 0, targetSurfaceWidth, 1);
+            final Rect extensionRect = new Rect(0, 0,
+                    targetSurfaceWidth, -maxExtensionInsets.top);
+            final int xPos = 0;
+            final int yPos = maxExtensionInsets.top;
+            createExtensionSurface(change.getLeash(), edgeBounds, extensionRect, xPos, yPos,
+                    "Top Edge Extension", startTransaction, finishTransaction);
+        }
+
+        if (maxExtensionInsets.right < 0) {
+            final Rect edgeBounds = new Rect(targetSurfaceWidth - 1, 0,
+                    targetSurfaceWidth, targetSurfaceHeight);
+            final Rect extensionRect = new Rect(0, 0,
+                    -maxExtensionInsets.right, targetSurfaceHeight);
+            final int xPos = targetSurfaceWidth;
+            final int yPos = 0;
+            createExtensionSurface(change.getLeash(), edgeBounds, extensionRect, xPos, yPos,
+                    "Right Edge Extension", startTransaction, finishTransaction);
+        }
+
+        if (maxExtensionInsets.bottom < 0) {
+            final Rect edgeBounds = new Rect(0, targetSurfaceHeight - 1,
+                    targetSurfaceWidth, targetSurfaceHeight);
+            final Rect extensionRect = new Rect(0, 0,
+                    targetSurfaceWidth, -maxExtensionInsets.bottom);
+            final int xPos = maxExtensionInsets.left;
+            final int yPos = targetSurfaceHeight;
+            createExtensionSurface(change.getLeash(), edgeBounds, extensionRect, xPos, yPos,
+                    "Bottom Edge Extension", startTransaction, finishTransaction);
+        }
+    }
+
+    private SurfaceControl createExtensionSurface(SurfaceControl surfaceToExtend, Rect edgeBounds,
+            Rect extensionRect, int xPos, int yPos, String layerName,
+            SurfaceControl.Transaction startTransaction,
+            SurfaceControl.Transaction finishTransaction) {
+        final SurfaceControl edgeExtensionLayer = new SurfaceControl.Builder()
+                .setName(layerName)
+                .setParent(surfaceToExtend)
+                .setHidden(true)
+                .setCallsite("DefaultTransitionHandler#startAnimation")
+                .setOpaque(true)
+                .setBufferSize(extensionRect.width(), extensionRect.height())
+                .build();
+
+        SurfaceControl.LayerCaptureArgs captureArgs =
+                new SurfaceControl.LayerCaptureArgs.Builder(surfaceToExtend)
+                        .setSourceCrop(edgeBounds)
+                        .setFrameScale(1)
+                        .setPixelFormat(PixelFormat.RGBA_8888)
+                        .setChildrenOnly(true)
+                        .setAllowProtected(true)
+                        .build();
+        final SurfaceControl.ScreenshotHardwareBuffer edgeBuffer =
+                SurfaceControl.captureLayers(captureArgs);
+
+        if (edgeBuffer == null) {
+            ProtoLog.e(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+                    "Failed to capture edge of window.");
+            return null;
+        }
+
+        android.graphics.BitmapShader shader =
+                new android.graphics.BitmapShader(edgeBuffer.asBitmap(),
+                        android.graphics.Shader.TileMode.CLAMP,
+                        android.graphics.Shader.TileMode.CLAMP);
+        final Paint paint = new Paint();
+        paint.setShader(shader);
+
+        final Surface surface = new Surface(edgeExtensionLayer);
+        Canvas c = surface.lockHardwareCanvas();
+        c.drawRect(extensionRect, paint);
+        surface.unlockCanvasAndPost(c);
+        surface.release();
+
+        startTransaction.setLayer(edgeExtensionLayer, Integer.MIN_VALUE);
+        startTransaction.setPosition(edgeExtensionLayer, xPos, yPos);
+        startTransaction.setVisibility(edgeExtensionLayer, true);
+        finishTransaction.remove(edgeExtensionLayer);
+
+        return edgeExtensionLayer;
+    }
+
     private void addBackgroundToTransition(
             @NonNull SurfaceControl rootLeash,
             @ColorInt int color,
@@ -778,9 +939,17 @@
         }
         t.setMatrix(leash, transformation.getMatrix(), matrix);
         t.setAlpha(leash, transformation.getAlpha());
+
+        Insets extensionInsets = Insets.min(transformation.getInsets(), Insets.NONE);
+        if (!extensionInsets.equals(Insets.NONE) && clipRect != null && !clipRect.isEmpty()) {
+            // Clip out any overflowing edge extension
+            clipRect.inset(extensionInsets);
+            t.setCrop(leash, clipRect);
+        }
+
         if (anim.hasRoundedCorners() && cornerRadius > 0 && clipRect != null) {
             // We can only apply rounded corner if a crop is set
-            t.setWindowCrop(leash, clipRect);
+            t.setCrop(leash, clipRect);
             t.setCornerRadius(leash, cornerRadius);
         }
 
diff --git a/media/java/android/media/BtProfileConnectionInfo.java b/media/java/android/media/BtProfileConnectionInfo.java
index 86dc6e0..88b9777 100644
--- a/media/java/android/media/BtProfileConnectionInfo.java
+++ b/media/java/android/media/BtProfileConnectionInfo.java
@@ -27,6 +27,7 @@
  */
 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 public final class BtProfileConnectionInfo implements Parcelable {
+
     private final int mProfile;
     private final boolean mSupprNoisy;
     private final int mVolume;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.java b/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.java
index 7f4e403..798e9c3 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.java
@@ -20,22 +20,34 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Objects;
+
 /** @hide */
 public final class InternalNetworkManagementException
         extends RuntimeException implements Parcelable {
 
     /* @hide */
-    public InternalNetworkManagementException(@NonNull final Throwable t) {
-        super(t);
+    public InternalNetworkManagementException(@NonNull final String errorMessage) {
+        super(errorMessage);
     }
 
-    private InternalNetworkManagementException(@NonNull final Parcel source) {
-        super(source.readString());
+    @Override
+    public int hashCode() {
+        return Objects.hash(getMessage());
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null || getClass() != obj.getClass()) return false;
+        final InternalNetworkManagementException that = (InternalNetworkManagementException) obj;
+
+        return Objects.equals(getMessage(), that.getMessage());
     }
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeString(getCause().getMessage());
+        dest.writeString(getMessage());
     }
 
     @Override
@@ -53,7 +65,7 @@
 
                 @Override
                 public InternalNetworkManagementException createFromParcel(@NonNull Parcel source) {
-                    return new InternalNetworkManagementException(source);
+                    return new InternalNetworkManagementException(source.readString());
                 }
             };
 }
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 93e3dee..29a1831 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -647,6 +647,11 @@
         <item>disabled</item>
     </array>
 
+    <!-- Images offered as options in the avatar picker. If populated, the avatar_image_descriptions
+         array must also be populated with a content description for each image. -->
     <array name="avatar_images"/>
 
+    <!-- Content descriptions for each of the images in the avatar_images array. -->
+    <string-array name="avatar_image_descriptions"/>
+
 </resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index af6a658..0fe869f 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1562,4 +1562,8 @@
 
     <!-- Title for a screen allowing the user to choose a profile picture. [CHAR LIMIT=NONE] -->
     <string name="avatar_picker_title">Choose a profile picture</string>
+
+    <!-- Content description for a default user icon. [CHAR LIMIT=NONE] -->
+    <string name="default_user_icon_description">Default user icon</string>
+
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
index 50015e6..93be66a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
@@ -45,6 +45,7 @@
 import com.google.android.setupdesign.util.ThemeHelper;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -180,6 +181,7 @@
         private final int mPreselectedImageStartPosition;
 
         private final List<Drawable> mImageDrawables;
+        private final List<String> mImageDescriptions;
         private final TypedArray mPreselectedImages;
         private final int[] mUserIconColors;
         private int mSelectedPosition = NONE;
@@ -196,6 +198,7 @@
             mPreselectedImages = getResources().obtainTypedArray(R.array.avatar_images);
             mUserIconColors = UserIcons.getUserIconColors(getResources());
             mImageDrawables = buildDrawableList();
+            mImageDescriptions = buildDescriptionsList();
         }
 
         @NonNull
@@ -210,15 +213,24 @@
         public void onBindViewHolder(@NonNull AvatarViewHolder viewHolder, int position) {
             if (position == mTakePhotoPosition) {
                 viewHolder.setDrawable(getDrawable(R.drawable.avatar_take_photo_circled));
+                viewHolder.setContentDescription(getString(R.string.user_image_take_photo));
                 viewHolder.setClickListener(view -> mAvatarPhotoController.takePhoto());
 
             } else if (position == mChoosePhotoPosition) {
                 viewHolder.setDrawable(getDrawable(R.drawable.avatar_choose_photo_circled));
+                viewHolder.setContentDescription(getString(R.string.user_image_choose_photo));
                 viewHolder.setClickListener(view -> mAvatarPhotoController.choosePhoto());
 
             } else if (position >= mPreselectedImageStartPosition) {
+                int index = indexFromPosition(position);
                 viewHolder.setSelected(position == mSelectedPosition);
-                viewHolder.setDrawable(mImageDrawables.get(indexFromPosition(position)));
+                viewHolder.setDrawable(mImageDrawables.get(index));
+                if (mImageDescriptions != null) {
+                    viewHolder.setContentDescription(mImageDescriptions.get(index));
+                } else {
+                    viewHolder.setContentDescription(
+                            getString(R.string.default_user_icon_description));
+                }
                 viewHolder.setClickListener(view -> {
                     if (mSelectedPosition == position) {
                         deselect(position);
@@ -256,6 +268,15 @@
             return result;
         }
 
+        private List<String> buildDescriptionsList() {
+            if (mPreselectedImages.length() > 0) {
+                return Arrays.asList(
+                        getResources().getStringArray(R.array.avatar_image_descriptions));
+            }
+
+            return null;
+        }
+
         private Drawable circularDrawableFrom(BitmapDrawable drawable) {
             Bitmap bitmap = drawable.getBitmap();
 
@@ -323,6 +344,10 @@
             mImageView.setImageDrawable(drawable);
         }
 
+        public void setContentDescription(String desc) {
+            mImageView.setContentDescription(desc);
+        }
+
         public void setClickListener(View.OnClickListener listener) {
             mImageView.setOnClickListener(listener);
         }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 27fc6ba..ca90fbe 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -192,6 +192,9 @@
     <uses-permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS" />
     <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" />
     <uses-permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS" />
+    <!-- Permission required for processes that don't own the focused window to switch
+         touch mode state -->
+    <uses-permission android:name="android.permission.MODIFY_TOUCH_MODE_STATE" />
     <!-- Permission required to test onPermissionsChangedListener -->
     <uses-permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS" />
     <uses-permission android:name="android.permission.SET_KEYBOARD_LAYOUT" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 55bf6e5..f83431b 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -213,6 +213,9 @@
     <!-- DevicePolicyManager get user restrictions -->
     <uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
 
+    <!-- DevicePolicyManager get admin policy -->
+    <uses-permission android:name="android.permission.QUERY_ADMIN_POLICY" />
+
     <!-- TV picture-in-picture -->
     <uses-permission android:name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE" />
 
@@ -305,6 +308,7 @@
 
     <!-- To change system language (HDMI CEC) -->
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
+    <uses-permission android:name="android.permission.SUPPRESS_CLIPBOARD_ACCESS_NOTIFICATION" />
 
     <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
     <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
@@ -875,6 +879,12 @@
             android:name=".media.taptotransfer.sender.MediaTttSenderService"
            />
 
+        <!-- Service for external clients to notify us of nearby media devices -->
+        <!-- TODO(b/216313420): Export and guard with a permission. -->
+        <service
+            android:name=".media.nearby.NearbyMediaDevicesService"
+            />
+
         <receiver
             android:name=".tuner.TunerService$ClearReceiver"
             android:exported="false">
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index dee4ff5..9722b1f 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -1,7 +1,7 @@
 {
   // Looking for unit test presubmit configuration?
   // This currently lives in ATP config apct/system_ui/unit_test
-  "presubmit": [
+  "presubmit-large": [
     {
       "name": "PlatformScenarioTests",
       "options": [
@@ -24,7 +24,9 @@
             "exclude-annotation": "android.platform.test.scenario.annotation.FoldableOnly"
         }
       ]
-    },
+    }
+  ],
+  "presubmit": [
     {
       "name": "SystemUIGoogleTests",
       "options": [
diff --git a/packages/SystemUI/res/drawable/auth_dialog_enterprise.xml b/packages/SystemUI/res/drawable/auth_dialog_enterprise.xml
index c547c52..ec9465b 100644
--- a/packages/SystemUI/res/drawable/auth_dialog_enterprise.xml
+++ b/packages/SystemUI/res/drawable/auth_dialog_enterprise.xml
@@ -20,6 +20,6 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM12,15c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM14,6h-4L10,4h4v2z"
+        android:pathData="@*android:string/config_work_badge_path_24"
         android:fillColor="?android:attr/colorAccent"/>
 </vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_credential_password_view.xml b/packages/SystemUI/res/layout/auth_credential_password_view.xml
index 1e0ce00..0ff1db2 100644
--- a/packages/SystemUI/res/layout/auth_credential_password_view.xml
+++ b/packages/SystemUI/res/layout/auth_credential_password_view.xml
@@ -18,64 +18,72 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:gravity="center_horizontal"
-    android:elevation="@dimen/biometric_dialog_elevation">
+    android:elevation="@dimen/biometric_dialog_elevation"
+    android:orientation="vertical">
 
-    <Space
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_weight="1"/>
-
-    <ImageView
-        android:id="@+id/icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"/>
-
-    <TextView
-        android:id="@+id/title"
+    <RelativeLayout
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="@style/TextAppearance.AuthCredential.Title"/>
+        android:layout_height="match_parent"
+        android:orientation="vertical">
 
-    <TextView
-        android:id="@+id/subtitle"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="@style/TextAppearance.AuthCredential.Subtitle"/>
+        <LinearLayout
+            android:id="@+id/auth_credential_header"
+            style="@style/AuthCredentialHeaderStyle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true">
 
-    <TextView
-        android:id="@+id/description"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="@style/TextAppearance.AuthCredential.Description"/>
+            <ImageView
+                android:id="@+id/icon"
+                android:layout_width="48dp"
+                android:layout_height="48dp"
+                android:contentDescription="@null" />
 
-    <Space
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_weight="1"/>
+            <TextView
+                android:id="@+id/title"
+                style="@style/TextAppearance.AuthNonBioCredential.Title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
 
-    <ImeAwareEditText
-        android:id="@+id/lockPassword"
-        android:layout_width="208dp"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal"
-        android:minHeight="48dp"
-        android:gravity="center"
-        android:inputType="textPassword"
-        android:maxLength="500"
-        android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
-        style="@style/TextAppearance.AuthCredential.PasswordEntry"/>
+            <TextView
+                android:id="@+id/subtitle"
+                style="@style/TextAppearance.AuthNonBioCredential.Subtitle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
 
-    <TextView
-        android:id="@+id/error"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="@style/TextAppearance.AuthCredential.Error"/>
+            <TextView
+                android:id="@+id/description"
+                style="@style/TextAppearance.AuthNonBioCredential.Description"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
 
-    <Space
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_weight="5"/>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:orientation="vertical"
+            android:layout_alignParentBottom="true">
+
+            <ImeAwareEditText
+                android:id="@+id/lockPassword"
+                style="@style/TextAppearance.AuthCredential.PasswordEntry"
+                android:layout_width="208dp"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
+                android:inputType="textPassword"
+                android:minHeight="48dp" />
+
+            <TextView
+                android:id="@+id/error"
+                style="@style/TextAppearance.AuthNonBioCredential.Error"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+
+        </LinearLayout>
+
+    </RelativeLayout>
 
 </com.android.systemui.biometrics.AuthCredentialPasswordView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
index 4939ea2..dada981 100644
--- a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
+++ b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
@@ -22,76 +22,81 @@
     android:gravity="center_horizontal"
     android:elevation="@dimen/biometric_dialog_elevation">
 
-    <Space
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_weight="1"/>
-
-    <ImageView
-        android:id="@+id/icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"/>
-
-    <TextView
-        android:id="@+id/title"
+    <RelativeLayout
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="@style/TextAppearance.AuthCredential.Title"/>
+        android:layout_height="match_parent"
+        android:orientation="vertical">
 
-    <TextView
-        android:id="@+id/subtitle"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="@style/TextAppearance.AuthCredential.Subtitle"/>
+        <LinearLayout
+            android:id="@+id/auth_credential_header"
+            style="@style/AuthCredentialHeaderStyle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
 
-    <TextView
-        android:id="@+id/description"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="@style/TextAppearance.AuthCredential.Description"/>
+            <ImageView
+                android:id="@+id/icon"
+                android:layout_width="48dp"
+                android:layout_height="48dp"
+                android:contentDescription="@null" />
 
-    <Space
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_weight="1"/>
+            <TextView
+                android:id="@+id/title"
+                style="@style/TextAppearance.AuthNonBioCredential.Title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
 
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:gravity="center"
-        android:paddingLeft="0dp"
-        android:paddingRight="0dp"
-        android:paddingTop="0dp"
-        android:paddingBottom="16dp"
-        android:clipToPadding="false">
+            <TextView
+                android:id="@+id/subtitle"
+                style="@style/TextAppearance.AuthNonBioCredential.Subtitle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
 
-        <FrameLayout
-            android:layout_width="wrap_content"
-            android:layout_height="0dp"
-            android:layout_weight="1"
-            style="@style/LockPatternContainerStyle">
+            <TextView
+                android:id="@+id/description"
+                style="@style/TextAppearance.AuthNonBioCredential.Description"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
+        </LinearLayout>
 
-            <com.android.internal.widget.LockPatternView
-                android:id="@+id/lockPattern"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_gravity="center"
-                style="@style/LockPatternStyleBiometricPrompt"/>
-
-        </FrameLayout>
-
-        <TextView
-            android:id="@+id/error"
+        <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            style="@style/TextAppearance.AuthCredential.Error"/>
+            android:layout_below="@id/auth_credential_header"
+            android:gravity="center"
+            android:orientation="vertical"
+            android:paddingBottom="16dp"
+            android:paddingTop="60dp">
 
-    </LinearLayout>
+            <FrameLayout
+                style="@style/LockPatternContainerStyle"
+                android:layout_width="wrap_content"
+                android:layout_height="0dp"
+                android:layout_weight="1">
 
-    <Space
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_weight="1"/>
+                <com.android.internal.widget.LockPatternView
+                    android:id="@+id/lockPattern"
+                    style="@style/LockPatternStyle"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_gravity="center" />
+
+            </FrameLayout>
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true">
+
+            <TextView
+                android:id="@+id/error"
+                style="@style/TextAppearance.AuthNonBioCredential.Error"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+
+        </LinearLayout>
+
+    </RelativeLayout>
 
 </com.android.systemui.biometrics.AuthCredentialPatternView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml b/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml
new file mode 100644
index 0000000..b6f516f
--- /dev/null
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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.
+-->
+<TextClock
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/date_view"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:paddingLeft="@dimen/dream_overlay_complication_clock_date_padding_left"
+    android:paddingBottom="@dimen/dream_overlay_complication_clock_date_padding_bottom"
+    android:gravity="center_horizontal"
+    android:textColor="@android:color/white"
+    android:shadowColor="@color/keyguard_shadow_color"
+    android:shadowRadius="?attr/shadowRadius"
+    android:format12Hour="EEE, MMM d"
+    android:format24Hour="EEE, MMM d"
+    android:textSize="@dimen/dream_overlay_complication_clock_date_text_size"/>
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
new file mode 100644
index 0000000..a41d34f
--- /dev/null
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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.
+-->
+<TextClock
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/time_view"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:paddingLeft="@dimen/dream_overlay_complication_clock_time_padding_left"
+    android:fontFamily="sans-serif-thin"
+    android:textColor="@android:color/white"
+    android:format12Hour="h:mm"
+    android:format24Hour="kk:mm"
+    android:shadowColor="@color/keyguard_shadow_color"
+    android:shadowRadius="?attr/shadowRadius"
+    android:textSize="@dimen/dream_overlay_complication_clock_time_text_size"/>
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml b/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml
new file mode 100644
index 0000000..08f0d67
--- /dev/null
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/weather_view"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:paddingLeft="@dimen/dream_overlay_complication_weather_padding_left"
+    android:paddingBottom="@dimen/dream_overlay_complication_weather_padding_bottom"
+    android:textColor="@android:color/white"
+    android:shadowColor="@color/keyguard_shadow_color"
+    android:shadowRadius="?attr/shadowRadius"
+    android:textSize="@dimen/dream_overlay_complication_weather_text_size"/>
diff --git a/packages/SystemUI/res/layout/dream_overlay_complications_layer.xml b/packages/SystemUI/res/layout/dream_overlay_complications_layer.xml
index 2d565a1..f4eb32f 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complications_layer.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complications_layer.xml
@@ -20,34 +20,6 @@
     android:id="@+id/dream_overlay_complications_layer"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-    <TextClock
-        android:id="@+id/time_view"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:fontFamily="sans-serif-thin"
-        android:format12Hour="h:mm"
-        android:format24Hour="kk:mm"
-        android:shadowColor="#B2000000"
-        android:shadowRadius="2.0"
-        android:singleLine="true"
-        android:textSize="72sp"
-        android:textColor="@android:color/white"
-        app:layout_constraintBottom_toTopOf="@+id/date_view"
-        app:layout_constraintStart_toStartOf="parent" />
-    <TextClock
-        android:id="@+id/date_view"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:shadowColor="#B2000000"
-        android:shadowRadius="2.0"
-        android:format12Hour="EEE, MMM d"
-        android:format24Hour="EEE, MMM d"
-        android:singleLine="true"
-        android:textSize="18sp"
-        android:textColor="@android:color/white"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="@+id/time_view"
-        app:layout_constraintStart_toStartOf="@+id/time_view" />
     <androidx.constraintlayout.widget.Guideline
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/dream_overlay_container.xml b/packages/SystemUI/res/layout/dream_overlay_container.xml
index 4929f50..3c2183d 100644
--- a/packages/SystemUI/res/layout/dream_overlay_container.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_container.xml
@@ -25,7 +25,7 @@
         android:id="@+id/dream_overlay_content"
         android:layout_width="match_parent"
         android:layout_height="0dp"
-        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/dream_overlay_status_bar"
         app:layout_constraintBottom_toBottomOf="parent" />
 
     <com.android.systemui.dreams.DreamOverlayStatusBarView
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 2290964..39d7f4f 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -122,7 +122,7 @@
             android:layout_marginTop="@dimen/notification_panel_margin_top"
             android:layout_width="@dimen/notification_panel_width"
             android:layout_height="match_parent"
-            android:layout_marginBottom="@dimen/close_handle_underlap"
+            android:layout_marginBottom="@dimen/notification_panel_margin_bottom"
             android:importantForAccessibility="no"
             systemui:layout_constraintStart_toStartOf="parent"
             systemui:layout_constraintEnd_toEndOf="parent"
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 89d046b..c2cec52 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -26,6 +26,10 @@
          keyguard_split_shade_top_margin - status_bar_header_height_keyguard = 8dp -->
     <dimen name="keyguard_clock_top_margin">8dp</dimen>
 
+    <dimen name="split_shade_notifications_scrim_margin_bottom">16dp</dimen>
+
+    <dimen name="notification_panel_margin_bottom">48dp</dimen>
+
     <!-- Limit the TaskView to this percentage of the overall screen width (0.0 - 1.0) -->
     <item name="controls_task_view_width_percentage" translatable="false" format="float" type="dimen">0.45</item>
     <dimen name="controls_task_view_right_margin">8dp</dimen>
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
similarity index 66%
copy from packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl
copy to packages/SystemUI/res/values-sw720dp-land/dimens.xml
index cb602d79..219fd43 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -1,5 +1,6 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2022, 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.
@@ -12,8 +13,9 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- */
-
-package android.net;
-
-parcelable NetworkStateSnapshot;
+*/
+-->
+<resources>
+    <dimen name="split_shade_notifications_scrim_margin_bottom">16dp</dimen>
+    <dimen name="notification_panel_margin_bottom">56dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3cceaf0..74bb9e4 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -311,9 +311,6 @@
     <!-- Move the back button drawable for 3 button layout upwards in ime mode and in portrait -->
     <dimen name="navbar_back_button_ime_offset">2dp</dimen>
 
-    <!-- Amount of close_handle that will NOT overlap the notification list -->
-    <dimen name="close_handle_underlap">32dp</dimen>
-
     <!-- Height of the status bar header bar in the car setting. -->
     <dimen name="car_status_bar_header_height">128dp</dimen>
 
@@ -376,8 +373,12 @@
     -->
     <dimen name="nssl_split_shade_min_content_height">256dp</dimen>
 
-    <!-- The bottom margin of the panel that holds the list of notifications. -->
-    <dimen name="notification_panel_margin_bottom">0dp</dimen>
+    <dimen name="notification_panel_margin_bottom">32dp</dimen>
+
+    <!-- The bottom padding of the panel that holds the list of notifications. -->
+    <dimen name="notification_panel_padding_bottom">0dp</dimen>
+
+    <dimen name="split_shade_notifications_scrim_margin_bottom">0dp</dimen>
 
     <dimen name="notification_panel_width">@dimen/match_parent</dimen>
 
@@ -1345,6 +1346,16 @@
          shade. -->
     <dimen name="dream_overlay_notifications_drag_area_height">100dp</dimen>
 
+    <!-- Dream overlay complications related dimensions -->
+    <dimen name="dream_overlay_complication_clock_time_padding_left">50dp</dimen>
+    <dimen name="dream_overlay_complication_clock_time_text_size">72sp</dimen>
+    <dimen name="dream_overlay_complication_clock_date_padding_left">60dp</dimen>
+    <dimen name="dream_overlay_complication_clock_date_padding_bottom">50dp</dimen>
+    <dimen name="dream_overlay_complication_clock_date_text_size">18sp</dimen>
+    <dimen name="dream_overlay_complication_weather_padding_left">20dp</dimen>
+    <dimen name="dream_overlay_complication_weather_padding_bottom">50dp</dimen>
+    <dimen name="dream_overlay_complication_weather_text_size">18sp</dimen>
+
     <!-- The position of the end guide, which dream overlay complications can align their start with
          if their end is aligned with the parent end. Represented as the percentage over from the
          start of the parent container. -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9b23829..590cc9b 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -236,6 +236,41 @@
         <item name="android:textColor">?android:attr/colorError</item>
     </style>
 
+    <style name="TextAppearance.AuthNonBioCredential"
+        parent="@android:style/TextAppearance.DeviceDefault">
+        <item name="android:accessibilityLiveRegion">polite</item>
+        <item name="android:textAlignment">gravity</item>
+        <item name="android:layout_gravity">top</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+
+    <style name="TextAppearance.AuthNonBioCredential.Title">
+        <item name="android:fontFamily">google-sans</item>
+        <item name="android:layout_marginTop">20dp</item>
+        <item name="android:textSize">36sp</item>
+    </style>
+
+    <style name="TextAppearance.AuthNonBioCredential.Subtitle">
+        <item name="android:fontFamily">google-sans</item>
+        <item name="android:layout_marginTop">20dp</item>
+        <item name="android:textSize">18sp</item>
+    </style>
+
+    <style name="TextAppearance.AuthNonBioCredential.Description">
+        <item name="android:fontFamily">google-sans</item>
+        <item name="android:layout_marginTop">20dp</item>
+        <item name="android:textSize">16sp</item>
+    </style>
+
+    <style name="TextAppearance.AuthNonBioCredential.Error">
+        <item name="android:paddingTop">6dp</item>
+        <item name="android:paddingBottom">18dp</item>
+        <item name="android:paddingHorizontal">24dp</item>
+        <item name="android:textSize">14sp</item>
+        <item name="android:textColor">?android:attr/colorError</item>
+        <item name="android:gravity">center</item>
+    </style>
+
     <style name="TextAppearance.AuthCredential.PasswordEntry" parent="@android:style/TextAppearance.DeviceDefault">
         <item name="android:gravity">center</item>
         <item name="android:singleLine">true</item>
@@ -243,6 +278,15 @@
         <item name="android:textSize">24sp</item>
     </style>
 
+    <style name="AuthCredentialHeaderStyle">
+        <item name="android:paddingStart">48dp</item>
+        <item name="android:paddingEnd">24dp</item>
+        <item name="android:paddingTop">28dp</item>
+        <item name="android:paddingBottom">20dp</item>
+        <item name="android:orientation">vertical</item>
+        <item name="android:layout_gravity">top</item>
+    </style>
+
     <style name="DeviceManagementDialogTitle">
         <item name="android:gravity">center</item>
         <item name="android:textAppearance">@style/TextAppearance.DeviceManagementDialog.Title</item>
@@ -307,9 +351,8 @@
         <item name="android:maxWidth">420dp</item>
         <item name="android:minHeight">0dp</item>
         <item name="android:minWidth">0dp</item>
-        <item name="android:paddingBottom">0dp</item>
-        <item name="android:paddingHorizontal">44dp</item>
-        <item name="android:paddingTop">0dp</item>
+        <item name="android:paddingHorizontal">60dp</item>
+        <item name="android:paddingBottom">40dp</item>
     </style>
 
     <style name="LockPatternStyle">
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
index 9010d51..fc6bb50 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
@@ -42,7 +42,9 @@
      * are different than actual bounds (e.g. view container may
      * have larger width than width of the items in the container)
      */
-    private val viewCenterProvider: ViewCenterProvider = object : ViewCenterProvider {}
+    private val viewCenterProvider: ViewCenterProvider = object : ViewCenterProvider {},
+    /** Allows to set the alpha based on the progress. */
+    private val alphaProvider: AlphaProvider? = null
 ) : UnfoldTransitionProgressProvider.TransitionProgressListener {
 
     private val screenSize = Point()
@@ -99,17 +101,27 @@
 
     override fun onTransitionProgress(progress: Float) {
         animatedViews.forEach {
-            it.view.get()?.let { view ->
-                translationApplier.apply(
-                    view = view,
-                    x = it.startTranslationX * (1 - progress),
-                    y = it.startTranslationY * (1 - progress)
-                )
-            }
+            it.applyTransition(progress)
+            it.applyAlpha(progress)
         }
         lastAnimationProgress = progress
     }
 
+    private fun AnimatedView.applyTransition(progress: Float) {
+        view.get()?.let { view ->
+            translationApplier.apply(
+                view = view,
+                x = startTranslationX * (1 - progress),
+                y = startTranslationY * (1 - progress)
+            )
+        }
+    }
+
+    private fun AnimatedView.applyAlpha(progress: Float) {
+        if (alphaProvider == null) return
+        view.get()?.alpha = alphaProvider.getAlpha(progress)
+    }
+
     private fun createAnimatedView(view: View): AnimatedView =
         AnimatedView(view = WeakReference(view)).updateAnimatedView(view)
 
@@ -146,6 +158,13 @@
         }
     }
 
+    /** Allows to set a custom alpha based on the progress. */
+    interface AlphaProvider {
+
+        /** Returns the alpha views should have at a given progress. */
+        fun getAlpha(progress: Float): Float
+    }
+
     /**
      * Interface that allows to use custom logic to get the center of the view
      */
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesProvider.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesProvider.aidl
new file mode 100644
index 0000000..6db06f0
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesProvider.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.media;
+
+import com.android.systemui.shared.media.INearbyMediaDevicesUpdateCallback;
+import com.android.systemui.shared.media.NearbyDevice;
+
+/**
+ * An interface that provides information about nearby devices that are able to play media.
+ *
+ * External clients will implement this interface and System UI will invoke it if it's passed to
+ * SystemUI via {@link INearbyMediaDevicesService.registerProvider}.
+ */
+interface INearbyMediaDevicesProvider {
+  /**
+   * Returns a list of nearby devices that are able to play media.
+   */
+  List<NearbyDevice> getCurrentNearbyDevices() = 1;
+
+  /**
+   * Registers a callback that will be notified each time the status of a nearby device changes.
+   */
+  oneway void registerNearbyDevicesCallback(in INearbyMediaDevicesUpdateCallback callback) = 2;
+
+  /**
+   * Unregisters a callback. See {@link registerNearbyDevicesCallback}.
+   */
+  oneway void unregisterNearbyDevicesCallback(in INearbyMediaDevicesUpdateCallback callback) = 3;
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesService.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesService.aidl
new file mode 100644
index 0000000..4f3e10d
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesService.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.media;
+
+import com.android.systemui.shared.media.INearbyMediaDevicesProvider;
+
+/**
+ * An interface that can be invoked to notify System UI of nearby media devices.
+ *
+ * External clients wanting to notify System UI about the status of nearby media devices should
+ * implement {@link INearbyMediaDevicesProvider} and then register it with system UI using this
+ * service.
+ *
+ * System UI will implement this interface and external clients will invoke it.
+ */
+interface INearbyMediaDevicesService {
+  /** Registers a new provider. */
+  oneway void registerProvider(INearbyMediaDevicesProvider provider) = 1;
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesUpdateCallback.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesUpdateCallback.aidl
new file mode 100644
index 0000000..a835f52
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesUpdateCallback.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.media;
+
+/**
+ * A callback used to notify implementors of changes in the status of nearby devices that are able
+ * to play media.
+ *
+ * External clients may allow registration of these callbacks and external clients will be
+ * responsible for notifying the callbacks appropriately. System UI is only a mediator between the
+ * external client and these callbacks.
+ */
+interface INearbyMediaDevicesUpdateCallback {
+    /** Unknown distance range. */
+    const int RANGE_UNKNOWN = 0;
+    /** Distance is very far away from the peer device. */
+    const int RANGE_FAR = 1;
+    /** Distance is relatively long from the peer device, typically a few meters. */
+    const int RANGE_LONG = 2;
+    /** Distance is close to the peer device, typically with one or two meter. */
+    const int RANGE_CLOSE = 3;
+    /** Distance is very close to the peer device, typically within one meter or less. */
+    const int RANGE_WITHIN_REACH = 4;
+
+    /** Invoked by external clients when media device changes are detected. */
+    oneway void nearbyDeviceUpdate(in String routeId, in int rangeZone) = 1;
+}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/media/NearbyDevice.aidl
similarity index 73%
copy from packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl
copy to packages/SystemUI/shared/src/com/android/systemui/shared/media/NearbyDevice.aidl
index cb602d79..62b50ed 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/media/NearbyDevice.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
+/*
+ * Copyright (C) 2022 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
+ *      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,
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net;
+package com.android.systemui.shared.media;
 
-parcelable NetworkStateSnapshot;
+parcelable NearbyDevice;
diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyDevice.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/media/NearbyDevice.kt
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/media/nearby/NearbyDevice.kt
rename to packages/SystemUI/shared/src/com/android/systemui/shared/media/NearbyDevice.kt
index 96b853f..9cab3ab 100644
--- a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyDevice.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/media/NearbyDevice.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.media.nearby
+package com.android.systemui.shared.media
 
 import android.os.Parcel
 import android.os.Parcelable
@@ -26,14 +26,15 @@
  *   - [routeId] identifying the media route
  *   - [rangeZone] specifying how far away the device with the media route is from this device.
  */
-class NearbyDevice(parcel: Parcel) : Parcelable {
-    var routeId: String? = null
+class NearbyDevice(
+    val routeId: String?,
     @RangeZone val rangeZone: Int
+) : Parcelable {
 
-    init {
-        routeId = parcel.readString() ?: "unknown"
+    private constructor(parcel: Parcel) : this(
+        routeId = parcel.readString() ?: null,
         rangeZone = parcel.readInt()
-    }
+    )
 
     override fun describeContents() = 0
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/media/RangeZone.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/media/RangeZone.kt
new file mode 100644
index 0000000..b5eaff6
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/media/RangeZone.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.media
+
+import androidx.annotation.IntDef
+import kotlin.annotation.AnnotationRetention
+
+@IntDef(
+    INearbyMediaDevicesUpdateCallback.RANGE_UNKNOWN,
+    INearbyMediaDevicesUpdateCallback.RANGE_FAR,
+    INearbyMediaDevicesUpdateCallback.RANGE_LONG,
+    INearbyMediaDevicesUpdateCallback.RANGE_CLOSE,
+    INearbyMediaDevicesUpdateCallback.RANGE_WITHIN_REACH
+)
+@Retention(AnnotationRetention.SOURCE)
+/** The various range zones a device can be in, in relation to the current device. */
+annotation class RangeZone
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index 20d6e32..881e6a9 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -120,6 +120,13 @@
             AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT; // = 9
 
     /**
+     * Action ID to send the KEYCODE_HEADSETHOOK KeyEvent, which is used to answer/hang up calls and
+     * play/stop media
+     */
+    private static final int SYSTEM_ACTION_ID_KEYCODE_HEADSETHOOK =
+            AccessibilityService.GLOBAL_ACTION_KEYCODE_HEADSETHOOK; // = 10
+
+    /**
      * Action ID to trigger the accessibility button
      */
     public static final int SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON =
@@ -137,6 +144,36 @@
     public static final int SYSTEM_ACTION_ID_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE =
             AccessibilityService.GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE; // 15
 
+    /**
+     * Action ID to trigger the dpad up button
+     */
+    private static final int SYSTEM_ACTION_ID_DPAD_UP =
+            AccessibilityService.GLOBAL_ACTION_DPAD_UP; // 16
+
+    /**
+     * Action ID to trigger the dpad down button
+     */
+    private static final int SYSTEM_ACTION_ID_DPAD_DOWN =
+            AccessibilityService.GLOBAL_ACTION_DPAD_DOWN; // 17
+
+    /**
+     * Action ID to trigger the dpad left button
+     */
+    private static final int SYSTEM_ACTION_ID_DPAD_LEFT =
+            AccessibilityService.GLOBAL_ACTION_DPAD_LEFT; // 18
+
+    /**
+     * Action ID to trigger the dpad right button
+     */
+    private static final int SYSTEM_ACTION_ID_DPAD_RIGHT =
+            AccessibilityService.GLOBAL_ACTION_DPAD_RIGHT; // 19
+
+    /**
+     * Action ID to trigger dpad center keyevent
+     */
+    private static final int SYSTEM_ACTION_ID_DPAD_CENTER =
+            AccessibilityService.GLOBAL_ACTION_DPAD_CENTER; // 20
+
     private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
 
     private final SystemActionsBroadcastReceiver mReceiver;
@@ -222,10 +259,34 @@
                 R.string.accessibility_system_action_screenshot_label,
                 SystemActionsBroadcastReceiver.INTENT_ACTION_TAKE_SCREENSHOT);
 
+        RemoteAction actionHeadsetHook = createRemoteAction(
+                R.string.accessibility_system_action_headset_hook_label,
+                SystemActionsBroadcastReceiver.INTENT_ACTION_HEADSET_HOOK);
+
         RemoteAction actionAccessibilityShortcut = createRemoteAction(
                 R.string.accessibility_system_action_hardware_a11y_shortcut_label,
                 SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_SHORTCUT);
 
+        RemoteAction actionDpadUp = createRemoteAction(
+                R.string.accessibility_system_action_dpad_up_label,
+                SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_UP);
+
+        RemoteAction actionDpadDown = createRemoteAction(
+                R.string.accessibility_system_action_dpad_down_label,
+                SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_DOWN);
+
+        RemoteAction actionDpadLeft = createRemoteAction(
+                R.string.accessibility_system_action_dpad_left_label,
+                SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_LEFT);
+
+        RemoteAction actionDpadRight = createRemoteAction(
+                R.string.accessibility_system_action_dpad_right_label,
+                SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_RIGHT);
+
+        RemoteAction actionDpadCenter = createRemoteAction(
+                R.string.accessibility_system_action_dpad_center_label,
+                SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_CENTER);
+
         mA11yManager.registerSystemAction(actionBack, SYSTEM_ACTION_ID_BACK);
         mA11yManager.registerSystemAction(actionHome, SYSTEM_ACTION_ID_HOME);
         mA11yManager.registerSystemAction(actionRecents, SYSTEM_ACTION_ID_RECENTS);
@@ -234,8 +295,14 @@
         mA11yManager.registerSystemAction(actionPowerDialog, SYSTEM_ACTION_ID_POWER_DIALOG);
         mA11yManager.registerSystemAction(actionLockScreen, SYSTEM_ACTION_ID_LOCK_SCREEN);
         mA11yManager.registerSystemAction(actionTakeScreenshot, SYSTEM_ACTION_ID_TAKE_SCREENSHOT);
+        mA11yManager.registerSystemAction(actionHeadsetHook, SYSTEM_ACTION_ID_KEYCODE_HEADSETHOOK);
         mA11yManager.registerSystemAction(
                 actionAccessibilityShortcut, SYSTEM_ACTION_ID_ACCESSIBILITY_SHORTCUT);
+        mA11yManager.registerSystemAction(actionDpadUp, SYSTEM_ACTION_ID_DPAD_UP);
+        mA11yManager.registerSystemAction(actionDpadDown, SYSTEM_ACTION_ID_DPAD_DOWN);
+        mA11yManager.registerSystemAction(actionDpadLeft, SYSTEM_ACTION_ID_DPAD_LEFT);
+        mA11yManager.registerSystemAction(actionDpadRight, SYSTEM_ACTION_ID_DPAD_RIGHT);
+        mA11yManager.registerSystemAction(actionDpadCenter, SYSTEM_ACTION_ID_DPAD_CENTER);
         registerOrUnregisterDismissNotificationShadeAction();
     }
 
@@ -305,6 +372,10 @@
                 labelId = R.string.accessibility_system_action_screenshot_label;
                 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_TAKE_SCREENSHOT;
                 break;
+            case SYSTEM_ACTION_ID_KEYCODE_HEADSETHOOK:
+                labelId = R.string.accessibility_system_action_headset_hook_label;
+                intent = SystemActionsBroadcastReceiver.INTENT_ACTION_HEADSET_HOOK;
+                break;
             case SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON:
                 labelId = R.string.accessibility_system_action_on_screen_a11y_shortcut_label;
                 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_BUTTON;
@@ -323,6 +394,26 @@
                 intent = SystemActionsBroadcastReceiver
                         .INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE;
                 break;
+            case SYSTEM_ACTION_ID_DPAD_UP:
+                labelId = R.string.accessibility_system_action_dpad_up_label;
+                intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_UP;
+                break;
+            case SYSTEM_ACTION_ID_DPAD_DOWN:
+                labelId = R.string.accessibility_system_action_dpad_down_label;
+                intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_DOWN;
+                break;
+            case SYSTEM_ACTION_ID_DPAD_LEFT:
+                labelId = R.string.accessibility_system_action_dpad_left_label;
+                intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_LEFT;
+                break;
+            case SYSTEM_ACTION_ID_DPAD_RIGHT:
+                labelId = R.string.accessibility_system_action_dpad_right_label;
+                intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_RIGHT;
+                break;
+            case SYSTEM_ACTION_ID_DPAD_CENTER:
+                labelId = R.string.accessibility_system_action_dpad_center_label;
+                intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_CENTER;
+                break;
             default:
                 return;
         }
@@ -411,6 +502,10 @@
                 SCREENSHOT_ACCESSIBILITY_ACTIONS, new Handler(Looper.getMainLooper()), null);
     }
 
+    private void handleHeadsetHook() {
+        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK);
+    }
+
     private void handleAccessibilityButton() {
         AccessibilityManager.getInstance(mContext).notifyAccessibilityButtonClicked(
                 Display.DEFAULT_DISPLAY);
@@ -434,6 +529,26 @@
                         CommandQueue.FLAG_EXCLUDE_NONE, false /* force */));
     }
 
+    private void handleDpadUp() {
+        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_UP);
+    }
+
+    private void handleDpadDown() {
+        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_DOWN);
+    }
+
+    private void handleDpadLeft() {
+        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_LEFT);
+    }
+
+    private void handleDpadRight() {
+        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_RIGHT);
+    }
+
+    private void handleDpadCenter() {
+        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER);
+    }
+
     private class SystemActionsBroadcastReceiver extends BroadcastReceiver {
         private static final String INTENT_ACTION_BACK = "SYSTEM_ACTION_BACK";
         private static final String INTENT_ACTION_HOME = "SYSTEM_ACTION_HOME";
@@ -443,6 +558,7 @@
         private static final String INTENT_ACTION_POWER_DIALOG = "SYSTEM_ACTION_POWER_DIALOG";
         private static final String INTENT_ACTION_LOCK_SCREEN = "SYSTEM_ACTION_LOCK_SCREEN";
         private static final String INTENT_ACTION_TAKE_SCREENSHOT = "SYSTEM_ACTION_TAKE_SCREENSHOT";
+        private static final String INTENT_ACTION_HEADSET_HOOK = "SYSTEM_ACTION_HEADSET_HOOK";
         private static final String INTENT_ACTION_ACCESSIBILITY_BUTTON =
                 "SYSTEM_ACTION_ACCESSIBILITY_BUTTON";
         private static final String INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER =
@@ -451,6 +567,11 @@
                 "SYSTEM_ACTION_ACCESSIBILITY_SHORTCUT";
         private static final String INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE =
                 "SYSTEM_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE";
+        private static final String INTENT_ACTION_DPAD_UP = "SYSTEM_ACTION_DPAD_UP";
+        private static final String INTENT_ACTION_DPAD_DOWN = "SYSTEM_ACTION_DPAD_DOWN";
+        private static final String INTENT_ACTION_DPAD_LEFT = "SYSTEM_ACTION_DPAD_LEFT";
+        private static final String INTENT_ACTION_DPAD_RIGHT = "SYSTEM_ACTION_DPAD_RIGHT";
+        private static final String INTENT_ACTION_DPAD_CENTER = "SYSTEM_ACTION_DPAD_CENTER";
 
         private PendingIntent createPendingIntent(Context context, String intentAction) {
             switch (intentAction) {
@@ -462,10 +583,16 @@
                 case INTENT_ACTION_POWER_DIALOG:
                 case INTENT_ACTION_LOCK_SCREEN:
                 case INTENT_ACTION_TAKE_SCREENSHOT:
+                case INTENT_ACTION_HEADSET_HOOK:
                 case INTENT_ACTION_ACCESSIBILITY_BUTTON:
                 case INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER:
                 case INTENT_ACTION_ACCESSIBILITY_SHORTCUT:
-                case INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE: {
+                case INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE:
+                case INTENT_ACTION_DPAD_UP:
+                case INTENT_ACTION_DPAD_DOWN:
+                case INTENT_ACTION_DPAD_LEFT:
+                case INTENT_ACTION_DPAD_RIGHT:
+                case INTENT_ACTION_DPAD_CENTER: {
                     Intent intent = new Intent(intentAction);
                     intent.setPackage(context.getPackageName());
                     return PendingIntent.getBroadcast(context, 0, intent,
@@ -487,10 +614,16 @@
             intentFilter.addAction(INTENT_ACTION_POWER_DIALOG);
             intentFilter.addAction(INTENT_ACTION_LOCK_SCREEN);
             intentFilter.addAction(INTENT_ACTION_TAKE_SCREENSHOT);
+            intentFilter.addAction(INTENT_ACTION_HEADSET_HOOK);
             intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_BUTTON);
             intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER);
             intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_SHORTCUT);
             intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE);
+            intentFilter.addAction(INTENT_ACTION_DPAD_UP);
+            intentFilter.addAction(INTENT_ACTION_DPAD_DOWN);
+            intentFilter.addAction(INTENT_ACTION_DPAD_LEFT);
+            intentFilter.addAction(INTENT_ACTION_DPAD_RIGHT);
+            intentFilter.addAction(INTENT_ACTION_DPAD_CENTER);
             return intentFilter;
         }
 
@@ -530,6 +663,10 @@
                     handleTakeScreenshot();
                     break;
                 }
+                case INTENT_ACTION_HEADSET_HOOK: {
+                    handleHeadsetHook();
+                    break;
+                }
                 case INTENT_ACTION_ACCESSIBILITY_BUTTON: {
                     handleAccessibilityButton();
                     break;
@@ -546,6 +683,26 @@
                     handleAccessibilityDismissNotificationShade();
                     break;
                 }
+                case INTENT_ACTION_DPAD_UP: {
+                    handleDpadUp();
+                    break;
+                }
+                case INTENT_ACTION_DPAD_DOWN: {
+                    handleDpadDown();
+                    break;
+                }
+                case INTENT_ACTION_DPAD_LEFT: {
+                    handleDpadLeft();
+                    break;
+                }
+                case INTENT_ACTION_DPAD_RIGHT: {
+                    handleDpadRight();
+                    break;
+                }
+                case INTENT_ACTION_DPAD_CENTER: {
+                    handleDpadCenter();
+                    break;
+                }
                 default:
                     break;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 41287b6..ec2beb1 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -27,6 +27,9 @@
 import com.android.systemui.clipboardoverlay.ClipboardListener;
 import com.android.systemui.dreams.DreamOverlayRegistrant;
 import com.android.systemui.dreams.SmartSpaceComplication;
+import com.android.systemui.dreams.complication.DreamClockDateComplication;
+import com.android.systemui.dreams.complication.DreamClockTimeComplication;
+import com.android.systemui.dreams.complication.DreamWeatherComplication;
 import com.android.systemui.globalactions.GlobalActionsComponent;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.dagger.KeyguardModule;
@@ -234,4 +237,25 @@
     @ClassKey(MediaDreamSentinel.class)
     public abstract CoreStartable bindMediaDreamSentinel(
             MediaDreamSentinel sentinel);
+
+    /** Inject into DreamClockTimeComplication.Registrant */
+    @Binds
+    @IntoMap
+    @ClassKey(DreamClockTimeComplication.Registrant.class)
+    public abstract CoreStartable bindDreamClockTimeComplicationRegistrant(
+            DreamClockTimeComplication.Registrant registrant);
+
+    /** Inject into DreamClockDateComplication.Registrant */
+    @Binds
+    @IntoMap
+    @ClassKey(DreamClockDateComplication.Registrant.class)
+    public abstract CoreStartable bindDreamClockDateComplicationRegistrant(
+            DreamClockDateComplication.Registrant registrant);
+
+    /** Inject into DreamWeatherComplication.Registrant */
+    @Binds
+    @IntoMap
+    @ClassKey(DreamWeatherComplication.Registrant.class)
+    public abstract CoreStartable bindDreamWeatherComplicationRegistrant(
+            DreamWeatherComplication.Registrant registrant);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java
new file mode 100644
index 0000000..59c52b9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 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.dreams.complication;
+
+import static com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationComponent.DreamClockDateComplicationModule.DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS;
+import static com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationComponent.DreamClockDateComplicationModule.DREAM_CLOCK_DATE_COMPLICATION_VIEW;
+
+import android.content.Context;
+import android.view.View;
+
+import com.android.systemui.CoreStartable;
+import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationComponent;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * Clock Date Complication that produce Clock Date view holder.
+ */
+public class DreamClockDateComplication implements Complication {
+    DreamClockDateComplicationComponent.Factory mComponentFactory;
+
+    /**
+     * Default constructor for {@link DreamClockDateComplication}.
+     */
+    @Inject
+    public DreamClockDateComplication(
+            DreamClockDateComplicationComponent.Factory componentFactory) {
+        mComponentFactory = componentFactory;
+    }
+
+    /**
+     * Create {@link DreamClockDateViewHolder}.
+     */
+    @Override
+    public ViewHolder createView(ComplicationViewModel model) {
+        return mComponentFactory.create().getViewHolder();
+    }
+
+    /**
+     * {@link CoreStartable} responsbile for registering {@link DreamClockDateComplication} with
+     * SystemUI.
+     */
+    public static class Registrant extends CoreStartable {
+        private final DreamOverlayStateController mDreamOverlayStateController;
+        private final DreamClockDateComplication mComplication;
+
+        /**
+         * Default constructor to register {@link DreamClockDateComplication}.
+         */
+        @Inject
+        public Registrant(Context context,
+                DreamOverlayStateController dreamOverlayStateController,
+                DreamClockDateComplication dreamClockDateComplication) {
+            super(context);
+            mDreamOverlayStateController = dreamOverlayStateController;
+            mComplication = dreamClockDateComplication;
+        }
+
+        @Override
+        public void start() {
+            mDreamOverlayStateController.addComplication(mComplication);
+        }
+    }
+
+    /**
+     * ViewHolder to contain value/logic associated with a Clock Date Complication View.
+     */
+    public static class DreamClockDateViewHolder implements ViewHolder {
+        private final View mView;
+        private final ComplicationLayoutParams mLayoutParams;
+
+        @Inject
+        DreamClockDateViewHolder(@Named(DREAM_CLOCK_DATE_COMPLICATION_VIEW) View view,
+                @Named(DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS)
+                        ComplicationLayoutParams layoutParams) {
+            mView = view;
+            mLayoutParams = layoutParams;
+        }
+
+        @Override
+        public View getView() {
+            return mView;
+        }
+
+        @Override
+        public ComplicationLayoutParams getLayoutParams() {
+            return mLayoutParams;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
new file mode 100644
index 0000000..b0c3a42
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 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.dreams.complication;
+
+import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationComponent.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS;
+import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationComponent.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_VIEW;
+
+import android.content.Context;
+import android.view.View;
+
+import com.android.systemui.CoreStartable;
+import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationComponent;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * Clock Time Complication that produce Clock Time view holder.
+ */
+public class DreamClockTimeComplication implements Complication {
+    DreamClockTimeComplicationComponent.Factory mComponentFactory;
+
+    /**
+     * Default constructor for {@link DreamClockTimeComplication}.
+     */
+    @Inject
+    public DreamClockTimeComplication(
+            DreamClockTimeComplicationComponent.Factory componentFactory) {
+        mComponentFactory = componentFactory;
+    }
+
+    /**
+     * Create {@link DreamClockTimeViewHolder}.
+     */
+    @Override
+    public ViewHolder createView(ComplicationViewModel model) {
+        return mComponentFactory.create().getViewHolder();
+    }
+
+    /**
+     * {@link CoreStartable} responsbile for registering {@link DreamClockTimeComplication} with
+     * SystemUI.
+     */
+    public static class Registrant extends CoreStartable {
+        private final DreamOverlayStateController mDreamOverlayStateController;
+        private final DreamClockTimeComplication mComplication;
+
+        /**
+         * Default constructor to register {@link DreamClockTimeComplication}.
+         */
+        @Inject
+        public Registrant(Context context,
+                DreamOverlayStateController dreamOverlayStateController,
+                DreamClockTimeComplication dreamClockTimeComplication) {
+            super(context);
+            mDreamOverlayStateController = dreamOverlayStateController;
+            mComplication = dreamClockTimeComplication;
+        }
+
+        @Override
+        public void start() {
+            mDreamOverlayStateController.addComplication(mComplication);
+        }
+    }
+
+    /**
+     * ViewHolder to contain value/logic associated with a Clock Time Complication View.
+     */
+    public static class DreamClockTimeViewHolder implements ViewHolder {
+        private final View mView;
+        private final ComplicationLayoutParams mLayoutParams;
+
+        @Inject
+        DreamClockTimeViewHolder(@Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW) View view,
+                @Named(DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS)
+                        ComplicationLayoutParams layoutParams) {
+            mView = view;
+            mLayoutParams = layoutParams;
+        }
+
+        @Override
+        public View getView() {
+            return mView;
+        }
+
+        @Override
+        public ComplicationLayoutParams getLayoutParams() {
+            return mLayoutParams;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java
new file mode 100644
index 0000000..cbdbef3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2022 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.dreams.complication;
+
+import static com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent.DreamWeatherComplicationModule.DREAM_WEATHER_COMPLICATION_LAYOUT_PARAMS;
+import static com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent.DreamWeatherComplicationModule.DREAM_WEATHER_COMPLICATION_VIEW;
+
+import android.app.smartspace.SmartspaceAction;
+import android.app.smartspace.SmartspaceTarget;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.text.TextUtils;
+import android.widget.TextView;
+
+import com.android.systemui.CoreStartable;
+import com.android.systemui.R;
+import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent;
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener;
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * Weather Complication that produce Weather view holder.
+ */
+public class DreamWeatherComplication implements Complication {
+    DreamWeatherComplicationComponent.Factory mComponentFactory;
+
+    /**
+     * Default constructor for {@link DreamWeatherComplication}.
+     */
+    @Inject
+    public DreamWeatherComplication(
+            DreamWeatherComplicationComponent.Factory componentFactory) {
+        mComponentFactory = componentFactory;
+    }
+
+    /**
+     * Create {@link DreamWeatherViewHolder}.
+     */
+    @Override
+    public ViewHolder createView(ComplicationViewModel model) {
+        return mComponentFactory.create().getViewHolder();
+    }
+
+    /**
+     * {@link CoreStartable} for registering {@link DreamWeatherComplication} with SystemUI.
+     */
+    public static class Registrant extends CoreStartable {
+        private final LockscreenSmartspaceController mSmartSpaceController;
+        private final DreamOverlayStateController mDreamOverlayStateController;
+        private final DreamWeatherComplication mComplication;
+
+        /**
+         * Default constructor to register {@link DreamWeatherComplication}.
+         */
+        @Inject
+        public Registrant(Context context,
+                LockscreenSmartspaceController smartspaceController,
+                DreamOverlayStateController dreamOverlayStateController,
+                DreamWeatherComplication dreamWeatherComplication) {
+            super(context);
+            mSmartSpaceController = smartspaceController;
+            mDreamOverlayStateController = dreamOverlayStateController;
+            mComplication = dreamWeatherComplication;
+        }
+
+        @Override
+        public void start() {
+            if (mSmartSpaceController.isEnabled()) {
+                mDreamOverlayStateController.addComplication(mComplication);
+            }
+        }
+    }
+
+    /**
+     * ViewHolder to contain value/logic associated with a Weather Complication View.
+     */
+    public static class DreamWeatherViewHolder implements ViewHolder {
+        private final TextView mView;
+        private final ComplicationLayoutParams mLayoutParams;
+        private final DreamWeatherViewController mViewController;
+
+        @Inject
+        DreamWeatherViewHolder(
+                @Named(DREAM_WEATHER_COMPLICATION_VIEW) TextView view,
+                DreamWeatherViewController controller,
+                @Named(DREAM_WEATHER_COMPLICATION_LAYOUT_PARAMS)
+                        ComplicationLayoutParams layoutParams) {
+            mView = view;
+            mLayoutParams = layoutParams;
+            mViewController = controller;
+            mViewController.init();
+        }
+
+        @Override
+        public TextView getView() {
+            return mView;
+        }
+
+        @Override
+        public ComplicationLayoutParams getLayoutParams() {
+            return mLayoutParams;
+        }
+    }
+
+    /**
+     * ViewController to contain value/logic associated with a Weather Complication View.
+     */
+    static class DreamWeatherViewController extends ViewController<TextView> {
+        private final LockscreenSmartspaceController mSmartSpaceController;
+        private SmartspaceTargetListener mSmartspaceTargetListener;
+
+        @Inject
+        DreamWeatherViewController(
+                @Named(DREAM_WEATHER_COMPLICATION_VIEW) TextView view,
+                LockscreenSmartspaceController smartspaceController
+        ) {
+            super(view);
+            mSmartSpaceController = smartspaceController;
+        }
+
+        @Override
+        protected void onViewAttached() {
+            mSmartspaceTargetListener = targets -> targets.forEach(
+                    t -> {
+                        if (t instanceof SmartspaceTarget
+                                && ((SmartspaceTarget) t).getFeatureType()
+                                == SmartspaceTarget.FEATURE_WEATHER) {
+                            final SmartspaceTarget target = (SmartspaceTarget) t;
+                            final SmartspaceAction headerAction = target.getHeaderAction();
+                            if (headerAction == null || TextUtils.isEmpty(
+                                    headerAction.getTitle())) {
+                                return;
+                            }
+
+                            String temperature = headerAction.getTitle().toString();
+                            mView.setText(temperature);
+                            final Icon icon = headerAction.getIcon();
+                            if (icon != null) {
+                                final int iconSize =
+                                        getResources().getDimensionPixelSize(
+                                                R.dimen.smart_action_button_icon_size);
+                                final Drawable iconDrawable = icon.loadDrawable(getContext());
+                                iconDrawable.setBounds(0, 0, iconSize, iconSize);
+                                mView.setCompoundDrawables(iconDrawable, null, null, null);
+                                mView.setCompoundDrawablePadding(
+                                        getResources().getDimensionPixelSize(
+                                                R.dimen.smart_action_button_icon_padding));
+
+                            }
+                        }
+                    });
+            mSmartSpaceController.addListener(mSmartspaceTargetListener);
+        }
+
+        @Override
+        protected void onViewDetached() {
+            mSmartSpaceController.removeListener(mSmartspaceTargetListener);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationComponent.java
new file mode 100644
index 0000000..eaffb1c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationComponent.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2022 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.dreams.complication.dagger;
+
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.util.Preconditions;
+import com.android.systemui.R;
+import com.android.systemui.dreams.complication.ComplicationLayoutParams;
+import com.android.systemui.dreams.complication.DreamClockDateComplication.DreamClockDateViewHolder;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Named;
+import javax.inject.Scope;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.Subcomponent;
+
+/**
+ * {@link DreamClockDateComplicationComponent} is responsible for generating dependencies
+ * surrounding the
+ * Clock Date {@link com.android.systemui.dreams.complication.Complication}, such as the layout
+ * details.
+ */
+@Subcomponent(modules = {
+        DreamClockDateComplicationComponent.DreamClockDateComplicationModule.class,
+})
+@DreamClockDateComplicationComponent.DreamClockDateComplicationScope
+public interface DreamClockDateComplicationComponent {
+    /**
+     * Creates {@link DreamClockDateViewHolder}.
+     */
+    DreamClockDateViewHolder getViewHolder();
+
+    @Documented
+    @Retention(RUNTIME)
+    @Scope
+    @interface DreamClockDateComplicationScope {
+    }
+
+    /**
+     * Generates {@link DreamClockDateComplicationComponent}.
+     */
+    @Subcomponent.Factory
+    interface Factory {
+        DreamClockDateComplicationComponent create();
+    }
+
+    /**
+     * Scoped values for {@link DreamClockDateComplicationComponent}.
+     */
+    @Module
+    interface DreamClockDateComplicationModule {
+        String DREAM_CLOCK_DATE_COMPLICATION_VIEW = "clock_date_complication_view";
+        String DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS =
+                "clock_date_complication_layout_params";
+        // Order weight of insert into parent container
+        int INSERT_ORDER_WEIGHT = 2;
+
+        /**
+         * Provides the complication view.
+         */
+        @Provides
+        @DreamClockDateComplicationScope
+        @Named(DREAM_CLOCK_DATE_COMPLICATION_VIEW)
+        static View provideComplicationView(LayoutInflater layoutInflater) {
+            return Preconditions.checkNotNull(
+                    layoutInflater.inflate(R.layout.dream_overlay_complication_clock_date,
+                            null, false),
+                    "R.layout.dream_overlay_complication_clock_date did not properly inflated");
+        }
+
+        /**
+         * Provides the layout parameters for the complication view.
+         */
+        @Provides
+        @DreamClockDateComplicationScope
+        @Named(DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS)
+        static ComplicationLayoutParams provideLayoutParams() {
+            return new ComplicationLayoutParams(0,
+                    ViewGroup.LayoutParams.WRAP_CONTENT,
+                    ComplicationLayoutParams.POSITION_BOTTOM
+                            | ComplicationLayoutParams.POSITION_START,
+                    ComplicationLayoutParams.DIRECTION_END,
+                    INSERT_ORDER_WEIGHT,
+                    true);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java
new file mode 100644
index 0000000..053c5b3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2022 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.dreams.complication.dagger;
+
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.util.Preconditions;
+import com.android.systemui.R;
+import com.android.systemui.dreams.complication.ComplicationLayoutParams;
+import com.android.systemui.dreams.complication.DreamClockTimeComplication.DreamClockTimeViewHolder;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Named;
+import javax.inject.Scope;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.Subcomponent;
+
+/**
+ * {@link DreamClockTimeComplicationComponent} is responsible for generating dependencies
+ * surrounding the
+ * Clock Time {@link com.android.systemui.dreams.complication.Complication}, such as the layout
+ * details.
+ */
+@Subcomponent(modules = {
+        DreamClockTimeComplicationComponent.DreamClockTimeComplicationModule.class,
+})
+@DreamClockTimeComplicationComponent.DreamClockTimeComplicationScope
+public interface DreamClockTimeComplicationComponent {
+    /**
+     * Creates {@link DreamClockTimeViewHolder}.
+     */
+    DreamClockTimeViewHolder getViewHolder();
+
+    @Documented
+    @Retention(RUNTIME)
+    @Scope
+    @interface DreamClockTimeComplicationScope {
+    }
+
+    /**
+     * Generates {@link DreamClockTimeComplicationComponent}.
+     */
+    @Subcomponent.Factory
+    interface Factory {
+        DreamClockTimeComplicationComponent create();
+    }
+
+    /**
+     * Scoped values for {@link DreamClockTimeComplicationComponent}.
+     */
+    @Module
+    interface DreamClockTimeComplicationModule {
+        String DREAM_CLOCK_TIME_COMPLICATION_VIEW = "clock_time_complication_view";
+        String DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS =
+                "clock_time_complication_layout_params";
+        // Order weight of insert into parent container
+        int INSERT_ORDER_WEIGHT = 0;
+
+        /**
+         * Provides the complication view.
+         */
+        @Provides
+        @DreamClockTimeComplicationScope
+        @Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW)
+        static View provideComplicationView(LayoutInflater layoutInflater) {
+            return Preconditions.checkNotNull(
+                    layoutInflater.inflate(R.layout.dream_overlay_complication_clock_time,
+                            null, false),
+                    "R.layout.dream_overlay_complication_clock_time did not properly inflated");
+        }
+
+        /**
+         * Provides the layout parameters for the complication view.
+         */
+        @Provides
+        @DreamClockTimeComplicationScope
+        @Named(DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS)
+        static ComplicationLayoutParams provideLayoutParams() {
+            return new ComplicationLayoutParams(0,
+                    ViewGroup.LayoutParams.WRAP_CONTENT,
+                    ComplicationLayoutParams.POSITION_BOTTOM
+                            | ComplicationLayoutParams.POSITION_START,
+                    ComplicationLayoutParams.DIRECTION_UP,
+                    INSERT_ORDER_WEIGHT,
+                    true);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java
new file mode 100644
index 0000000..a282594
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2022 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.dreams.complication.dagger;
+
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.internal.util.Preconditions;
+import com.android.systemui.R;
+import com.android.systemui.dreams.complication.ComplicationLayoutParams;
+import com.android.systemui.dreams.complication.DreamWeatherComplication.DreamWeatherViewHolder;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Named;
+import javax.inject.Scope;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.Subcomponent;
+
+/**
+ * {@link DreamWeatherComplicationComponent} is responsible for generating dependencies surrounding
+ * the
+ * Clock Date {@link com.android.systemui.dreams.complication.Complication}, such as the layout
+ * details.
+ */
+@Subcomponent(modules = {
+        DreamWeatherComplicationComponent.DreamWeatherComplicationModule.class,
+})
+@DreamWeatherComplicationComponent.DreamWeatherComplicationScope
+public interface DreamWeatherComplicationComponent {
+    /**
+     * Creates {@link DreamWeatherViewHolder}.
+     */
+    DreamWeatherViewHolder getViewHolder();
+
+    @Documented
+    @Retention(RUNTIME)
+    @Scope
+    @interface DreamWeatherComplicationScope {
+    }
+
+    /**
+     * Generates {@link DreamWeatherComplicationComponent}.
+     */
+    @Subcomponent.Factory
+    interface Factory {
+        DreamWeatherComplicationComponent create();
+    }
+
+    /**
+     * Scoped values for {@link DreamWeatherComplicationComponent}.
+     */
+    @Module
+    interface DreamWeatherComplicationModule {
+        String DREAM_WEATHER_COMPLICATION_VIEW = "weather_complication_view";
+        String DREAM_WEATHER_COMPLICATION_LAYOUT_PARAMS =
+                "weather_complication_layout_params";
+        // Order weight of insert into parent container
+        int INSERT_ORDER_WEIGHT = 1;
+
+        /**
+         * Provides the complication view.
+         */
+        @Provides
+        @DreamWeatherComplicationScope
+        @Named(DREAM_WEATHER_COMPLICATION_VIEW)
+        static TextView provideComplicationView(LayoutInflater layoutInflater) {
+            return Preconditions.checkNotNull((TextView)
+                            layoutInflater.inflate(R.layout.dream_overlay_complication_weather,
+                                    null, false),
+                    "R.layout.dream_overlay_complication_weather did not properly inflated");
+        }
+
+        /**
+         * Provides the layout parameters for the complication view.
+         */
+        @Provides
+        @DreamWeatherComplicationScope
+        @Named(DREAM_WEATHER_COMPLICATION_LAYOUT_PARAMS)
+        static ComplicationLayoutParams provideLayoutParams() {
+            return new ComplicationLayoutParams(0,
+                    ViewGroup.LayoutParams.WRAP_CONTENT,
+                    ComplicationLayoutParams.POSITION_BOTTOM
+                            | ComplicationLayoutParams.POSITION_START,
+                    ComplicationLayoutParams.DIRECTION_END,
+                    INSERT_ORDER_WEIGHT,
+                    true);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
new file mode 100644
index 0000000..8e4fb37
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 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.dreams.complication.dagger;
+
+import com.android.systemui.dagger.SystemUIBinder;
+
+import dagger.Module;
+
+/**
+ * Module for all components with corresponding dream layer complications registered in
+ * {@link SystemUIBinder}.
+ */
+@Module(subcomponents = {
+        DreamClockTimeComplicationComponent.class,
+        DreamClockDateComplicationComponent.class,
+        DreamWeatherComplicationComponent.class,
+})
+public interface RegisteredComplicationsModule {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
index 3d2f924..d8af9e5 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.dreams.dagger;
 
+import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule;
 import com.android.systemui.dreams.touch.dagger.DreamTouchModule;
 
 import dagger.Module;
@@ -25,6 +26,7 @@
  */
 @Module(includes = {
             DreamTouchModule.class,
+            RegisteredComplicationsModule.class,
         },
         subcomponents = {
             DreamOverlayComponent.class,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 97edf3b..c894b70 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -112,6 +112,9 @@
     public static final BooleanFlag COMBINED_STATUS_BAR_SIGNAL_ICONS =
             new BooleanFlag(601, false);
 
+    public static final BooleanFlag STATUS_BAR_USER_SWITCHER =
+            new BooleanFlag(602, false);
+
     /***************************************/
     // 700 - dialer/calls
     public static final BooleanFlag ONGOING_CALL_STATUS_BAR_CHIP =
diff --git a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
index 44727f2..48f4826 100644
--- a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
@@ -159,8 +159,7 @@
     }
 
     fun refreshMediaPosition() {
-        val keyguardOrUserSwitcher = (statusBarStateController.state == StatusBarState.KEYGUARD ||
-                statusBarStateController.state == StatusBarState.FULLSCREEN_USER_SWITCHER)
+        val keyguardOrUserSwitcher = (statusBarStateController.state == StatusBarState.KEYGUARD)
         // mediaHost.visible required for proper animations handling
         visible = mediaHost.visible &&
                 !bypassController.bypassEnabled &&
@@ -196,4 +195,4 @@
             visibilityChangedListener?.invoke(newVisibility == View.VISIBLE)
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 64ebe56..6145f0f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -567,8 +567,7 @@
                 previousLocation = this.desiredLocation
             } else if (forceStateUpdate) {
                 val onLockscreen = (!bypassController.bypassEnabled &&
-                        (statusbarState == StatusBarState.KEYGUARD ||
-                            statusbarState == StatusBarState.FULLSCREEN_USER_SWITCHER))
+                        (statusbarState == StatusBarState.KEYGUARD))
                 if (desiredLocation == LOCATION_QS && previousLocation == LOCATION_LOCKSCREEN &&
                         !onLockscreen) {
                     // If media active state changed and the device is now unlocked, update the
@@ -955,8 +954,7 @@
             return desiredLocation
         }
         val onLockscreen = (!bypassController.bypassEnabled &&
-            (statusbarState == StatusBarState.KEYGUARD ||
-                statusbarState == StatusBarState.FULLSCREEN_USER_SWITCHER))
+            (statusbarState == StatusBarState.KEYGUARD))
         val allowedOnLockscreen = notifLockscreenUserManager.shouldShowLockscreenNotifications()
         val location = when {
             dreamOverlayActive -> LOCATION_DREAM_OVERLAY
@@ -1087,4 +1085,4 @@
 @IntDef(prefix = ["LOCATION_"], value = [MediaHierarchyManager.LOCATION_QS,
     MediaHierarchyManager.LOCATION_QQS, MediaHierarchyManager.LOCATION_LOCKSCREEN])
 @Retention(AnnotationRetention.SOURCE)
-annotation class MediaLocation
\ No newline at end of file
+annotation class MediaLocation
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
index 2bc910e..29938a0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
@@ -26,6 +26,7 @@
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.media.MediaHostStatesManager;
 import com.android.systemui.media.dream.dagger.MediaComplicationComponent;
+import com.android.systemui.media.nearby.NearbyMediaDevicesService;
 import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
 import com.android.systemui.media.taptotransfer.MediaTttFlags;
 import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver;
@@ -142,4 +143,10 @@
     @IntoMap
     @ClassKey(MediaTttSenderService.class)
     Service bindMediaTttSenderService(MediaTttSenderService service);
+
+    /** Inject into NearbyMediaDevicesService. */
+    @Binds
+    @IntoMap
+    @ClassKey(NearbyMediaDevicesService.class)
+    Service bindMediaNearbyDevicesService(NearbyMediaDevicesService service);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/MediaNearbyDevicesManager.kt b/packages/SystemUI/src/com/android/systemui/media/nearby/MediaNearbyDevicesManager.kt
deleted file mode 100644
index 0453fdb..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/nearby/MediaNearbyDevicesManager.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2022 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.media.nearby
-
-import com.android.systemui.dagger.SysUISingleton
-
-/**
- * A manager that returns information about devices that are nearby and can receive media transfers.
- */
-@SysUISingleton
-class MediaNearbyDevicesManager {
-
-    /** Returns a list containing the current nearby devices. */
-    fun getCurrentNearbyDevices(): List<NearbyDevice> {
-        // TODO(b/216313420): Implement this function.
-        return emptyList()
-    }
-
-    /**
-     * Registers [callback] to be notified each time a device's range changes or when a new device
-     * comes within range.
-     */
-    fun registerNearbyDevicesCallback(
-        callback: (device: NearbyDevice) -> Unit
-    ) {
-        // TODO(b/216313420): Implement this function.
-    }
-
-    /**
-     * Un-registers [callback]. See [registerNearbyDevicesCallback].
-     */
-    fun unregisterNearbyDevicesCallback(
-        callback: (device: NearbyDevice) -> Unit
-    ) {
-        // TODO(b/216313420): Implement this function.
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesService.kt b/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesService.kt
new file mode 100644
index 0000000..eaf2bd9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesService.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2022 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.media.nearby
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shared.media.INearbyMediaDevicesProvider
+import com.android.systemui.shared.media.INearbyMediaDevicesService
+import com.android.systemui.shared.media.INearbyMediaDevicesUpdateCallback
+import com.android.systemui.shared.media.NearbyDevice
+import javax.inject.Inject
+
+/**
+ * A service that acts as a bridge between (1) external clients that have data on nearby devices
+ * that are able to play media and (2) internal clients (like media Output Switcher) that need data
+ * on these nearby devices.
+ *
+ * TODO(b/216313420): Add logging to this class.
+ */
+@SysUISingleton
+class NearbyMediaDevicesService @Inject constructor() : Service() {
+
+    private var provider: INearbyMediaDevicesProvider? = null
+
+    private val binder: IBinder = object : INearbyMediaDevicesService.Stub() {
+        override fun registerProvider(newProvider: INearbyMediaDevicesProvider) {
+            provider = newProvider
+            newProvider.asBinder().linkToDeath(
+                {
+                    // We might've gotten a new provider before the old provider died, so we only
+                    // need to clear our provider if the most recent provider died.
+                    if (provider == newProvider) {
+                        provider = null
+                    }
+                },
+                /* flags= */ 0
+            )
+        }
+    }
+
+    override fun onBind(intent: Intent?): IBinder = binder
+
+    /** Returns a list containing the current nearby devices. */
+    fun getCurrentNearbyDevices(): List<NearbyDevice> {
+        val currentProvider = provider ?: return emptyList()
+        return currentProvider.currentNearbyDevices
+    }
+
+    /**
+     * Registers [callback] to be notified each time a device's range changes or when a new device
+     * comes within range.
+     */
+    fun registerNearbyDevicesCallback(callback: INearbyMediaDevicesUpdateCallback) {
+        val currentProvider = provider ?: return
+        currentProvider.registerNearbyDevicesCallback(callback)
+    }
+
+    /**
+     * Un-registers [callback]. See [registerNearbyDevicesCallback].
+     */
+    fun unregisterNearbyDevicesCallback(callback: INearbyMediaDevicesUpdateCallback) {
+        val currentProvider = provider ?: return
+        currentProvider.unregisterNearbyDevicesCallback(callback)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/RangeZone.kt b/packages/SystemUI/src/com/android/systemui/media/nearby/RangeZone.kt
deleted file mode 100644
index 3c890bc..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/nearby/RangeZone.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2022 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.media.nearby
-
-import androidx.annotation.IntDef
-import kotlin.annotation.AnnotationRetention
-
-@IntDef(
-        RangeZone.RANGE_UNKNOWN,
-        RangeZone.RANGE_FAR,
-        RangeZone.RANGE_LONG,
-        RangeZone.RANGE_CLOSE,
-        RangeZone.RANGE_WITHIN_REACH
-)
-@Retention(AnnotationRetention.SOURCE)
-/** The various range zones a device can be in, in relation to the current device. */
-annotation class RangeZone {
-    companion object {
-        /** Unknown distance range. */
-        const val RANGE_UNKNOWN = 0
-        /** Distance is very far away from the peer device. */
-        const val RANGE_FAR = 1
-        /** Distance is relatively long from the peer device, typically a few meters. */
-        const val RANGE_LONG = 2
-        /** Distance is close to the peer device, typically with one or two meter. */
-        const val RANGE_CLOSE = 3
-        /** Distance is very close to the peer device, typically within one meter or less. */
-        const val RANGE_WITHIN_REACH = 4
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
index c0148c0..16bc951e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
@@ -37,12 +37,6 @@
      */
     public static final int SHADE_LOCKED = 2;
 
-    /**
-     * Status bar is locked and shows the full screen user switcher.
-     */
-    public static final int FULLSCREEN_USER_SWITCHER = 3;
-
-
     public static String toShortString(int x) {
         switch (x) {
             case SHADE:
@@ -51,8 +45,6 @@
                 return "SHD_LCK";
             case KEYGUARD:
                 return "KGRD";
-            case FULLSCREEN_USER_SWITCHER:
-                return "FS_USRSW";
             default:
                 return "bad_value_" + x;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index f56602e..ee12cc5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -76,7 +76,7 @@
     // Must be a power of 2
     private static final int HISTORY_SIZE = 32;
 
-    private static final int MAX_STATE = StatusBarState.FULLSCREEN_USER_SWITCHER;
+    private static final int MAX_STATE = StatusBarState.SHADE_LOCKED;
     private static final int MIN_STATE = StatusBarState.SHADE;
 
     private static final Comparator<RankedListener> sComparator =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java
index 8330169..b66a48e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java
@@ -34,10 +34,7 @@
     STATUS_BAR_STATE_KEYGUARD(430),
 
     @UiEvent(doc = "StatusBarState changed to SHADE_LOCKED state")
-    STATUS_BAR_STATE_SHADE_LOCKED(431),
-
-    @UiEvent(doc = "StatusBarState changed to FULLSCREEN_USER_SWITCHER state")
-    STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER(432);
+    STATUS_BAR_STATE_SHADE_LOCKED(431);
 
     private int mId;
     StatusBarStateEvent(int id) {
@@ -60,8 +57,6 @@
                 return STATUS_BAR_STATE_KEYGUARD;
             case StatusBarState.SHADE_LOCKED:
                 return STATUS_BAR_STATE_SHADE_LOCKED;
-            case StatusBarState.FULLSCREEN_USER_SWITCHER:
-                return STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER;
             default:
                 return STATUS_BAR_STATE_UNKNOWN;
         }
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 9f6a81d..dd72615 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
@@ -199,7 +199,7 @@
     private int mMaxTopPadding;
     private int mTopPadding;
     private boolean mAnimateNextTopPaddingChange;
-    private int mBottomMargin;
+    private int mBottomPadding;
     private int mBottomInset = 0;
     private float mQsExpansionFraction;
     private final int mSplitShadeMinContentHeight;
@@ -981,7 +981,7 @@
         mMinTopOverScrollToEscape = res.getDimensionPixelSize(
                 R.dimen.min_top_overscroll_to_qs);
         mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext);
-        mBottomMargin = res.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom);
+        mBottomPadding = res.getDimensionPixelSize(R.dimen.notification_panel_padding_bottom);
         mMinimumPaddings = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
         mQsTilePadding = res.getDimensionPixelOffset(R.dimen.qs_tile_margin_horizontal);
         mSkinnyNotifsInLandscape = res.getBoolean(R.bool.config_skinnyNotifsInLandscape);
@@ -2280,7 +2280,7 @@
 
         // The topPadding can be bigger than the regular padding when qs is expanded, in that
         // state the maxPanelHeight and the contentHeight should be bigger
-        mContentHeight = height + Math.max(mIntrinsicPadding, mTopPadding) + mBottomMargin;
+        mContentHeight = height + Math.max(mIntrinsicPadding, mTopPadding) + mBottomPadding;
         updateScrollability();
         clampScrollPosition();
         updateStackPosition();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 8f0579c..e24cd3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -46,7 +46,7 @@
  */
 public class StackScrollAlgorithm {
 
-    public static final float START_FRACTION = 0.3f;
+    public static final float START_FRACTION = 0.5f;
 
     private static final String LOG_TAG = "StackScrollAlgorithm";
     private final ViewGroup mHostView;
@@ -61,7 +61,7 @@
     @VisibleForTesting float mHeadsUpInset;
     private int mPinnedZTranslationExtra;
     private float mNotificationScrimPadding;
-    private int mCloseHandleUnderlapHeight;
+    private int mMarginBottom;
 
     public StackScrollAlgorithm(
             Context context,
@@ -87,7 +87,7 @@
                 R.dimen.heads_up_pinned_elevation);
         mGapHeight = res.getDimensionPixelSize(R.dimen.notification_section_divider_height);
         mNotificationScrimPadding = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
-        mCloseHandleUnderlapHeight = res.getDimensionPixelSize(R.dimen.close_handle_underlap);
+        mMarginBottom = res.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom);
     }
 
     /**
@@ -463,7 +463,7 @@
             }
         } else {
             if (view instanceof EmptyShadeView) {
-                float fullHeight = ambientState.getLayoutMaxHeight() + mCloseHandleUnderlapHeight
+                float fullHeight = ambientState.getLayoutMaxHeight() + mMarginBottom
                         - ambientState.getStackY();
                 viewState.yTranslation = (fullHeight - getMaxAllowedChildHeight(view)) / 2f;
             } else if (view != ambientState.getTrackedHeadsUpRow()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 04d3e9a..6a78370 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -180,6 +180,7 @@
     private final MetricsLogger mMetricsLogger;
     private final AuthController mAuthController;
     private final StatusBarStateController mStatusBarStateController;
+    private final LatencyTracker mLatencyTracker;
 
     private long mLastFpFailureUptimeMillis;
     private int mNumConsecutiveFpFailures;
@@ -281,7 +282,8 @@
             AuthController authController,
             StatusBarStateController statusBarStateController,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
-            SessionTracker sessionTracker) {
+            SessionTracker sessionTracker,
+            LatencyTracker latencyTracker) {
         mContext = context;
         mPowerManager = powerManager;
         mShadeController = shadeController;
@@ -289,6 +291,7 @@
         mDozeParameters = dozeParameters;
         mUpdateMonitor.registerCallback(this);
         mMediaManager = notificationMediaManager;
+        mLatencyTracker = latencyTracker;
         wakefulnessLifecycle.addObserver(mWakefulnessObserver);
         screenLifecycle.addObserver(mScreenObserver);
 
@@ -343,13 +346,13 @@
     public void onBiometricAcquired(BiometricSourceType biometricSourceType) {
         Trace.beginSection("BiometricUnlockController#onBiometricAcquired");
         releaseBiometricWakeLock();
-        if (!mUpdateMonitor.isDeviceInteractive()) {
-            if (LatencyTracker.isEnabled(mContext)) {
+        if (isWakeAndUnlock()) {
+            if (mLatencyTracker.isEnabled()) {
                 int action = LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK;
                 if (biometricSourceType == BiometricSourceType.FACE) {
                     action = LatencyTracker.ACTION_FACE_WAKE_AND_UNLOCK;
                 }
-                LatencyTracker.getInstance(mContext).onActionStart(action);
+                mLatencyTracker.onActionStart(action);
             }
             mWakeLock = mPowerManager.newWakeLock(
                     PowerManager.PARTIAL_WAKE_LOCK, BIOMETRIC_WAKE_LOCK_NAME);
@@ -652,6 +655,14 @@
         Optional.ofNullable(BiometricUiEvent.FAILURE_EVENT_BY_SOURCE_TYPE.get(biometricSourceType))
                 .ifPresent(event -> UI_EVENT_LOGGER.log(event, getSessionId()));
 
+        if (mLatencyTracker.isEnabled()) {
+            int action = LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK;
+            if (biometricSourceType == BiometricSourceType.FACE) {
+                action = LatencyTracker.ACTION_FACE_WAKE_AND_UNLOCK;
+            }
+            mLatencyTracker.onActionCancel(action);
+        }
+
         if (biometricSourceType == BiometricSourceType.FINGERPRINT
                 && mUpdateMonitor.isUdfpsSupported()) {
             long currUptimeMillis = SystemClock.uptimeMillis();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 00b54e9..2ec5f25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.DejankUtils.whitelistIpcs;
 import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
 import static com.android.systemui.util.Utils.getStatusBarHeaderHeightKeyguard;
 
@@ -27,7 +26,6 @@
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.UserManager;
 import android.util.AttributeSet;
 import android.util.Pair;
 import android.util.TypedValue;
@@ -47,7 +45,6 @@
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.window.StatusBarWindowView;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -72,7 +69,6 @@
     private StatusIconContainer mStatusIconContainer;
 
     private boolean mKeyguardUserSwitcherEnabled;
-    private final UserManager mUserManager;
 
     private boolean mIsPrivacyDotEnabled;
     private int mSystemIconsSwitcherHiddenExpandedMargin;
@@ -99,10 +95,10 @@
      */
     private int mTopClipping;
     private final Rect mClipRect = new Rect(0, 0, 0, 0);
+    private boolean mIsUserSwitcherEnabled;
 
     public KeyguardStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mUserManager = UserManager.get(getContext());
     }
 
     @Override
@@ -163,6 +159,10 @@
         updateKeyguardStatusBarHeight();
     }
 
+    public void setUserSwitcherEnabled(boolean enabled) {
+        mIsUserSwitcherEnabled = enabled;
+    }
+
     private void updateKeyguardStatusBarHeight() {
         MarginLayoutParams lp =  (MarginLayoutParams) getLayoutParams();
         lp.height = getStatusBarHeaderHeightKeyguard(mContext);
@@ -200,11 +200,7 @@
             // If we have no keyguard switcher, the screen width is under 600dp. In this case,
             // we only show the multi-user switch if it's enabled through UserManager as well as
             // by the user.
-            // TODO(b/138661450) Move IPC calls to background
-            boolean isMultiUserEnabled = whitelistIpcs(() -> mUserManager.isUserSwitcherEnabled(
-                    mContext.getResources().getBoolean(
-                            R.bool.qs_show_user_switcher_for_single_user)));
-            if (isMultiUserEnabled) {
+            if (mIsUserSwitcherEnabled) {
                 mMultiUserAvatar.setVisibility(View.VISIBLE);
             } else {
                 mMultiUserAvatar.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 8187163..ee97fd6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -23,8 +23,10 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.hardware.biometrics.BiometricSourceType;
+import android.os.UserManager;
 import android.util.MathUtils;
 import android.view.View;
 
@@ -92,6 +94,7 @@
     private final BiometricUnlockController mBiometricUnlockController;
     private final SysuiStatusBarStateController mStatusBarStateController;
     private final StatusBarContentInsetsProvider mInsetsProvider;
+    private final UserManager mUserManager;
 
     private final ConfigurationController.ConfigurationListener mConfigurationListener =
             new ConfigurationController.ConfigurationListener() {
@@ -105,6 +108,11 @@
                     mView.onOverlayChanged();
                     KeyguardStatusBarViewController.this.onThemeChanged();
                 }
+
+                @Override
+                public void onConfigChanged(Configuration newConfig) {
+                    updateUserSwitcher();
+                }
             };
 
     private final SystemStatusAnimationCallback mAnimationCallback =
@@ -159,6 +167,13 @@
                 }
 
                 @Override
+                public void onKeyguardVisibilityChanged(boolean showing) {
+                    if (showing) {
+                        updateUserSwitcher();
+                    }
+                }
+
+                @Override
                 public void onBiometricRunningStateChanged(
                         boolean running,
                         BiometricSourceType biometricSourceType) {
@@ -230,7 +245,8 @@
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             BiometricUnlockController biometricUnlockController,
             SysuiStatusBarStateController statusBarStateController,
-            StatusBarContentInsetsProvider statusBarContentInsetsProvider
+            StatusBarContentInsetsProvider statusBarContentInsetsProvider,
+            UserManager userManager
     ) {
         super(view);
         mCarrierTextController = carrierTextController;
@@ -248,6 +264,7 @@
         mBiometricUnlockController = biometricUnlockController;
         mStatusBarStateController = statusBarStateController;
         mInsetsProvider = statusBarContentInsetsProvider;
+        mUserManager = userManager;
 
         mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
         mKeyguardStateController.addCallback(
@@ -293,7 +310,7 @@
         }
         mView.setOnApplyWindowInsetsListener(
                 (view, windowInsets) -> mView.updateWindowInsets(windowInsets, mInsetsProvider));
-
+        updateUserSwitcher();
         onThemeChanged();
     }
 
@@ -437,6 +454,14 @@
     }
 
     /**
+     * Updates visibility of the user switcher button based on {@link android.os.UserManager} state.
+     */
+    private void updateUserSwitcher() {
+        mView.setUserSwitcherEnabled(mUserManager.isUserSwitcherEnabled(getResources().getBoolean(
+                R.bool.qs_show_user_switcher_for_single_user)));
+    }
+
+    /**
      * Update {@link KeyguardStatusBarView}'s visibility based on whether keyguard is showing and
      * whether heads up is visible.
      */
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 1870588..3d3a1da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -20,6 +20,7 @@
 import static android.view.View.GONE;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
+import static androidx.constraintlayout.widget.ConstraintSet.BOTTOM;
 import static androidx.constraintlayout.widget.ConstraintSet.END;
 import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
 import static androidx.constraintlayout.widget.ConstraintSet.START;
@@ -414,6 +415,7 @@
     private int mDisplayTopInset = 0; // in pixels
     private int mDisplayRightInset = 0; // in pixels
     private int mSplitShadeStatusBarHeight;
+    private int mSplitShadeNotificationsScrimMarginBottom;
 
     private final KeyguardClockPositionAlgorithm
             mClockPositionAlgorithm =
@@ -1168,6 +1170,9 @@
     public void updateResources() {
         mQuickQsOffsetHeight = SystemBarUtils.getQuickQsOffsetHeight(mView.getContext());
         mSplitShadeStatusBarHeight = Utils.getSplitShadeStatusBarHeight(mView.getContext());
+        mSplitShadeNotificationsScrimMarginBottom =
+                mResources.getDimensionPixelSize(
+                        R.dimen.split_shade_notifications_scrim_margin_bottom);
         int qsWidth = mResources.getDimensionPixelSize(R.dimen.qs_panel_width);
         int panelWidth = mResources.getDimensionPixelSize(R.dimen.notification_panel_width);
         mShouldUseSplitNotificationShade =
@@ -1177,6 +1182,8 @@
             mQs.setInSplitShade(mShouldUseSplitNotificationShade);
         }
 
+        int notificationsBottomMargin = mResources.getDimensionPixelSize(
+                R.dimen.notification_panel_margin_bottom);
         int topMargin = mShouldUseSplitNotificationShade ? mSplitShadeStatusBarHeight :
                 mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_top);
         mSplitShadeHeaderController.setSplitShadeMode(mShouldUseSplitNotificationShade);
@@ -1205,9 +1212,12 @@
         constraintSet.getConstraint(R.id.notification_stack_scroller).layout.mWidth = panelWidth;
         constraintSet.getConstraint(R.id.qs_frame).layout.mWidth = qsWidth;
         constraintSet.setMargin(R.id.notification_stack_scroller, TOP, topMargin);
+        constraintSet.setMargin(R.id.notification_stack_scroller, BOTTOM,
+                notificationsBottomMargin);
         constraintSet.setMargin(R.id.qs_frame, TOP, topMargin);
         constraintSet.applyTo(mNotificationContainerParent);
         mAmbientState.setStackTopMargin(topMargin);
+        mNotificationsQSContainerController.updateMargins();
         mNotificationsQSContainerController.setSplitShadeEnabled(mShouldUseSplitNotificationShade);
 
         updateKeyguardStatusViewAlignment(/* animate= */false);
@@ -2565,7 +2575,8 @@
             right = getView().getRight() + mDisplayRightInset;
         } else {
             top = Math.min(qsPanelBottomY, mSplitShadeStatusBarHeight);
-            bottom = top + mNotificationStackScrollLayoutController.getHeight();
+            bottom = top + mNotificationStackScrollLayoutController.getHeight()
+                    - mSplitShadeNotificationsScrimMarginBottom;
             left = mNotificationStackScrollLayoutController.getLeft();
             right = mNotificationStackScrollLayoutController.getRight();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
index 34bb6d3..1a88533 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
@@ -63,7 +63,7 @@
     }
 
     public override fun onViewAttached() {
-        notificationsBottomMargin = mView.defaultNotificationsMarginBottom
+        updateMargins()
         overviewProxyService.addCallback(taskbarVisibilityListener)
         mView.setInsetsChangedListener(windowInsetsListener)
         mView.setQSFragmentAttachedListener { qs: QS -> qs.setContainerController(this) }
@@ -75,6 +75,10 @@
         mView.removeQSFragmentAttachedListener()
     }
 
+    fun updateMargins() {
+        notificationsBottomMargin = mView.defaultNotificationsMarginBottom
+    }
+
     override fun setCustomizerAnimating(animating: Boolean) {
         if (isQSCustomizerAnimating != animating) {
             isQSCustomizerAnimating = animating
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 9210a8b..cecbcdb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -45,7 +45,6 @@
     private View mStackScroller;
     private View mKeyguardStatusBar;
 
-    private int mStackScrollerMargin;
     private ArrayList<View> mDrawingOrderedChildren = new ArrayList<>();
     private ArrayList<View> mLayoutDrawingOrder = new ArrayList<>();
     private final Comparator<View> mIndexComparator = Comparator.comparingInt(this::indexOfChild);
@@ -63,7 +62,6 @@
         super.onFinishInflate();
         mQsFrame = findViewById(R.id.qs_frame);
         mStackScroller = findViewById(R.id.notification_stack_scroller);
-        mStackScrollerMargin = ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin;
         mKeyguardStatusBar = findViewById(R.id.keyguard_header);
     }
 
@@ -97,7 +95,7 @@
     }
 
     public int getDefaultNotificationsMarginBottom() {
-        return mStackScrollerMargin;
+        return ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin;
     }
 
     public void setInsetsChangedListener(Consumer<WindowInsets> onInsetsChangedListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index 1cb19ab..d6bf5f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -49,29 +49,29 @@
     }
 
     override fun onViewAttached() {
-        moveFromCenterAnimationController?.let { animationController ->
-            val statusBarLeftSide: View = mView.findViewById(R.id.status_bar_left_side)
-            val systemIconArea: ViewGroup = mView.findViewById(R.id.system_icon_area)
+        if (moveFromCenterAnimationController == null) return
 
-            val viewsToAnimate = arrayOf(
-                statusBarLeftSide,
-                systemIconArea
-            )
+        val statusBarLeftSide: View = mView.findViewById(R.id.status_bar_left_side)
+        val systemIconArea: ViewGroup = mView.findViewById(R.id.system_icon_area)
 
-            mView.viewTreeObserver.addOnPreDrawListener(object :
-                ViewTreeObserver.OnPreDrawListener {
-                override fun onPreDraw(): Boolean {
-                    animationController.onViewsReady(viewsToAnimate)
-                    mView.viewTreeObserver.removeOnPreDrawListener(this)
-                    return true
-                }
-            })
+        val viewsToAnimate = arrayOf(
+            statusBarLeftSide,
+            systemIconArea
+        )
 
-            mView.addOnLayoutChangeListener { _, left, _, right, _, oldLeft, _, oldRight, _ ->
-                val widthChanged = right - left != oldRight - oldLeft
-                if (widthChanged) {
-                    moveFromCenterAnimationController.onStatusBarWidthChanged()
-                }
+        mView.viewTreeObserver.addOnPreDrawListener(object :
+            ViewTreeObserver.OnPreDrawListener {
+            override fun onPreDraw(): Boolean {
+                moveFromCenterAnimationController.onViewsReady(viewsToAnimate)
+                mView.viewTreeObserver.removeOnPreDrawListener(this)
+                return true
+            }
+        })
+
+        mView.addOnLayoutChangeListener { _, left, _, right, _, oldLeft, _, oldRight, _ ->
+            val widthChanged = right - left != oldRight - oldLeft
+            if (widthChanged) {
+                moveFromCenterAnimationController.onStatusBarWidthChanged()
             }
         }
 
@@ -162,9 +162,7 @@
             PhoneStatusBarViewController(
                 view,
                 progressProvider.getOrNull(),
-                unfoldComponent.map {
-                    it.getStatusBarMoveFromCenterAnimationController()
-                }.getOrNull(),
+                unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController(),
                 touchEventHandler,
                 configurationController
             )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 2f3300a..c8cc807 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2935,14 +2935,6 @@
         return updateIsKeyguard();
     }
 
-    /**
-     * stop(tag)
-     * @return True if StatusBar state is FULLSCREEN_USER_SWITCHER.
-     */
-    public boolean isFullScreenUserSwitcherState() {
-        return mState == StatusBarState.FULLSCREEN_USER_SWITCHER;
-    }
-
     boolean updateIsKeyguard() {
         return updateIsKeyguard(false /* forceStateChange */);
     }
@@ -2996,9 +2988,7 @@
             onLaunchTransitionFadingEnded();
         }
         mMessageRouter.cancelMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
-        if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) {
-            mStatusBarStateController.setState(StatusBarState.FULLSCREEN_USER_SWITCHER);
-        } else if (!mLockscreenShadeTransitionController.isWakingToShadeLocked()) {
+        if (!mLockscreenShadeTransitionController.isWakingToShadeLocked()) {
             mStatusBarStateController.setState(StatusBarState.KEYGUARD);
         }
         updatePanelExpansionForKeyguard();
@@ -3009,8 +2999,6 @@
         if (mState == StatusBarState.KEYGUARD && mBiometricUnlockController.getMode()
                 != BiometricUnlockController.MODE_WAKE_AND_UNLOCK && !mBouncerShowing) {
             mShadeController.instantExpandNotificationsPanel();
-        } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
-            instantCollapseNotificationPanel();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index b833c89..d42a423 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -49,7 +49,6 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.KeyguardViewController;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.DejankUtils;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dreams.DreamOverlayStateController;
@@ -214,6 +213,7 @@
     private final SysuiStatusBarStateController mStatusBarStateController;
     private final DockManager mDockManager;
     private final KeyguardUpdateMonitor mKeyguardUpdateManager;
+    private final LatencyTracker mLatencyTracker;
     private KeyguardBypassController mBypassController;
     @Nullable private AlternateAuthInterceptor mAlternateAuthInterceptor;
 
@@ -246,7 +246,8 @@
             NotificationMediaManager notificationMediaManager,
             KeyguardBouncer.Factory keyguardBouncerFactory,
             KeyguardMessageAreaController.Factory keyguardMessageAreaFactory,
-            Lazy<ShadeController> shadeController) {
+            Lazy<ShadeController> shadeController,
+            LatencyTracker latencyTracker) {
         mContext = context;
         mViewMediatorCallback = callback;
         mLockPatternUtils = lockPatternUtils;
@@ -262,6 +263,7 @@
         mKeyguardBouncerFactory = keyguardBouncerFactory;
         mKeyguardMessageAreaFactory = keyguardMessageAreaFactory;
         mShadeController = shadeController;
+        mLatencyTracker = latencyTracker;
     }
 
     @Override
@@ -859,15 +861,11 @@
     }
 
     private void wakeAndUnlockDejank() {
-        if (mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK
-                && LatencyTracker.isEnabled(mContext)) {
+        if (mBiometricUnlockController.isWakeAndUnlock() && mLatencyTracker.isEnabled()) {
             BiometricSourceType type = mBiometricUnlockController.getBiometricType();
-            DejankUtils.postAfterTraversal(() -> {
-                    LatencyTracker.getInstance(mContext).onActionEnd(
-                            type == BiometricSourceType.FACE
-                                    ? LatencyTracker.ACTION_FACE_WAKE_AND_UNLOCK
-                                    : LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK);
-            });
+            mLatencyTracker.onActionEnd(type == BiometricSourceType.FACE
+                            ? LatencyTracker.ACTION_FACE_WAKE_AND_UNLOCK
+                            : LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK);
         }
     }
 
@@ -1186,7 +1184,6 @@
         // When a dream overlay is active, scrimming will cause any expansion to immediately expand.
         return (mOccluded && !mDreamOverlayStateController.isOverlayActive())
                 || mBouncer.willDismissWithAction()
-                || mStatusBar.isFullScreenUserSwitcherState()
                 || (mBouncer.isShowing() && mBouncer.isScrimmed())
                 || mBouncer.isFullscreenBouncer();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
index 6d033477..79c0984 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
@@ -18,11 +18,13 @@
 import android.view.View
 import android.view.WindowManager
 import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
+import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator.AlphaProvider
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController.StatusBarViewsCenterProvider
 import com.android.systemui.unfold.SysUIUnfoldScope
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
 import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
 import javax.inject.Inject
+import kotlin.math.max
 
 @SysUIUnfoldScope
 class StatusBarMoveFromCenterAnimationController @Inject constructor(
@@ -31,8 +33,11 @@
 ) {
 
     private val transitionListener = TransitionListener()
-    private val moveFromCenterAnimator = UnfoldMoveFromCenterAnimator(windowManager,
-        viewCenterProvider = StatusBarViewsCenterProvider())
+    private val moveFromCenterAnimator = UnfoldMoveFromCenterAnimator(
+        windowManager,
+        viewCenterProvider = StatusBarViewsCenterProvider(),
+        alphaProvider = StatusBarIconsAlphaProvider()
+    )
 
     fun onViewsReady(viewsToAnimate: Array<View>) {
         moveFromCenterAnimator.updateDisplayProperties()
@@ -65,4 +70,15 @@
             moveFromCenterAnimator.onTransitionProgress(1f)
         }
     }
+
+    private class StatusBarIconsAlphaProvider : AlphaProvider {
+        override fun getAlpha(progress: Float): Float {
+            return max(
+                0f,
+                (progress - ICONS_START_APPEARING_PROGRESS) / (1 - ICONS_START_APPEARING_PROGRESS)
+            )
+        }
+    }
 }
+
+private const val ICONS_START_APPEARING_PROGRESS = 0.75F
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 49e712d..1b73595 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -19,7 +19,6 @@
 import static android.os.UserManager.SWITCHABILITY_STATUS_OK;
 
 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import static com.android.systemui.DejankUtils.whitelistIpcs;
 
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
@@ -427,22 +426,6 @@
         return mSimpleUserSwitcher;
     }
 
-    public boolean useFullscreenUserSwitcher() {
-        // Use adb to override:
-        // adb shell settings put system enable_fullscreen_user_switcher 0  # Turn it off.
-        // adb shell settings put system enable_fullscreen_user_switcher 1  # Turn it on.
-        // Restart SystemUI or adb reboot.
-        final int DEFAULT = -1;
-        final int overrideUseFullscreenUserSwitcher =
-                whitelistIpcs(() -> Settings.System.getInt(mContext.getContentResolver(),
-                        "enable_fullscreen_user_switcher", DEFAULT));
-        if (overrideUseFullscreenUserSwitcher != DEFAULT) {
-            return overrideUseFullscreenUserSwitcher != 0;
-        }
-        // Otherwise default to the build setting.
-        return mContext.getResources().getBoolean(R.bool.config_enableFullscreenUserSwitcher);
-    }
-
     public void setResumeUserOnGuestLogout(boolean resume) {
         mResumeUserOnGuestLogout = resume;
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java
new file mode 100644
index 0000000..b02c506
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 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.dreams.complication;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dreams.DreamOverlayStateController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class DreamClockDateComplicationTest extends SysuiTestCase {
+    @SuppressWarnings("HidingField")
+    @Mock
+    private Context mContext;
+
+    @Mock
+    private DreamOverlayStateController mDreamOverlayStateController;
+
+    @Mock
+    private DreamClockDateComplication mComplication;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    /**
+     * Ensures {@link DreamClockDateComplication} is registered.
+     */
+    @Test
+    public void testComplicationAdded() {
+        final DreamClockDateComplication.Registrant registrant =
+                new DreamClockDateComplication.Registrant(
+                        mContext,
+                        mDreamOverlayStateController,
+                        mComplication);
+        registrant.start();
+        verify(mDreamOverlayStateController).addComplication(eq(mComplication));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
new file mode 100644
index 0000000..088b4d5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 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.dreams.complication;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dreams.DreamOverlayStateController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class DreamClockTimeComplicationTest extends SysuiTestCase {
+    @SuppressWarnings("HidingField")
+    @Mock
+    private Context mContext;
+
+    @Mock
+    private DreamOverlayStateController mDreamOverlayStateController;
+
+    @Mock
+    private DreamClockTimeComplication mComplication;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    /**
+     * Ensures {@link DreamClockTimeComplication} is registered.
+     */
+    @Test
+    public void testComplicationAdded() {
+        final DreamClockTimeComplication.Registrant registrant =
+                new DreamClockTimeComplication.Registrant(
+                        mContext,
+                        mDreamOverlayStateController,
+                        mComplication);
+        registrant.start();
+        verify(mDreamOverlayStateController).addComplication(eq(mComplication));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamWeatherComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamWeatherComplicationTest.java
new file mode 100644
index 0000000..151742a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamWeatherComplicationTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2022 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.dreams.complication;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class DreamWeatherComplicationTest extends SysuiTestCase {
+    @SuppressWarnings("HidingField")
+    @Mock
+    private Context mContext;
+
+    @Mock
+    private LockscreenSmartspaceController mSmartspaceController;
+
+    @Mock
+    private DreamOverlayStateController mDreamOverlayStateController;
+
+    @Mock
+    private DreamWeatherComplication mComplication;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    /**
+     * Ensures {@link DreamWeatherComplication} is only registered when it is available.
+     */
+    @Test
+    public void testComplicationAvailability() {
+        when(mSmartspaceController.isEnabled()).thenReturn(false);
+        final DreamWeatherComplication.Registrant registrant =
+                new DreamWeatherComplication.Registrant(
+                        mContext,
+                        mSmartspaceController,
+                        mDreamOverlayStateController,
+                        mComplication);
+        registrant.start();
+        verify(mDreamOverlayStateController, never()).addComplication(any());
+
+        when(mSmartspaceController.isEnabled()).thenReturn(true);
+        registrant.start();
+        verify(mDreamOverlayStateController).addComplication(eq(mComplication));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
index 43d9a75..dc7026d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
@@ -95,7 +95,6 @@
     fun testVisibleOnKeyguardOrFullScreenUserSwitcher() {
         testStateVisibility(StatusBarState.SHADE, GONE)
         testStateVisibility(StatusBarState.SHADE_LOCKED, GONE)
-        testStateVisibility(StatusBarState.FULLSCREEN_USER_SWITCHER, VISIBLE)
         testStateVisibility(StatusBarState.KEYGUARD, VISIBLE)
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesServiceTest.kt
new file mode 100644
index 0000000..c261086
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesServiceTest.kt
@@ -0,0 +1,124 @@
+package com.android.systemui.media.nearby
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.shared.media.INearbyMediaDevicesProvider
+import com.android.systemui.shared.media.INearbyMediaDevicesService
+import com.android.systemui.shared.media.INearbyMediaDevicesUpdateCallback
+import com.android.systemui.shared.media.INearbyMediaDevicesUpdateCallback.RANGE_LONG
+import com.android.systemui.shared.media.INearbyMediaDevicesUpdateCallback.RANGE_WITHIN_REACH
+import com.android.systemui.shared.media.NearbyDevice
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+class NearbyMediaDevicesServiceTest : SysuiTestCase() {
+
+    private lateinit var service: NearbyMediaDevicesService
+    private lateinit var binderInterface: INearbyMediaDevicesService
+
+    @Before
+    fun setUp() {
+        service = NearbyMediaDevicesService()
+        binderInterface = INearbyMediaDevicesService.Stub.asInterface(service.onBind(null))
+    }
+
+    @Test
+    fun getCurrentNearbyDevices_noProviderRegistered_returnsEmptyList() {
+        assertThat(service.getCurrentNearbyDevices()).isEmpty()
+    }
+
+    @Test
+    fun getCurrentNearbyDevices_providerRegistered_returnsProviderInfo() {
+        val nearbyDevice1 = NearbyDevice("routeId1", RANGE_LONG)
+        val nearbyDevice2 = NearbyDevice("routeId2", RANGE_WITHIN_REACH)
+        val provider = object : INearbyMediaDevicesProvider.Stub() {
+            override fun getCurrentNearbyDevices(): List<NearbyDevice> {
+                return listOf(nearbyDevice1, nearbyDevice2)
+            }
+
+            override fun registerNearbyDevicesCallback(
+                callback: INearbyMediaDevicesUpdateCallback?
+            ) {}
+            override fun unregisterNearbyDevicesCallback(
+                callback: INearbyMediaDevicesUpdateCallback?
+            ) {}
+        }
+        binderInterface.registerProvider(provider)
+
+        val returnedNearbyDevices = service.getCurrentNearbyDevices()
+
+        assertThat(returnedNearbyDevices).isEqualTo(listOf(nearbyDevice1, nearbyDevice2))
+    }
+
+    @Test
+    fun registerNearbyDevicesCallback_noProviderRegistered_noCrash() {
+        // No assert, just needs no crash
+        service.registerNearbyDevicesCallback(object : INearbyMediaDevicesUpdateCallback.Stub() {
+            override fun nearbyDeviceUpdate(routeId: String?, rangeZone: Int) {}
+        })
+    }
+
+    @Test
+    fun registerNearbyDevicesCallback_providerRegistered_providerReceivesCallback() {
+        val provider = object : INearbyMediaDevicesProvider.Stub() {
+            var registeredCallback: INearbyMediaDevicesUpdateCallback? = null
+            override fun getCurrentNearbyDevices(): List<NearbyDevice> = listOf()
+
+            override fun registerNearbyDevicesCallback(
+                callback: INearbyMediaDevicesUpdateCallback?
+            ) {
+                registeredCallback = callback
+            }
+
+            override fun unregisterNearbyDevicesCallback(
+                callback: INearbyMediaDevicesUpdateCallback?
+            ) {}
+        }
+        binderInterface.registerProvider(provider)
+
+        val callback = object : INearbyMediaDevicesUpdateCallback.Stub() {
+            override fun nearbyDeviceUpdate(routeId: String?, rangeZone: Int) {}
+        }
+
+        service.registerNearbyDevicesCallback(callback)
+
+        assertThat(provider.registeredCallback).isEqualTo(callback)
+    }
+
+    @Test
+    fun unregisterNearbyDevicesCallback_noProviderRegistered_noCrash() {
+        // No assert, just needs no crash
+        service.unregisterNearbyDevicesCallback(object : INearbyMediaDevicesUpdateCallback.Stub() {
+            override fun nearbyDeviceUpdate(routeId: String?, rangeZone: Int) {}
+        })
+    }
+
+    @Test
+    fun unregisterNearbyDevicesCallback_providerRegistered_providerReceivesCallback() {
+        val provider = object : INearbyMediaDevicesProvider.Stub() {
+            var unregisteredCallback: INearbyMediaDevicesUpdateCallback? = null
+            override fun getCurrentNearbyDevices(): List<NearbyDevice> = listOf()
+
+            override fun registerNearbyDevicesCallback(
+                callback: INearbyMediaDevicesUpdateCallback?
+            ) {}
+
+            override fun unregisterNearbyDevicesCallback(
+                callback: INearbyMediaDevicesUpdateCallback?
+            ) {
+                unregisteredCallback = callback
+            }
+        }
+        binderInterface.registerProvider(provider)
+
+        val callback = object : INearbyMediaDevicesUpdateCallback.Stub() {
+            override fun nearbyDeviceUpdate(routeId: String?, rangeZone: Int) {}
+        }
+
+        service.unregisterNearbyDevicesCallback(callback)
+
+        assertThat(provider.unregisteredCallback).isEqualTo(callback)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index d51d370..9076e16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -169,8 +169,6 @@
         transitionController.goToLockedShade(null)
         whenever(statusbarStateController.state).thenReturn(StatusBarState.SHADE)
         transitionController.goToLockedShade(null)
-        whenever(statusbarStateController.state).thenReturn(StatusBarState.FULLSCREEN_USER_SWITCHER)
-        transitionController.goToLockedShade(null)
         verify(statusbarStateController, never()).setState(anyInt())
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index b736f38..a5ea897 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -61,18 +61,16 @@
     @Test
     fun testChangeState_logged() {
         TestableLooper.get(this).runWithLooper {
-            controller.state = StatusBarState.FULLSCREEN_USER_SWITCHER
             controller.state = StatusBarState.KEYGUARD
             controller.state = StatusBarState.SHADE
             controller.state = StatusBarState.SHADE_LOCKED
         }
 
         val logs = uiEventLogger.logs
-        assertEquals(4, logs.size)
+        assertEquals(3, logs.size)
         val ids = logs.map(UiEventLoggerFake.FakeUiEvent::eventId)
-        assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER.id, ids[0])
-        assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_KEYGUARD.id, ids[1])
-        assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE.id, ids[2])
-        assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE_LOCKED.id, ids[3])
+        assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_KEYGUARD.id, ids[0])
+        assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE.id, ids[1])
+        assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE_LOCKED.id, ids[2])
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
index b5b2f1f..79a2008 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
@@ -33,18 +33,16 @@
                 StatusBarStateEvent.STATUS_BAR_STATE_SHADE,
                 StatusBarStateEvent.STATUS_BAR_STATE_SHADE_LOCKED,
                 StatusBarStateEvent.STATUS_BAR_STATE_KEYGUARD,
-                StatusBarStateEvent.STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER,
                 StatusBarStateEvent.STATUS_BAR_STATE_UNKNOWN
         )
         val states = listOf(
                 StatusBarState.SHADE,
                 StatusBarState.SHADE_LOCKED,
                 StatusBarState.KEYGUARD,
-                StatusBarState.FULLSCREEN_USER_SWITCHER,
                 -1
         )
         events.zip(states).forEach { (event, state) ->
             assertEquals(event, StatusBarStateEvent.fromState(state))
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index ea68143..1da9bbc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -69,10 +69,9 @@
 
         stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
 
-        val closeHandleUnderlapHeight =
-            context.resources.getDimensionPixelSize(R.dimen.close_handle_underlap)
-        val fullHeight =
-            ambientState.layoutMaxHeight + closeHandleUnderlapHeight - ambientState.stackY
+        val marginBottom =
+            context.resources.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom)
+        val fullHeight = ambientState.layoutMaxHeight + marginBottom - ambientState.stackY
         val centeredY = ambientState.stackY + fullHeight / 2f - emptyShadeView.height / 2f
         assertThat(emptyShadeView.viewState?.yTranslation).isEqualTo(centeredY)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 8c7d22d..fb232ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -38,6 +38,7 @@
 import android.testing.TestableResources;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.util.LatencyTracker;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.AuthController;
@@ -110,6 +111,8 @@
     private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     @Mock
     private SessionTracker mSessionTracker;
+    @Mock
+    private LatencyTracker mLatencyTracker;
     private BiometricUnlockController mBiometricUnlockController;
 
     @Before
@@ -133,7 +136,7 @@
                 mMetricsLogger, mDumpManager, mPowerManager,
                 mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle,
                 mAuthController, mStatusBarStateController, mKeyguardUnlockAnimationController,
-                mSessionTracker);
+                mSessionTracker, mLatencyTracker);
         mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
         mBiometricUnlockController.setBiometricModeListener(mBiometricModeListener);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 36a4c1e..01e9822e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -23,9 +23,13 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.os.UserManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.LayoutInflater;
@@ -45,6 +49,7 @@
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserInfoController;
 
@@ -52,6 +57,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -87,6 +93,12 @@
     private SysuiStatusBarStateController mStatusBarStateController;
     @Mock
     private StatusBarContentInsetsProvider mStatusBarContentInsetsProvider;
+    @Mock
+    private UserManager mUserManager;
+    @Captor
+    private ArgumentCaptor<ConfigurationListener> mConfigurationListenerCaptor;
+    @Captor
+    private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardCallbackCaptor;
 
     private TestNotificationPanelViewStateProvider mNotificationPanelViewStateProvider;
     private KeyguardStatusBarView mKeyguardStatusBarView;
@@ -101,8 +113,8 @@
         allowTestableLooperAsMainThread();
         TestableLooper.get(this).runWithLooper(() -> {
             mKeyguardStatusBarView =
-                    (KeyguardStatusBarView) LayoutInflater.from(mContext)
-                            .inflate(R.layout.keyguard_status_bar, null);
+                    spy((KeyguardStatusBarView) LayoutInflater.from(mContext)
+                            .inflate(R.layout.keyguard_status_bar, null));
         });
 
         mController = new KeyguardStatusBarViewController(
@@ -121,7 +133,8 @@
                 mKeyguardUpdateMonitor,
                 mBiometricUnlockController,
                 mStatusBarStateController,
-                mStatusBarContentInsetsProvider
+                mStatusBarContentInsetsProvider,
+                mUserManager
         );
     }
 
@@ -133,6 +146,31 @@
         verify(mAnimationScheduler).addCallback(any());
         verify(mUserInfoController).addCallback(any());
         verify(mStatusBarIconController).addIconGroup(any());
+        verify(mUserManager).isUserSwitcherEnabled(anyBoolean());
+    }
+
+    @Test
+    public void onConfigurationChanged_updatesUserSwitcherVisibility() {
+        mController.onViewAttached();
+        verify(mConfigurationController).addCallback(mConfigurationListenerCaptor.capture());
+        clearInvocations(mUserManager);
+        clearInvocations(mKeyguardStatusBarView);
+
+        mConfigurationListenerCaptor.getValue().onConfigChanged(null);
+        verify(mUserManager).isUserSwitcherEnabled(anyBoolean());
+        verify(mKeyguardStatusBarView).setUserSwitcherEnabled(anyBoolean());
+    }
+
+    @Test
+    public void onKeyguardVisibilityChanged_updatesUserSwitcherVisibility() {
+        mController.onViewAttached();
+        verify(mKeyguardUpdateMonitor).registerCallback(mKeyguardCallbackCaptor.capture());
+        clearInvocations(mUserManager);
+        clearInvocations(mKeyguardStatusBarView);
+
+        mKeyguardCallbackCaptor.getValue().onKeyguardVisibilityChanged(true);
+        verify(mUserManager).isUserSwitcherEnabled(anyBoolean());
+        verify(mKeyguardStatusBarView).setUserSwitcherEnabled(anyBoolean());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
index 337e64592..77e9025 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
@@ -215,6 +215,18 @@
         then(expectedContainerPadding = 0)
     }
 
+    @Test
+    fun testNotificationsMarginBottomIsUpdated() {
+        notificationsQSContainerController.splitShadeEnabled = true
+        verify(notificationsQSContainer).setNotificationsMarginBottom(NOTIFICATIONS_MARGIN)
+
+        whenever(notificationsQSContainer.defaultNotificationsMarginBottom).thenReturn(100)
+        notificationsQSContainerController.updateMargins()
+        notificationsQSContainerController.splitShadeEnabled = false
+
+        verify(notificationsQSContainer).setNotificationsMarginBottom(100)
+    }
+
     private fun given(
         taskbarVisible: Boolean,
         navigationMode: Int,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index bb79941..107ba81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -36,6 +36,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.util.LatencyTracker;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardMessageArea;
 import com.android.keyguard.KeyguardMessageAreaController;
@@ -100,6 +101,8 @@
     private ShadeController mShadeController;
     @Mock
     private DreamOverlayStateController mDreamOverlayStateController;
+    @Mock
+    private LatencyTracker mLatencyTracker;
 
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
@@ -127,7 +130,8 @@
                 mock(NotificationMediaManager.class),
                 mKeyguardBouncerFactory,
                 mKeyguardMessageAreaFactory,
-                () -> mShadeController);
+                () -> mShadeController,
+                mLatencyTracker);
         mStatusBarKeyguardViewManager.registerStatusBar(
                 mStatusBar,
                 mNotificationPanelView,
@@ -171,17 +175,6 @@
     }
 
     @Test
-    public void onPanelExpansionChanged_neverHidesFullscreenBouncer() {
-        // TODO: StatusBar should not be here, mBouncer.isFullscreenBouncer() should do the same.
-        when(mStatusBar.isFullScreenUserSwitcherState()).thenReturn(true);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(
-                /* fraction= */ 0.5f,
-                /* expanded= */ false,
-                /* tracking= */ true);
-        verify(mBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_VISIBLE));
-    }
-
-    @Test
     public void onPanelExpansionChanged_neverHidesScrimmedBouncer() {
         when(mBouncer.isShowing()).thenReturn(true);
         when(mBouncer.isScrimmed()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 1564dfe..90b93e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -885,15 +885,6 @@
     }
 
     @Test
-    public void testSetState_changesIsFullScreenUserSwitcherState() {
-        mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
-        assertFalse(mStatusBar.isFullScreenUserSwitcherState());
-
-        mStatusBar.setBarStateForTest(StatusBarState.FULLSCREEN_USER_SWITCHER);
-        assertTrue(mStatusBar.isFullScreenUserSwitcherState());
-    }
-
-    @Test
     public void testShowKeyguardImplementation_setsState() {
         when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>());
 
@@ -903,12 +894,6 @@
         mStatusBar.showKeyguardImpl();
         verify(mStatusBarStateController).setState(
                 eq(StatusBarState.KEYGUARD), eq(false) /* force */);
-
-        // If useFullscreenUserSwitcher is true, state is set to FULLSCREEN_USER_SWITCHER.
-        when(mUserSwitcherController.useFullscreenUserSwitcher()).thenReturn(true);
-        mStatusBar.showKeyguardImpl();
-        verify(mStatusBarStateController).setState(
-                eq(StatusBarState.FULLSCREEN_USER_SWITCHER), eq(false) /* force */);
     }
 
     @Test
diff --git a/services/Android.bp b/services/Android.bp
index af70692..b0a5c66 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -102,6 +102,7 @@
         ":services.usage-sources",
         ":services.usb-sources",
         ":services.voiceinteraction-sources",
+        ":services.wallpapereffectsgeneration-sources",
         ":services.wifi-sources",
     ],
     visibility: ["//visibility:private"],
@@ -158,6 +159,7 @@
         "services.usage",
         "services.usb",
         "services.voiceinteraction",
+        "services.wallpapereffectsgeneration",
         "services.wifi",
         "service-blobstore",
         "service-jobscheduler",
diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
index 6744ea8..803177b 100644
--- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
@@ -295,6 +295,21 @@
                 case AccessibilityService.GLOBAL_ACTION_KEYCODE_HEADSETHOOK :
                     sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK);
                     return true;
+                case AccessibilityService.GLOBAL_ACTION_DPAD_UP:
+                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_UP);
+                    return true;
+                case AccessibilityService.GLOBAL_ACTION_DPAD_DOWN:
+                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_DOWN);
+                    return true;
+                case AccessibilityService.GLOBAL_ACTION_DPAD_LEFT:
+                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_LEFT);
+                    return true;
+                case AccessibilityService.GLOBAL_ACTION_DPAD_RIGHT:
+                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_RIGHT);
+                    return true;
+                case AccessibilityService.GLOBAL_ACTION_DPAD_CENTER:
+                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER);
+                    return true;
                 default:
                     Slog.e(TAG, "Invalid action id: " + actionId);
                     return false;
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 1106fe7..561009f 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -134,6 +134,7 @@
         "app-compat-annotations",
         "framework-tethering.stubs.module_lib",
         "service-permission.stubs.system_server",
+        "service-supplementalprocess.stubs.system_server",
     ],
 
     required: [
diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
index 435d294..a35aa7c 100644
--- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager.ProcessState;
 import android.app.usage.UsageStatsManager.StandbyBuckets;
 import android.content.ComponentName;
 import android.content.LocusId;
@@ -375,10 +376,11 @@
      *                           to this broadcast.
      * @param timestampMs time (in millis) when the broadcast was dispatched, in
      *                    {@link SystemClock#elapsedRealtime()} timebase.
+     * @param targetUidProcState process state of the uid that the broadcast is targeted to.
      */
     public abstract void reportBroadcastDispatched(int sourceUid, @NonNull String targetPackage,
             @NonNull UserHandle targetUser, long idForResponseEvent,
-            @ElapsedRealtimeLong long timestampMs);
+            @ElapsedRealtimeLong long timestampMs, @ProcessState int targetUidProcState);
 
     /**
      * Reports a notification posted event to the UsageStatsManager.
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 0bc3fcc..ce30f03 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -576,19 +576,20 @@
         return () -> {
             final TimingsTraceAndSlog t = new TimingsTraceAndSlog(oldTrace);
             final String serviceName = service.getClass().getName();
+            final int curUserId = curUser.getUserIdentifier();
+            t.traceBegin("ssm.on" + USER_STARTING + "User-" + curUserId + "_" + serviceName);
             try {
-                final int curUserId = curUser.getUserIdentifier();
-                t.traceBegin("ssm.on" + USER_STARTING + "User-" + curUserId + "_" + serviceName);
                 long time = SystemClock.elapsedRealtime();
                 service.onUserStarting(curUser);
                 warnIfTooLong(SystemClock.elapsedRealtime() - time, service,
                         "on" + USER_STARTING + "User-" + curUserId);
-                t.traceEnd();
             } catch (Exception e) {
                 Slog.wtf(TAG, "Failure reporting " + USER_STARTING + " of user " + curUser
                         + " to service " + serviceName, e);
                 Slog.e(TAG, "Disabling thread pool - please capture a bug report.");
                 sUseLifecycleThreadPool = false;
+            } finally {
+                t.traceEnd();
             }
         };
     }
@@ -601,11 +602,18 @@
             final int curUserId = curUser.getUserIdentifier();
             t.traceBegin("ssm.on" + USER_COMPLETED_EVENT + "User-" + curUserId
                     + "_" + eventType + "_" + serviceName);
-            long time = SystemClock.elapsedRealtime();
-            service.onUserCompletedEvent(curUser, eventType);
-            warnIfTooLong(SystemClock.elapsedRealtime() - time, service,
-                    "on" + USER_COMPLETED_EVENT + "User-" + curUserId);
-            t.traceEnd();
+            try {
+                long time = SystemClock.elapsedRealtime();
+                service.onUserCompletedEvent(curUser, eventType);
+                warnIfTooLong(SystemClock.elapsedRealtime() - time, service,
+                        "on" + USER_COMPLETED_EVENT + "User-" + curUserId);
+            } catch (Exception e) {
+                Slog.wtf(TAG, "Failure reporting " + USER_COMPLETED_EVENT + " of user " + curUser
+                        + " to service " + serviceName, e);
+                throw e;
+            } finally {
+                t.traceEnd();
+            }
         };
     }
 
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 0c383eb..e2921e9 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -334,7 +334,7 @@
         mService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
 
         // Tell the application to launch this receiver.
-        maybeReportBroadcastDispatchedEventLocked(r);
+        maybeReportBroadcastDispatchedEventLocked(r, r.curReceiver.applicationInfo.uid);
         r.intent.setComponent(r.curComponent);
 
         boolean started = false;
@@ -927,7 +927,7 @@
                 r.receiverTime = SystemClock.uptimeMillis();
                 maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
                 maybeScheduleTempAllowlistLocked(filter.owningUid, r, r.options);
-                maybeReportBroadcastDispatchedEventLocked(r);
+                maybeReportBroadcastDispatchedEventLocked(r, filter.owningUid);
                 performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                         new Intent(r.intent), r.resultCode, r.resultData,
                         r.resultExtras, r.ordered, r.initialSticky, r.userId);
@@ -1856,7 +1856,7 @@
         return null;
     }
 
-    private void maybeReportBroadcastDispatchedEventLocked(BroadcastRecord r) {
+    private void maybeReportBroadcastDispatchedEventLocked(BroadcastRecord r, int targetUid) {
         final String targetPackage = getTargetPackage(r);
         // Ignore non-explicit broadcasts
         if (targetPackage == null) {
@@ -1867,11 +1867,10 @@
         if (r.options == null || r.options.getIdForResponseEvent() <= 0) {
             return;
         }
-        // TODO (206518114): Only report this event when the broadcast is dispatched while the app
-        // is in the background state.
         getUsageStatsManagerInternal().reportBroadcastDispatched(
                 r.callingUid, targetPackage, UserHandle.of(r.userId),
-                r.options.getIdForResponseEvent(), SystemClock.elapsedRealtime());
+                r.options.getIdForResponseEvent(), SystemClock.elapsedRealtime(),
+                mService.getUidStateLocked(targetUid));
     }
 
     @NonNull
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 3c9d29d..551773e 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -20,6 +20,11 @@
 import static android.content.Intent.ACTION_PACKAGE_CHANGED;
 import static android.content.Intent.ACTION_PACKAGE_REMOVED;
 
+import static com.android.internal.R.styleable.GameModeConfig_allowGameAngleDriver;
+import static com.android.internal.R.styleable.GameModeConfig_allowGameDownscaling;
+import static com.android.internal.R.styleable.GameModeConfig_allowGameFpsOverride;
+import static com.android.internal.R.styleable.GameModeConfig_supportsBatteryGameMode;
+import static com.android.internal.R.styleable.GameModeConfig_supportsPerformanceGameMode;
 import static com.android.server.wm.CompatModePackages.DOWNSCALED;
 import static com.android.server.wm.CompatModePackages.DOWNSCALE_30;
 import static com.android.server.wm.CompatModePackages.DOWNSCALE_35;
@@ -54,6 +59,10 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
 import android.hardware.power.Mode;
 import android.net.Uri;
 import android.os.Binder;
@@ -71,8 +80,10 @@
 import android.provider.DeviceConfig;
 import android.provider.DeviceConfig.Properties;
 import android.util.ArrayMap;
+import android.util.AttributeSet;
 import android.util.KeyValueListParser;
 import android.util.Slog;
+import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -84,7 +95,11 @@
 import com.android.server.SystemService;
 import com.android.server.SystemService.TargetUser;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.List;
 
@@ -425,12 +440,20 @@
         public static final String METADATA_BATTERY_MODE_ENABLE =
                 "com.android.app.gamemode.battery.enabled";
 
+        /**
+         * Metadata that allows a game to specify all intervention information with an XML file in
+         * the application field.
+         */
+        public static final String METADATA_GAME_MODE_CONFIG = "android.game_mode_config";
+
+        private static final String GAME_MODE_CONFIG_NODE_NAME = "game-mode-config";
         private final String mPackageName;
         private final ArrayMap<Integer, GameModeConfiguration> mModeConfigs;
         private boolean mPerfModeOptedIn;
         private boolean mBatteryModeOptedIn;
         private boolean mAllowDownscale;
         private boolean mAllowAngle;
+        private boolean mAllowFpsOverride;
 
         GamePackageConfiguration(String packageName, int userId) {
             mPackageName = packageName;
@@ -438,18 +461,21 @@
             try {
                 final ApplicationInfo ai = mPackageManager.getApplicationInfoAsUser(packageName,
                         PackageManager.GET_META_DATA, userId);
-                if (ai.metaData != null) {
-                    mPerfModeOptedIn = ai.metaData.getBoolean(METADATA_PERFORMANCE_MODE_ENABLE);
-                    mBatteryModeOptedIn = ai.metaData.getBoolean(METADATA_BATTERY_MODE_ENABLE);
-                    mAllowDownscale = ai.metaData.getBoolean(METADATA_WM_ALLOW_DOWNSCALE, true);
-                    mAllowAngle = ai.metaData.getBoolean(METADATA_ANGLE_ALLOW_ANGLE, true);
-                } else {
-                    mPerfModeOptedIn = false;
-                    mBatteryModeOptedIn = false;
-                    mAllowDownscale = true;
-                    mAllowAngle = true;
+                if (!parseInterventionFromXml(ai, packageName)) {
+                    if (ai.metaData != null) {
+                        mPerfModeOptedIn = ai.metaData.getBoolean(METADATA_PERFORMANCE_MODE_ENABLE);
+                        mBatteryModeOptedIn = ai.metaData.getBoolean(METADATA_BATTERY_MODE_ENABLE);
+                        mAllowDownscale = ai.metaData.getBoolean(METADATA_WM_ALLOW_DOWNSCALE, true);
+                        mAllowAngle = ai.metaData.getBoolean(METADATA_ANGLE_ALLOW_ANGLE, true);
+                    } else {
+                        mPerfModeOptedIn = false;
+                        mBatteryModeOptedIn = false;
+                        mAllowDownscale = true;
+                        mAllowAngle = true;
+                        mAllowFpsOverride = true;
+                    }
                 }
-            } catch (PackageManager.NameNotFoundException e) {
+            } catch (NameNotFoundException e) {
                 // Not all packages are installed, hence ignore those that are not installed yet.
                 Slog.v(TAG, "Failed to get package metadata");
             }
@@ -469,6 +495,53 @@
             }
         }
 
+        private boolean parseInterventionFromXml(ApplicationInfo ai, String packageName) {
+            boolean xmlFound = false;
+            try (XmlResourceParser parser = ai.loadXmlMetaData(mPackageManager,
+                    METADATA_GAME_MODE_CONFIG)) {
+                if (parser == null) {
+                    Slog.v(TAG, "No " + METADATA_GAME_MODE_CONFIG
+                            + " meta-data found for package " + mPackageName);
+                } else {
+                    xmlFound = true;
+                    final Resources resources = mPackageManager.getResourcesForApplication(
+                            packageName);
+                    final AttributeSet attributeSet = Xml.asAttributeSet(parser);
+                    int type;
+                    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                            && type != XmlPullParser.START_TAG) {
+                        // Do nothing
+                    }
+
+                    boolean isStartingTagGameModeConfig =
+                            GAME_MODE_CONFIG_NODE_NAME.equals(parser.getName());
+                    if (!isStartingTagGameModeConfig) {
+                        Slog.w(TAG, "Meta-data does not start with "
+                                + GAME_MODE_CONFIG_NODE_NAME
+                                + " tag");
+                    } else {
+                        final TypedArray array = resources.obtainAttributes(attributeSet,
+                                com.android.internal.R.styleable.GameModeConfig);
+                        mPerfModeOptedIn = array.getBoolean(
+                                GameModeConfig_supportsPerformanceGameMode, false);
+                        mBatteryModeOptedIn = array.getBoolean(
+                                GameModeConfig_supportsBatteryGameMode,
+                                false);
+                        mAllowDownscale = array.getBoolean(GameModeConfig_allowGameDownscaling,
+                                true);
+                        mAllowAngle = array.getBoolean(GameModeConfig_allowGameAngleDriver, true);
+                        mAllowFpsOverride = array.getBoolean(GameModeConfig_allowGameFpsOverride,
+                                true);
+                        array.recycle();
+                    }
+                }
+            } catch (NameNotFoundException | XmlPullParserException | IOException ex) {
+                Slog.e(TAG, "Error while parsing XML meta-data for "
+                        + METADATA_GAME_MODE_CONFIG);
+            }
+            return xmlFound;
+        }
+
         /**
          * GameModeConfiguration contains all the values for all the interventions associated with
          * a game mode.
@@ -497,7 +570,8 @@
                 mScaling = !mAllowDownscale || willGamePerformOptimizations(mGameMode)
                         ? DEFAULT_SCALING : parser.getString(SCALING_KEY, DEFAULT_SCALING);
 
-                mFps = parser.getString(FPS_KEY, DEFAULT_FPS);
+                mFps = mAllowFpsOverride && !willGamePerformOptimizations(mGameMode)
+                        ? parser.getString(FPS_KEY, DEFAULT_FPS) : DEFAULT_FPS;
                 // We only want to use ANGLE if:
                 // - We're allowed to use ANGLE (the app hasn't opted out via the manifest) AND
                 // - The app has not opted in to performing the work itself AND
@@ -691,7 +765,7 @@
         try {
             return mPackageManager.getPackageUidAsUser(packageName, userId)
                     == Binder.getCallingUid();
-        } catch (PackageManager.NameNotFoundException e) {
+        } catch (NameNotFoundException e) {
             return false;
         }
     }
@@ -855,7 +929,7 @@
      */
     @Override
     @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
-    public @GameMode boolean getAngleEnabled(String packageName, int userId)
+    public @GameMode boolean isAngleEnabled(String packageName, int userId)
             throws SecurityException {
         final int gameMode = getGameMode(packageName, userId);
         if (gameMode == GameManager.GAME_MODE_UNSUPPORTED) {
@@ -1413,7 +1487,7 @@
                         if (applicationInfo.category != ApplicationInfo.CATEGORY_GAME) {
                             return;
                         }
-                    } catch (PackageManager.NameNotFoundException e) {
+                    } catch (NameNotFoundException e) {
                         // Ignore the exception.
                     }
                     switch (intent.getAction()) {
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index af1dd33..960fbf1 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -50,6 +50,7 @@
 import com.android.internal.infra.AndroidFuture;
 import com.android.internal.infra.ServiceConnector;
 import com.android.server.wm.WindowManagerInternal;
+import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
 import com.android.server.wm.WindowManagerService;
 
 import java.util.List;
@@ -62,6 +63,18 @@
     private static final int CREATE_GAME_SESSION_TIMEOUT_MS = 10_000;
     private static final boolean DEBUG = false;
 
+    private final TaskSystemBarsListener mTaskSystemBarsVisibilityListener =
+            new TaskSystemBarsListener() {
+                @Override
+                public void onTransientSystemBarsVisibilityChanged(
+                        int taskId,
+                        boolean visible,
+                        boolean wereRevealedFromSwipeOnSystemBar) {
+                    GameServiceProviderInstanceImpl.this.onTransientSystemBarsVisibilityChanged(
+                            taskId, visible, wereRevealedFromSwipeOnSystemBar);
+                }
+            };
+
     private final TaskStackListener mTaskStackListener = new TaskStackListener() {
         @Override
         public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
@@ -203,6 +216,8 @@
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed to register task stack listener", e);
         }
+
+        mWindowManagerInternal.registerTaskSystemBarsListener(mTaskSystemBarsVisibilityListener);
     }
 
     @GuardedBy("mLock")
@@ -218,6 +233,9 @@
             Slog.w(TAG, "Failed to unregister task stack listener", e);
         }
 
+        mWindowManagerInternal.unregisterTaskSystemBarsListener(
+                mTaskSystemBarsVisibilityListener);
+
         for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
             destroyGameSessionFromRecord(gameSessionRecord);
         }
@@ -307,6 +325,37 @@
         }
     }
 
+    private void onTransientSystemBarsVisibilityChanged(
+            int taskId,
+            boolean visible,
+            boolean wereRevealedFromSwipeOnSystemBar) {
+        if (visible && !wereRevealedFromSwipeOnSystemBar) {
+            return;
+        }
+
+        GameSessionRecord gameSessionRecord;
+        synchronized (mLock) {
+            gameSessionRecord = mGameSessions.get(taskId);
+        }
+
+        if (gameSessionRecord == null) {
+            return;
+        }
+
+        IGameSession gameSession = gameSessionRecord.getGameSession();
+        if (gameSession == null) {
+            return;
+        }
+
+        try {
+            gameSession.onTransientSystemBarVisibilityFromRevealGestureChanged(visible);
+        } catch (RemoteException ex) {
+            Slog.w(TAG,
+                    "Failed to send transient system bars visibility from reveal gesture for task: "
+                            + taskId);
+        }
+    }
+
     private void createGameSession(int taskId) {
         synchronized (mLock) {
             createGameSessionLocked(taskId);
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index a139589..d2fa386 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -22,6 +22,7 @@
 import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
 import static android.service.attention.AttentionService.ATTENTION_FAILURE_CANCELLED;
 import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN;
+import static android.service.attention.AttentionService.PROXIMITY_UNKNOWN;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -29,6 +30,7 @@
 import android.app.ActivityThread;
 import android.attention.AttentionManagerInternal;
 import android.attention.AttentionManagerInternal.AttentionCallbackInternal;
+import android.attention.AttentionManagerInternal.ProximityCallbackInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -57,6 +59,7 @@
 import android.service.attention.AttentionService.AttentionSuccessCodes;
 import android.service.attention.IAttentionCallback;
 import android.service.attention.IAttentionService;
+import android.service.attention.IProximityCallback;
 import android.text.TextUtils;
 import android.util.Slog;
 
@@ -134,6 +137,15 @@
     @GuardedBy("mLock")
     AttentionCheck mCurrentAttentionCheck;
 
+    /**
+     * A proxy for relaying proximity information between the Attention Service and the client.
+     * The proxy will be initialized when the client calls onStartProximityUpdates and will be
+     * disabled only when the client calls onStopProximityUpdates.
+     */
+    @VisibleForTesting
+    @GuardedBy("mLock")
+    ProximityUpdate mCurrentProximityUpdate;
+
     public AttentionManagerService(Context context) {
         this(context, (PowerManager) context.getSystemService(Context.POWER_SERVICE),
                 new Object(), null);
@@ -315,6 +327,77 @@
         }
     }
 
+    /**
+     * Requests the continuous updates of proximity signal via the provided callback,
+     * until the given callback is stopped.
+     *
+     * Calling this multiple times for duplicate requests will be no-ops, returning true.
+     *
+     * @return {@code true} if the framework was able to dispatch the request
+     */
+    @VisibleForTesting
+    boolean onStartProximityUpdates(ProximityCallbackInternal callbackInternal) {
+        Objects.requireNonNull(callbackInternal);
+        if (!mIsServiceEnabled) {
+            Slog.w(LOG_TAG, "Trying to call onProximityUpdate() on an unsupported device.");
+            return false;
+        }
+
+        if (!isServiceAvailable()) {
+            Slog.w(LOG_TAG, "Service is not available at this moment.");
+            return false;
+        }
+
+        // don't allow proximity request in screen off state.
+        // This behavior might change in the future.
+        if (!mPowerManager.isInteractive()) {
+            Slog.w(LOG_TAG, "Proximity Service is unavailable during screen off at this moment.");
+            return false;
+        }
+
+        synchronized (mLock) {
+            // schedule shutting down the connection if no one resets this timer
+            freeIfInactiveLocked();
+
+            // lazily start the service, which should be very lightweight to start
+            bindLocked();
+
+            /*
+            Prevent spamming with multiple requests, only one at a time is allowed.
+            If there are use-cases for keeping track of multiple requests, we
+            can refactor ProximityUpdate object to keep track of multiple internal callbacks.
+             */
+            if (mCurrentProximityUpdate != null && mCurrentProximityUpdate.mStartedUpdates) {
+                if (mCurrentProximityUpdate.mCallbackInternal == callbackInternal) {
+                    Slog.w(LOG_TAG, "Provided callback is already registered. Skipping.");
+                    return true;
+                } else {
+                    // reject the new request since the old request is still alive.
+                    Slog.w(LOG_TAG, "New proximity update cannot be processed because there is "
+                            + "already an ongoing update");
+                    return false;
+                }
+            }
+            mCurrentProximityUpdate = new ProximityUpdate(callbackInternal);
+            return mCurrentProximityUpdate.startUpdates();
+        }
+    }
+
+    /** Cancels the specified proximity registration. */
+    @VisibleForTesting
+    void onStopProximityUpdates(ProximityCallbackInternal callbackInternal) {
+        synchronized (mLock) {
+            if (mCurrentProximityUpdate == null
+                    || !mCurrentProximityUpdate.mCallbackInternal.equals(callbackInternal)
+                    || !mCurrentProximityUpdate.mStartedUpdates) {
+                Slog.w(LOG_TAG, "Cannot stop a non-current callback");
+                return;
+            }
+            mCurrentProximityUpdate.cancelUpdates();
+            mCurrentProximityUpdate = null;
+        }
+    }
+
     @GuardedBy("mLock")
     @VisibleForTesting
     protected void freeIfInactiveLocked() {
@@ -390,15 +473,18 @@
             ipw.println("Class=" + mComponentName.getClassName());
             ipw.decreaseIndent();
         }
-        ipw.println("binding=" + mBinding);
-        ipw.println("current attention check:");
         synchronized (mLock) {
+            ipw.println("binding=" + mBinding);
+            ipw.println("current attention check:");
             if (mCurrentAttentionCheck != null) {
                 mCurrentAttentionCheck.dump(ipw);
             }
             if (mAttentionCheckCacheBuffer != null) {
                 mAttentionCheckCacheBuffer.dump(ipw);
             }
+            if (mCurrentProximityUpdate != null) {
+                mCurrentProximityUpdate.dump(ipw);
+            }
         }
     }
 
@@ -417,6 +503,17 @@
         public void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) {
             AttentionManagerService.this.cancelAttentionCheck(callbackInternal);
         }
+
+        @Override
+        public boolean onStartProximityUpdates(
+                ProximityCallbackInternal callback) {
+            return AttentionManagerService.this.onStartProximityUpdates(callback);
+        }
+
+        @Override
+        public void onStopProximityUpdates(ProximityCallbackInternal callback) {
+            AttentionManagerService.this.onStopProximityUpdates(callback);
+        }
     }
 
     @VisibleForTesting
@@ -536,6 +633,71 @@
         }
     }
 
+    @VisibleForTesting
+    final class ProximityUpdate {
+        private final ProximityCallbackInternal mCallbackInternal;
+        private final IProximityCallback mIProximityCallback;
+        private boolean mStartedUpdates;
+
+        ProximityUpdate(ProximityCallbackInternal callbackInternal) {
+            mCallbackInternal = callbackInternal;
+            mIProximityCallback = new IProximityCallback.Stub() {
+                @Override
+                public void onProximityUpdate(double distance) {
+                    synchronized (mLock) {
+                        mCallbackInternal.onProximityUpdate(distance);
+                        freeIfInactiveLocked();
+                    }
+                }
+            };
+        }
+
+        boolean startUpdates() {
+            synchronized (mLock) {
+                if (mStartedUpdates) {
+                    Slog.w(LOG_TAG, "Already registered to a proximity service.");
+                    return false;
+                }
+                if (mService == null) {
+                    Slog.w(LOG_TAG,
+                            "There is no service bound. Proximity update request rejected.");
+                    return false;
+                }
+                try {
+                    mService.onStartProximityUpdates(mIProximityCallback);
+                    mStartedUpdates = true;
+                } catch (RemoteException e) {
+                    Slog.e(LOG_TAG, "Cannot call into the AttentionService", e);
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        void cancelUpdates() {
+            synchronized (mLock) {
+                if (mStartedUpdates) {
+                    if (mService == null) {
+                        mStartedUpdates = false;
+                        return;
+                    }
+                    try {
+                        mService.onStopProximityUpdates();
+                        mStartedUpdates = false;
+                    } catch (RemoteException e) {
+                        Slog.e(LOG_TAG, "Cannot call into the AttentionService", e);
+                    }
+                }
+            }
+        }
+
+        void dump(IndentingPrintWriter ipw) {
+            ipw.increaseIndent();
+            ipw.println("is StartedUpdates=" + mStartedUpdates);
+            ipw.decreaseIndent();
+        }
+    }
+
     private void appendResultToAttentionCacheBuffer(AttentionCheckCache cache) {
         synchronized (mLock) {
             if (mAttentionCheckCacheBuffer == null) {
@@ -593,6 +755,18 @@
                 mCurrentAttentionCheck.mCallbackInternal.onFailure(ATTENTION_FAILURE_UNKNOWN);
             }
         }
+        if (mCurrentProximityUpdate != null && mCurrentProximityUpdate.mStartedUpdates) {
+            if (mService != null) {
+                try {
+                    mService.onStartProximityUpdates(mCurrentProximityUpdate.mIProximityCallback);
+                } catch (RemoteException e) {
+                    Slog.e(LOG_TAG, "Cannot call into the AttentionService", e);
+                }
+            } else {
+                mCurrentProximityUpdate.cancelUpdates();
+                mCurrentProximityUpdate = null;
+            }
+        }
     }
 
     @VisibleForTesting
@@ -609,7 +783,9 @@
             switch (msg.what) {
                 // Do not occupy resources when not in use - unbind proactively.
                 case CHECK_CONNECTION_EXPIRATION: {
-                    cancelAndUnbindLocked();
+                    synchronized (mLock) {
+                        cancelAndUnbindLocked();
+                    }
                 }
                 break;
 
@@ -653,10 +829,15 @@
     @GuardedBy("mLock")
     private void cancelAndUnbindLocked() {
         synchronized (mLock) {
-            if (mCurrentAttentionCheck == null) {
+            if (mCurrentAttentionCheck == null && mCurrentProximityUpdate == null) {
                 return;
             }
-            cancel();
+            if (mCurrentAttentionCheck != null) {
+                cancel();
+            }
+            if (mCurrentProximityUpdate != null) {
+                mCurrentProximityUpdate.cancelUpdates();
+            }
             if (mService == null) {
                 return;
             }
@@ -702,7 +883,9 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
-                cancelAndUnbindLocked();
+                synchronized (mLock) {
+                    cancelAndUnbindLocked();
+                }
             }
         }
     }
@@ -730,8 +913,27 @@
             }
         }
 
+        class TestableProximityCallbackInternal extends ProximityCallbackInternal {
+            private double mLastCallbackCode = PROXIMITY_UNKNOWN;
+
+            @Override
+            public void onProximityUpdate(double distance) {
+                mLastCallbackCode = distance;
+            }
+
+            public void reset() {
+                mLastCallbackCode = PROXIMITY_UNKNOWN;
+            }
+
+            public double getLastCallbackCode() {
+                return mLastCallbackCode;
+            }
+        }
+
         final TestableAttentionCallbackInternal mTestableAttentionCallback =
                 new TestableAttentionCallbackInternal();
+        final TestableProximityCallbackInternal mTestableProximityCallback =
+                new TestableProximityCallbackInternal();
 
         @Override
         public int onCommand(@Nullable final String cmd) {
@@ -749,6 +951,10 @@
                                 return cmdCallCheckAttention();
                             case "cancelCheckAttention":
                                 return cmdCallCancelAttention();
+                            case "onStartProximityUpdates":
+                                return cmdCallOnStartProximityUpdates();
+                            case "onStopProximityUpdates":
+                                return cmdCallOnStopProximityUpdates();
                             default:
                                 throw new IllegalArgumentException("Invalid argument");
                         }
@@ -758,6 +964,8 @@
                         return cmdClearTestableAttentionService();
                     case "getLastTestCallbackCode":
                         return cmdGetLastTestCallbackCode();
+                    case "getLastTestProximityCallbackCode":
+                        return cmdGetLastTestProximityCallbackCode();
                     default:
                         return handleDefaultCommands(cmd);
                 }
@@ -782,6 +990,7 @@
         private int cmdClearTestableAttentionService() {
             sTestAttentionServicePackage = "";
             mTestableAttentionCallback.reset();
+            mTestableProximityCallback.reset();
             resetStates();
             return 0;
         }
@@ -800,6 +1009,20 @@
             return 0;
         }
 
+        private int cmdCallOnStartProximityUpdates() {
+            final PrintWriter out = getOutPrintWriter();
+            boolean calledSuccessfully = onStartProximityUpdates(mTestableProximityCallback);
+            out.println(calledSuccessfully ? "true" : "false");
+            return 0;
+        }
+
+        private int cmdCallOnStopProximityUpdates() {
+            final PrintWriter out = getOutPrintWriter();
+            onStopProximityUpdates(mTestableProximityCallback);
+            out.println("true");
+            return 0;
+        }
+
         private int cmdResolveAttentionServiceComponent() {
             final PrintWriter out = getOutPrintWriter();
             ComponentName resolvedComponent = resolveAttentionService(mContext);
@@ -813,7 +1036,16 @@
             return 0;
         }
 
+        private int cmdGetLastTestProximityCallbackCode() {
+            final PrintWriter out = getOutPrintWriter();
+            out.println(mTestableProximityCallback.getLastCallbackCode());
+            return 0;
+        }
+
         private void resetStates() {
+            synchronized (mLock) {
+                mCurrentProximityUpdate = null;
+            }
             mComponentName = resolveAttentionService(mContext);
         }
 
@@ -844,11 +1076,24 @@
                             + " (to see the result, call getLastTestCallbackCode)");
             out.println("       := false, otherwise");
             out.println("  call cancelCheckAttention: Cancels check attention");
+            out.println("  call onStartProximityUpdates: Calls onStartProximityUpdates");
+            out.println("  ---returns:");
+            out.println(
+                    "       := true, if the request was successfully dispatched to the service "
+                            + "implementation."
+                            + " (to see the result, call getLastTestProximityCallbackCode)");
+            out.println("       := false, otherwise");
+            out.println("  call onStopProximityUpdates: Cancels proximity updates");
             out.println("  getLastTestCallbackCode");
             out.println("  ---returns:");
             out.println(
                     "       := An integer, representing the last callback code received from the "
                             + "bounded implementation. If none, it will return -1");
+            out.println("  getLastTestProximityCallbackCode");
+            out.println("  ---returns:");
+            out.println(
+                    "       := A double, representing the last proximity value received from the "
+                            + "bounded implementation. If none, it will return -1.0");
         }
     }
 
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 28508f4..53fe450 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -1090,6 +1090,10 @@
                 && mAutofillInternal.isAugmentedAutofillServiceForUser(uid, userId)) {
             return;
         }
+        if (mPm.checkPermission(Manifest.permission.SUPPRESS_CLIPBOARD_ACCESS_NOTIFICATION,
+                callingPackage) == PackageManager.PERMISSION_GRANTED) {
+            return;
+        }
         // Don't notify if already notified for this uid and clip.
         if (clipboard.mNotifiedUids.get(uid)) {
             return;
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 1b55257..162eb0e 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -201,6 +201,10 @@
     // Controls High Brightness Mode.
     private HighBrightnessModeController mHbmController;
 
+    // Throttles (caps) maximum allowed brightness
+    private BrightnessThrottler mBrightnessThrottler;
+    private boolean mIsBrightnessThrottled;
+
     // Context-sensitive brightness configurations require keeping track of the foreground app's
     // package name and category, which is done by registering a TaskStackListener to call back to
     // us onTaskStackChanged, and then using the ActivityTaskManager to get the foreground app's
@@ -226,7 +230,7 @@
             long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
             boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
             HysteresisLevels screenBrightnessThresholds, Context context,
-            HighBrightnessModeController hbmController,
+            HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler,
             BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
             int ambientLightHorizonLong) {
         this(new Injector(), callbacks, looper, sensorManager, lightSensor,
@@ -235,8 +239,8 @@
                 lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig,
                 darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig,
                 ambientBrightnessThresholds, screenBrightnessThresholds, context,
-                hbmController, idleModeBrightnessMapper, ambientLightHorizonShort,
-                ambientLightHorizonLong
+                hbmController, brightnessThrottler, idleModeBrightnessMapper,
+                ambientLightHorizonShort, ambientLightHorizonLong
         );
     }
 
@@ -249,7 +253,7 @@
             long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
             boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
             HysteresisLevels screenBrightnessThresholds, Context context,
-            HighBrightnessModeController hbmController,
+            HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler,
             BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
             int ambientLightHorizonLong) {
         mInjector = injector;
@@ -291,6 +295,7 @@
         mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
         mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
         mHbmController = hbmController;
+        mBrightnessThrottler = brightnessThrottler;
         mInteractiveModeBrightnessMapper = interactiveModeBrightnessMapper;
         mIdleModeBrightnessMapper = idleModeBrightnessMapper;
         // Initialize to active (normal) screen brightness mode
@@ -365,6 +370,13 @@
             prepareBrightnessAdjustmentSample();
         }
         changed |= setLightSensorEnabled(enable && !dozing);
+
+        if (mIsBrightnessThrottled != mBrightnessThrottler.isThrottled()) {
+            // Maximum brightness has changed, so recalculate display brightness.
+            mIsBrightnessThrottled = mBrightnessThrottler.isThrottled();
+            changed = true;
+        }
+
         if (changed) {
             updateAutoBrightness(false /*sendUpdate*/, userInitiatedChange);
         }
@@ -855,8 +867,11 @@
 
     // Clamps values with float range [0.0-1.0]
     private float clampScreenBrightness(float value) {
-        return MathUtils.constrain(value,
-                mHbmController.getCurrentBrightnessMin(), mHbmController.getCurrentBrightnessMax());
+        final float minBrightness = Math.min(mHbmController.getCurrentBrightnessMin(),
+                mBrightnessThrottler.getBrightnessCap());
+        final float maxBrightness = Math.min(mHbmController.getCurrentBrightnessMax(),
+                mBrightnessThrottler.getBrightnessCap());
+        return MathUtils.constrain(value, minBrightness, maxBrightness);
     }
 
     private void prepareBrightnessAdjustmentSample() {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 3494342..6ae1a5a 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -974,7 +974,7 @@
                     lightSensorRate, initialLightSensorRate, brighteningLightDebounce,
                     darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp,
                     ambientBrightnessThresholds, screenBrightnessThresholds, mContext,
-                    mHbmController, mIdleModeBrightnessMapper,
+                    mHbmController, mBrightnessThrottler, mIdleModeBrightnessMapper,
                     mDisplayDeviceConfig.getAmbientHorizonShort(),
                     mDisplayDeviceConfig.getAmbientHorizonLong());
         } else {
@@ -1347,6 +1347,29 @@
             mBrightnessReasonTemp.setReason(BrightnessReason.REASON_MANUAL);
         }
 
+        // Now that a desired brightness has been calculated, apply brightness throttling. The
+        // dimming and low power transformations that follow can only dim brightness further.
+        //
+        // We didn't do this earlier through brightness clamping because we need to know both
+        // unthrottled (unclamped/ideal) and throttled brightness levels for subsequent operations.
+        // Note throttling effectively changes the allowed brightness range, so, similarly to HBM,
+        // we broadcast this change through setting.
+        final float unthrottledBrightnessState = brightnessState;
+        if (mBrightnessThrottler.isThrottled()) {
+            brightnessState = Math.min(brightnessState, mBrightnessThrottler.getBrightnessCap());
+            mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_THROTTLED);
+            if (!mAppliedThrottling) {
+                // Brightness throttling is needed, so do so quickly.
+                // Later, when throttling is removed, we let other mechanisms decide on speed.
+                slowChange = false;
+                updateScreenBrightnessSetting = true;
+            }
+            mAppliedThrottling = true;
+        } else if (mAppliedThrottling) {
+            mAppliedThrottling = false;
+            updateScreenBrightnessSetting = true;
+        }
+
         if (updateScreenBrightnessSetting) {
             // Tell the rest of the system about the new brightness in case we had to change it
             // for things like auto-brightness or high-brightness-mode. Note that we do this
@@ -1393,20 +1416,6 @@
             mAppliedLowPower = false;
         }
 
-        // Apply brightness throttling after applying all other transforms
-        final float unthrottledBrightnessState = brightnessState;
-        if (mBrightnessThrottler.isThrottled()) {
-            brightnessState = Math.min(brightnessState, mBrightnessThrottler.getBrightnessCap());
-            mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_THROTTLED);
-            if (!mAppliedThrottling) {
-                slowChange = false;
-            }
-            mAppliedThrottling = true;
-        } else if (mAppliedThrottling) {
-            slowChange = false;
-            mAppliedThrottling = false;
-        }
-
         // The current brightness to use has been calculated at this point, and HbmController should
         // be notified so that it can accurately calculate HDR or HBM levels. We specifically do it
         // here instead of having HbmController listen to the brightness setting because certain
@@ -1656,6 +1665,10 @@
 
     private boolean saveBrightnessInfo(float brightness, float adjustedBrightness) {
         synchronized (mCachedBrightnessInfo) {
+            final float minBrightness = Math.min(mHbmController.getCurrentBrightnessMin(),
+                    mBrightnessThrottler.getBrightnessCap());
+            final float maxBrightness = Math.min(mHbmController.getCurrentBrightnessMax(),
+                    mBrightnessThrottler.getBrightnessCap());
             boolean changed = false;
 
             changed |=
@@ -1666,10 +1679,10 @@
                         adjustedBrightness);
             changed |=
                 mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightnessMin,
-                        mHbmController.getCurrentBrightnessMin());
+                        minBrightness);
             changed |=
                 mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightnessMax,
-                        mHbmController.getCurrentBrightnessMax());
+                        maxBrightness);
             changed |=
                 mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.hbmMode,
                         mHbmController.getHighBrightnessMode());
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index 65ec1c0..4792821f6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -385,6 +385,16 @@
                 R.bool.config_cecTvSendStandbyOnSleepDisabled_allowed,
                 R.bool.config_cecTvSendStandbyOnSleepDisabled_default);
 
+        Setting setMenuLanguage = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE,
+                R.bool.config_cecSetMenuLanguage_userConfigurable);
+        setMenuLanguage.registerValue(HdmiControlManager.SET_MENU_LANGUAGE_ENABLED,
+                R.bool.config_cecSetMenuLanguageEnabled_allowed,
+                R.bool.config_cecSetMenuLanguageEnabled_default);
+        setMenuLanguage.registerValue(HdmiControlManager.SET_MENU_LANGUAGE_DISABLED,
+                R.bool.config_cecSetMenuLanguageDisabled_allowed,
+                R.bool.config_cecSetMenuLanguageDisabled_default);
+
         Setting rcProfileTv = registerSetting(
                 HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
                 R.bool.config_cecRcProfileTv_userConfigurable);
@@ -697,6 +707,8 @@
                 return STORAGE_SHARED_PREFS;
             case HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP:
                 return STORAGE_SHARED_PREFS;
+            case HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE:
+                return STORAGE_SHARED_PREFS;
             case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV:
                 return STORAGE_SHARED_PREFS;
             case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU:
@@ -768,6 +780,8 @@
                 return setting.getName();
             case HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP:
                 return setting.getName();
+            case HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE:
+                return setting.getName();
             case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV:
                 return setting.getName();
             case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU:
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index c674ffe..454a76a 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -901,17 +901,12 @@
     protected int handleVendorCommandWithId(HdmiCecMessage message) {
         byte[] params = message.getParams();
         int vendorId = HdmiUtils.threeBytesToInt(params);
-        if (vendorId == mService.getVendorId()) {
-            if (!mService.invokeVendorCommandListenersOnReceived(
-                    mDeviceType, message.getSource(), message.getDestination(), params, true)) {
-                return Constants.ABORT_REFUSED;
-            }
-        } else if (message.getDestination() != Constants.ADDR_BROADCAST
-                && message.getSource() != Constants.ADDR_UNREGISTERED) {
-            Slog.v(TAG, "Wrong direct vendor command. Replying with <Feature Abort>");
-            return Constants.ABORT_UNRECOGNIZED_OPCODE;
-        } else {
+        if (message.getDestination() == Constants.ADDR_BROADCAST
+                || message.getSource() == Constants.ADDR_UNREGISTERED) {
             Slog.v(TAG, "Wrong broadcast vendor command. Ignoring");
+        } else if (!mService.invokeVendorCommandListenersOnReceived(
+                mDeviceType, message.getSource(), message.getDestination(), params, true)) {
+            return Constants.ABORT_REFUSED;
         }
         return Constants.HANDLED;
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index f413fbd..0edcea5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -50,9 +50,6 @@
 public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
     private static final String TAG = "HdmiCecLocalDevicePlayback";
 
-    private static final boolean SET_MENU_LANGUAGE =
-            HdmiProperties.set_menu_language_enabled().orElse(false);
-
     // How long to wait after hotplug out before possibly going to Standby.
     @VisibleForTesting
     static final long STANDBY_AFTER_HOTPLUG_OUT_DELAY_MS = 30_000;
@@ -388,7 +385,9 @@
     @Constants.HandleMessageResult
     protected int handleSetMenuLanguage(HdmiCecMessage message) {
         assertRunOnServiceThread();
-        if (!SET_MENU_LANGUAGE) {
+        if (mService.getHdmiCecConfig().getIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE)
+                    == HdmiControlManager.SET_MENU_LANGUAGE_DISABLED) {
             return Constants.ABORT_UNRECOGNIZED_OPCODE;
         }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
index 6f7473d..57fe9e6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
@@ -133,6 +133,7 @@
         addHandler(Constants.MESSAGE_SET_OSD_NAME, mBypasser);
         addHandler(Constants.MESSAGE_DEVICE_VENDOR_ID, mBypasser);
         addHandler(Constants.MESSAGE_REPORT_POWER_STATUS, mBypasser);
+        addHandler(Constants.MESSAGE_GIVE_FEATURES, mBypasser);
 
         addHandler(Constants.MESSAGE_USER_CONTROL_PRESSED, mUserControlProcessedHandler);
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 8391e0b..8ac2331 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1701,11 +1701,11 @@
 
     class VendorCommandListenerRecord implements IBinder.DeathRecipient {
         private final IHdmiVendorCommandListener mListener;
-        private final int mDeviceType;
+        private final int mVendorId;
 
-        public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) {
+        VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int vendorId) {
             mListener = listener;
-            mDeviceType = deviceType;
+            mVendorId = vendorId;
         }
 
         @Override
@@ -2191,10 +2191,10 @@
         }
 
         @Override
-        public void addVendorCommandListener(final IHdmiVendorCommandListener listener,
-                final int deviceType) {
+        public void addVendorCommandListener(
+                final IHdmiVendorCommandListener listener, final int vendorId) {
             initBinderCall();
-            HdmiControlService.this.addVendorCommandListener(listener, deviceType);
+            HdmiControlService.this.addVendorCommandListener(listener, vendorId);
         }
 
         @Override
@@ -3354,8 +3354,9 @@
         mStandbyMessageReceived = false;
     }
 
-    private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {
-        VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType);
+    @VisibleForTesting
+    void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) {
+        VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, vendorId);
         try {
             listener.asBinder().linkToDeath(record, 0);
         } catch (RemoteException e) {
@@ -3374,8 +3375,14 @@
                 return false;
             }
             for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) {
-                if (record.mDeviceType != deviceType) {
-                    continue;
+                if (hasVendorId) {
+                    int vendorId =
+                            ((params[0] & 0xFF) << 16)
+                                    + ((params[1] & 0xFF) << 8)
+                                    + (params[2] & 0xFF);
+                    if (record.mVendorId != vendorId) {
+                        continue;
+                    }
                 }
                 try {
                     record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId);
diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
new file mode 100644
index 0000000..dbd3f35
--- /dev/null
+++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.input;
+
+import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+
+import android.os.IBinder;
+import android.view.InputApplicationHandle;
+import android.view.InputChannel;
+import android.view.InputMonitor;
+import android.view.InputWindowHandle;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+
+/**
+ * An internal implementation of an {@link InputMonitor} that uses a spy window.
+ *
+ * This spy window is a layer container in the SurfaceFlinger hierarchy that does not have any
+ * graphical buffer, but can still receive input. It is parented to the DisplayContent so
+ * that it can spy on any pointer events that start in the DisplayContent bounds. When the
+ * object is constructed, it will add itself to SurfaceFlinger.
+ */
+class GestureMonitorSpyWindow {
+    final InputApplicationHandle mApplicationHandle;
+    final InputWindowHandle mWindowHandle;
+
+    // The token, InputChannel, and SurfaceControl are owned by this object.
+    final IBinder mMonitorToken;
+    final InputChannel mClientChannel;
+    final SurfaceControl mInputSurface;
+
+    GestureMonitorSpyWindow(IBinder token, String name, int displayId, int pid, int uid,
+            SurfaceControl sc, InputChannel inputChannel) {
+        mMonitorToken = token;
+        mClientChannel = inputChannel;
+        mInputSurface = sc;
+
+        mApplicationHandle = new InputApplicationHandle(null, name,
+                DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
+        mWindowHandle = new InputWindowHandle(mApplicationHandle, displayId);
+
+        mWindowHandle.name = name;
+        mWindowHandle.token = mClientChannel.getToken();
+        mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
+        mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+        mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+        mWindowHandle.visible = true;
+        mWindowHandle.focusable = false;
+        mWindowHandle.hasWallpaper = false;
+        mWindowHandle.paused = false;
+        mWindowHandle.ownerPid = pid;
+        mWindowHandle.ownerUid = uid;
+        mWindowHandle.inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_SPY;
+        mWindowHandle.scaleFactor = 1.0f;
+        mWindowHandle.trustedOverlay = true;
+        mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
+
+        final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+        t.setInputWindowInfo(mInputSurface, mWindowHandle);
+        t.setLayer(mInputSurface, Integer.MAX_VALUE);
+        t.setPosition(mInputSurface, 0, 0);
+        t.setCrop(mInputSurface, null /* crop to parent surface */);
+        t.show(mInputSurface);
+
+        t.apply();
+    }
+
+    void remove() {
+        final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+        t.hide(mInputSurface);
+        t.remove(mInputSurface);
+        t.apply();
+
+        mClientChannel.dispose();
+    }
+
+    String dump() {
+        return "name='" + mWindowHandle.name + "', inputChannelToken="
+                + mClientChannel.getToken() + " displayId=" + mWindowHandle.displayId;
+    }
+}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 783a88c..64b4da7 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -150,6 +150,8 @@
     static final String TAG = "InputManager";
     static final boolean DEBUG = false;
 
+    private static final boolean USE_SPY_WINDOW_GESTURE_MONITORS = false;
+
     private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
     private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml";
 
@@ -277,6 +279,12 @@
     @GuardedBy("mPointerDisplayIdLock")
     private int mOverriddenPointerDisplayId = Display.INVALID_DISPLAY;
 
+
+    // Holds all the registered gesture monitors that are implemented as spy windows. The spy
+    // windows are mapped by their InputChannel tokens.
+    @GuardedBy("mInputMonitors")
+    final Map<IBinder, GestureMonitorSpyWindow> mInputMonitors = new HashMap<>();
+
     private static native long nativeInit(InputManagerService service,
             Context context, MessageQueue messageQueue);
     private static native void nativeStart(long ptr);
@@ -716,33 +724,77 @@
                 inputChannelName, Binder.getCallingPid());
     }
 
+    @NonNull
+    private InputChannel createSpyWindowGestureMonitor(IBinder monitorToken, String name,
+            int displayId, int pid, int uid) {
+        final SurfaceControl sc = mWindowManagerCallbacks.createSurfaceForGestureMonitor(name,
+                displayId);
+        if (sc == null) {
+            throw new IllegalArgumentException(
+                    "Could not create gesture monitor surface on display: " + displayId);
+        }
+        final InputChannel channel = createInputChannel(name);
+
+        try {
+            monitorToken.linkToDeath(() -> removeSpyWindowGestureMonitor(channel.getToken()), 0);
+        } catch (RemoteException e) {
+            Slog.i(TAG, "Client died before '" + name + "' could be created.");
+            return null;
+        }
+        synchronized (mInputMonitors) {
+            mInputMonitors.put(channel.getToken(),
+                    new GestureMonitorSpyWindow(monitorToken, name, displayId, pid, uid, sc,
+                            channel));
+        }
+
+        final InputChannel outInputChannel = new InputChannel();
+        channel.copyTo(outInputChannel);
+        return outInputChannel;
+    }
+
+    private void removeSpyWindowGestureMonitor(IBinder inputChannelToken) {
+        final GestureMonitorSpyWindow monitor;
+        synchronized (mInputMonitors) {
+            monitor = mInputMonitors.remove(inputChannelToken);
+        }
+        removeInputChannel(inputChannelToken);
+        if (monitor == null) return;
+        monitor.remove();
+    }
+
     /**
      * Creates an input monitor that will receive pointer events for the purposes of system-wide
      * gesture interpretation.
      *
-     * @param inputChannelName The input channel name.
+     * @param requestedName The input channel name.
      * @param displayId Target display id.
      * @return The input channel.
      */
     @Override // Binder call
-    public InputMonitor monitorGestureInput(String inputChannelName, int displayId) {
+    public InputMonitor monitorGestureInput(IBinder monitorToken, @NonNull String requestedName,
+            int displayId) {
         if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT,
-                "monitorInputRegion()")) {
+                "monitorGestureInput()")) {
             throw new SecurityException("Requires MONITOR_INPUT permission");
         }
-        Objects.requireNonNull(inputChannelName, "inputChannelName must not be null.");
+        Objects.requireNonNull(requestedName, "name must not be null.");
+        Objects.requireNonNull(monitorToken, "token must not be null.");
 
         if (displayId < Display.DEFAULT_DISPLAY) {
             throw new IllegalArgumentException("displayId must >= 0.");
         }
+        final String name = "[Gesture Monitor] " + requestedName;
         final int pid = Binder.getCallingPid();
+        final int uid = Binder.getCallingUid();
 
         final long ident = Binder.clearCallingIdentity();
         try {
-            InputChannel inputChannel = nativeCreateInputMonitor(
-                    mPtr, displayId, true /*isGestureMonitor*/, inputChannelName, pid);
-            InputMonitorHost host = new InputMonitorHost(inputChannel.getToken());
-            return new InputMonitor(inputChannel, host);
+            final InputChannel inputChannel =
+                    USE_SPY_WINDOW_GESTURE_MONITORS
+                            ? createSpyWindowGestureMonitor(monitorToken, name, displayId, pid, uid)
+                            : nativeCreateInputMonitor(mPtr, displayId, true /*isGestureMonitor*/,
+                                    requestedName, pid);
+            return new InputMonitor(inputChannel, new InputMonitorHost(inputChannel.getToken()));
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -2563,37 +2615,51 @@
         String dumpStr = nativeDump(mPtr);
         if (dumpStr != null) {
             pw.println(dumpStr);
-            dumpAssociations(pw);
         }
+
+        pw.println("Input Manager Service (Java) State:");
+        dumpAssociations(pw, "  " /*prefix*/);
+        dumpSpyWindowGestureMonitors(pw, "  " /*prefix*/);
     }
 
-    private void dumpAssociations(PrintWriter pw) {
+    private void dumpAssociations(PrintWriter pw, String prefix) {
         if (!mStaticAssociations.isEmpty()) {
-            pw.println("Static Associations:");
+            pw.println(prefix + "Static Associations:");
             mStaticAssociations.forEach((k, v) -> {
-                pw.print("  port: " + k);
+                pw.print(prefix + "  port: " + k);
                 pw.println("  display: " + v);
             });
         }
 
         synchronized (mAssociationsLock) {
             if (!mRuntimeAssociations.isEmpty()) {
-                pw.println("Runtime Associations:");
+                pw.println(prefix + "Runtime Associations:");
                 mRuntimeAssociations.forEach((k, v) -> {
-                    pw.print("  port: " + k);
+                    pw.print(prefix + "  port: " + k);
                     pw.println("  display: " + v);
                 });
             }
             if (!mUniqueIdAssociations.isEmpty()) {
-                pw.println("Unique Id Associations:");
+                pw.println(prefix + "Unique Id Associations:");
                 mUniqueIdAssociations.forEach((k, v) -> {
-                    pw.print("  port: " + k);
+                    pw.print(prefix + "  port: " + k);
                     pw.println("  uniqueId: " + v);
                 });
             }
         }
     }
 
+    private void dumpSpyWindowGestureMonitors(PrintWriter pw, String prefix) {
+        synchronized (mInputMonitors) {
+            if (mInputMonitors.isEmpty()) return;
+            pw.println(prefix + "Gesture Monitors (implemented as spy windows):");
+            int i = 0;
+            for (final GestureMonitorSpyWindow monitor : mInputMonitors.values()) {
+                pw.append(prefix + "  " + i++ + ": ").println(monitor.dump());
+            }
+        }
+    }
+
     private boolean checkCallingPermission(String permission, String func) {
         // Quick check: if the calling permission is me, it's all okay.
         if (Binder.getCallingPid() == Process.myPid()) {
@@ -2618,6 +2684,7 @@
         synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
         synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ }
         synchronized (mPointerDisplayIdLock) { /* Test if blocked by pointer display id lock */ }
+        synchronized (mInputMonitors) { /* Test if blocked by input monitor lock. */ }
         nativeMonitor(mPtr);
     }
 
@@ -2686,6 +2753,11 @@
 
     // Native callback.
     private void notifyInputChannelBroken(IBinder token) {
+        synchronized (mInputMonitors) {
+            if (mInputMonitors.containsKey(token)) {
+                removeSpyWindowGestureMonitor(token);
+            }
+        }
         mWindowManagerCallbacks.notifyInputChannelBroken(token);
     }
 
@@ -2721,6 +2793,17 @@
 
     // Native callback
     private void notifyWindowUnresponsive(IBinder token, String reason) {
+        int gestureMonitorPid = -1;
+        synchronized (mInputMonitors) {
+            final GestureMonitorSpyWindow gestureMonitor = mInputMonitors.get(token);
+            if (gestureMonitor != null) {
+                gestureMonitorPid = gestureMonitor.mWindowHandle.ownerPid;
+            }
+        }
+        if (gestureMonitorPid != -1) {
+            mWindowManagerCallbacks.notifyGestureMonitorUnresponsive(gestureMonitorPid, reason);
+            return;
+        }
         mWindowManagerCallbacks.notifyWindowUnresponsive(token, reason);
     }
 
@@ -2731,6 +2814,17 @@
 
     // Native callback
     private void notifyWindowResponsive(IBinder token) {
+        int gestureMonitorPid = -1;
+        synchronized (mInputMonitors) {
+            final GestureMonitorSpyWindow gestureMonitor = mInputMonitors.get(token);
+            if (gestureMonitor != null) {
+                gestureMonitorPid = gestureMonitor.mWindowHandle.ownerPid;
+            }
+        }
+        if (gestureMonitorPid != -1) {
+            mWindowManagerCallbacks.notifyGestureMonitorResponsive(gestureMonitorPid);
+            return;
+        }
         mWindowManagerCallbacks.notifyWindowResponsive(token);
     }
 
@@ -3184,6 +3278,16 @@
          * pointers such as the mouse cursor and touch spots for the given display.
          */
         SurfaceControl getParentSurfaceForPointers(int displayId);
+
+        /**
+         * Create a {@link SurfaceControl} that can be configured to receive input over the entire
+         * display to implement a gesture monitor. The surface will not have a graphical buffer.
+         * @param name the name of the gesture monitor
+         * @param displayId the display to create the window in
+         * @return the SurfaceControl of the new layer container surface
+         */
+        @Nullable
+        SurfaceControl createSurfaceForGestureMonitor(String name, int displayId);
     }
 
     /**
@@ -3258,20 +3362,24 @@
      * Interface for the system to handle request from InputMonitors.
      */
     private final class InputMonitorHost extends IInputMonitorHost.Stub {
-        private final IBinder mToken;
+        private final IBinder mInputChannelToken;
 
-        InputMonitorHost(IBinder token) {
-            mToken = token;
+        InputMonitorHost(IBinder inputChannelToken) {
+            mInputChannelToken = inputChannelToken;
         }
 
         @Override
         public void pilferPointers() {
-            nativePilferPointers(mPtr, mToken);
+            nativePilferPointers(mPtr, mInputChannelToken);
         }
 
         @Override
         public void dispose() {
-            nativeRemoveInputChannel(mPtr, mToken);
+            if (USE_SPY_WINDOW_GESTURE_MONITORS) {
+                removeSpyWindowGestureMonitor(mInputChannelToken);
+                return;
+            }
+            nativeRemoveInputChannel(mPtr, mInputChannelToken);
         }
     }
 
diff --git a/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java b/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
index 134fb96..01aee7b 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
@@ -31,13 +31,11 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.os.BestClock;
 import android.os.Binder;
 import android.os.HandlerThread;
 import android.os.LocaleList;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -61,7 +59,6 @@
 import java.nio.charset.StandardCharsets;
 import java.time.Clock;
 import java.time.Duration;
-import java.time.ZoneOffset;
 import java.util.HashMap;
 
 /**
@@ -97,15 +94,10 @@
 
     LocaleManagerBackupHelper(LocaleManagerService localeManagerService,
             PackageManagerInternal pmInternal) {
-        this(localeManagerService.mContext, localeManagerService, pmInternal, getDefaultClock(),
+        this(localeManagerService.mContext, localeManagerService, pmInternal, Clock.systemUTC(),
                 new SparseArray<>());
     }
 
-    private static @NonNull Clock getDefaultClock() {
-        return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(),
-                Clock.systemUTC());
-    }
-
     @VisibleForTesting LocaleManagerBackupHelper(Context context,
             LocaleManagerService localeManagerService,
             PackageManagerInternal pmInternal, Clock clock, SparseArray<StagedData> stagedData) {
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 21ea1f6..a1ee46b 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -465,7 +465,7 @@
             try {
                 mHub.onHostEndpointConnected(info);
             } catch (RemoteException | ServiceSpecificException e) {
-                Log.e(TAG, "RemoteException in onHostEndpointConnected");
+                Log.e(TAG, "Exception in onHostEndpointConnected" + e.getMessage());
             }
         }
 
@@ -474,7 +474,7 @@
             try {
                 mHub.onHostEndpointDisconnected((char) hostEndpointId);
             } catch (RemoteException | ServiceSpecificException e) {
-                Log.e(TAG, "RemoteException in onHostEndpointDisconnected");
+                Log.e(TAG, "Exception in onHostEndpointDisconnected" + e.getMessage());
             }
         }
 
@@ -488,6 +488,8 @@
                 return ContextHubTransaction.RESULT_SUCCESS;
             } catch (RemoteException | ServiceSpecificException e) {
                 return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
+            } catch (IllegalArgumentException e) {
+                return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
             }
         }
 
@@ -499,8 +501,10 @@
             try {
                 mHub.loadNanoapp(contextHubId, aidlNanoAppBinary, transactionId);
                 return ContextHubTransaction.RESULT_SUCCESS;
-            } catch (RemoteException | ServiceSpecificException e) {
+            } catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
                 return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
+            } catch (IllegalArgumentException e) {
+                return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
             }
         }
 
@@ -510,8 +514,10 @@
             try {
                 mHub.unloadNanoapp(contextHubId, nanoappId, transactionId);
                 return ContextHubTransaction.RESULT_SUCCESS;
-            } catch (RemoteException | ServiceSpecificException e) {
+            } catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
                 return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
+            } catch (IllegalArgumentException e) {
+                return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
             }
         }
 
@@ -521,8 +527,10 @@
             try {
                 mHub.enableNanoapp(contextHubId, nanoappId, transactionId);
                 return ContextHubTransaction.RESULT_SUCCESS;
-            } catch (RemoteException | ServiceSpecificException e) {
+            } catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
                 return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
+            } catch (IllegalArgumentException e) {
+                return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
             }
         }
 
@@ -532,8 +540,10 @@
             try {
                 mHub.disableNanoapp(contextHubId, nanoappId, transactionId);
                 return ContextHubTransaction.RESULT_SUCCESS;
-            } catch (RemoteException | ServiceSpecificException e) {
+            } catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
                 return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
+            } catch (IllegalArgumentException e) {
+                return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
             }
         }
 
@@ -542,8 +552,10 @@
             try {
                 mHub.queryNanoapps(contextHubId);
                 return ContextHubTransaction.RESULT_SUCCESS;
-            } catch (RemoteException | ServiceSpecificException e) {
+            } catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
                 return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
+            } catch (IllegalArgumentException e) {
+                return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
             }
         }
 
@@ -551,7 +563,7 @@
             mAidlCallbackMap.put(contextHubId, new ContextHubAidlCallback(contextHubId, callback));
             try {
                 mHub.registerCallback(contextHubId, mAidlCallbackMap.get(contextHubId));
-            } catch (RemoteException | ServiceSpecificException e) {
+            } catch (RemoteException | ServiceSpecificException | IllegalArgumentException e) {
                 Log.e(TAG, "Exception while registering callback: " + e.getMessage());
             }
         }
diff --git a/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java b/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java
index 5036a6e..bfef978 100644
--- a/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java
@@ -63,16 +63,25 @@
     @Override
     protected boolean registerWithService(Void ignored,
             Collection<GnssListenerRegistration> registrations) {
-        if (D) {
-            Log.d(TAG, "starting gnss nmea messages");
+        if (mGnssNative.startNmeaMessageCollection()) {
+            if (D) {
+                Log.d(TAG, "starting gnss nmea messages collection");
+            }
+            return true;
+        } else {
+            Log.e(TAG, "error starting gnss nmea messages collection");
+            return false;
         }
-        return true;
     }
 
     @Override
     protected void unregisterWithService() {
-        if (D) {
-            Log.d(TAG, "stopping gnss nmea messages");
+        if (mGnssNative.stopNmeaMessageCollection()) {
+            if (D) {
+                Log.d(TAG, "stopping gnss nmea messages collection");
+            }
+        } else {
+            Log.e(TAG, "error stopping gnss nmea messages collection");
         }
     }
 
diff --git a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
index 936283d..0ce36d6 100644
--- a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
@@ -43,6 +43,7 @@
 
     private final AppOpsHelper mAppOpsHelper;
     private final LocationUsageLogger mLogger;
+    private final GnssNative mGnssNative;
 
     private boolean mIsNavigating = false;
 
@@ -50,6 +51,7 @@
         super(injector);
         mAppOpsHelper = injector.getAppOpsHelper();
         mLogger = injector.getLocationUsageLogger();
+        mGnssNative = gnssNative;
 
         gnssNative.addBaseCallbacks(this);
         gnssNative.addStatusCallbacks(this);
@@ -64,16 +66,25 @@
     @Override
     protected boolean registerWithService(Void ignored,
             Collection<GnssListenerRegistration> registrations) {
-        if (D) {
-            Log.d(TAG, "starting gnss status");
+        if (mGnssNative.startSvStatusCollection()) {
+            if (D) {
+                Log.d(TAG, "starting gnss sv status");
+            }
+            return true;
+        } else {
+            Log.e(TAG, "error starting gnss sv status");
+            return false;
         }
-        return true;
     }
 
     @Override
     protected void unregisterWithService() {
-        if (D) {
-            Log.d(TAG, "stopping gnss status");
+        if (mGnssNative.stopSvStatusCollection()) {
+            if (D) {
+                Log.d(TAG, "stopping gnss sv status");
+            }
+        } else {
+            Log.e(TAG, "error stopping gnss sv status");
         }
     }
 
diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
index e072bf7..af87677 100644
--- a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
+++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
@@ -783,6 +783,38 @@
     }
 
     /**
+     * Starts sv status collection.
+     */
+    public boolean startSvStatusCollection() {
+        Preconditions.checkState(mRegistered);
+        return mGnssHal.startSvStatusCollection();
+    }
+
+    /**
+     * Stops sv status collection.
+     */
+    public boolean stopSvStatusCollection() {
+        Preconditions.checkState(mRegistered);
+        return mGnssHal.stopSvStatusCollection();
+    }
+
+    /**
+     * Starts NMEA message collection.
+     */
+    public boolean startNmeaMessageCollection() {
+        Preconditions.checkState(mRegistered);
+        return mGnssHal.startNmeaMessageCollection();
+    }
+
+    /**
+     * Stops NMEA message collection.
+     */
+    public boolean stopNmeaMessageCollection() {
+        Preconditions.checkState(mRegistered);
+        return mGnssHal.stopNmeaMessageCollection();
+    }
+
+    /**
      * Returns true if measurement corrections are supported.
      */
     public boolean isMeasurementCorrectionsSupported() {
@@ -1369,6 +1401,22 @@
             return native_inject_measurement_corrections(corrections);
         }
 
+        protected boolean startSvStatusCollection() {
+            return native_start_sv_status_collection();
+        }
+
+        protected boolean stopSvStatusCollection() {
+            return native_stop_sv_status_collection();
+        }
+
+        protected boolean startNmeaMessageCollection() {
+            return native_start_nmea_message_collection();
+        }
+
+        protected boolean stopNmeaMessageCollection() {
+            return native_stop_nmea_message_collection();
+        }
+
         protected int getBatchSize() {
             return native_get_batch_size();
         }
@@ -1478,6 +1526,10 @@
 
     private static native int native_read_nmea(byte[] buffer, int bufferSize);
 
+    private static native boolean native_start_nmea_message_collection();
+
+    private static native boolean native_stop_nmea_message_collection();
+
     // location injection APIs
 
     private static native void native_inject_location(
@@ -1501,6 +1553,11 @@
 
     private static native void native_inject_time(long time, long timeReference, int uncertainty);
 
+    // sv status APIs
+    private static native boolean native_start_sv_status_collection();
+
+    private static native boolean native_stop_sv_status_collection();
+
     // navigation message APIs
 
     private static native boolean native_is_navigation_message_supported();
diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
similarity index 64%
rename from services/core/java/com/android/server/pm/InitAppsHelper.java
rename to services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
index 2fda02d..06405ae 100644
--- a/services/core/java/com/android/server/pm/InitAppsHelper.java
+++ b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
@@ -32,7 +32,6 @@
 import static com.android.server.pm.PackageManagerService.TAG;
 import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_FRAMEWORK_RES_SPLITS;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.parsing.ApkLiteParseUtils;
 import android.os.Environment;
@@ -62,25 +61,14 @@
  * further cleanup and eventually all the installation/scanning related logic will go to another
  * class.
  */
-final class InitAppsHelper {
+final class InitAndSystemPackageHelper {
     private final PackageManagerService mPm;
+
     private final List<ScanPartition> mDirsToScanAsSystem;
     private final int mScanFlags;
     private final int mSystemParseFlags;
     private final int mSystemScanFlags;
     private final InstallPackageHelper mInstallPackageHelper;
-    private final ApexManager mApexManager;
-    private final PackageParser2 mPackageParser;
-    private final ExecutorService mExecutorService;
-    /* Tracks how long system scan took */
-    private long mSystemScanTime;
-    /* Track of the number of cached system apps */
-    private int mCachedSystemApps;
-    /* Track of the number of system apps */
-    private int mSystemPackagesCount;
-    private final boolean mIsDeviceUpgrading;
-    private final boolean mIsOnlyCoreApps;
-    private final List<ScanPartition> mSystemPartitions;
 
     /**
      * Tracks new system packages [received in an OTA] that we expect to
@@ -88,34 +76,21 @@
      * are package location.
      */
     private final ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
-    /* Tracks of any system packages that no longer exist that needs to be pruned. */
-    private final List<String> mPossiblyDeletedUpdatedSystemApps = new ArrayList<>();
-    // Tracks of stub packages that must either be replaced with full versions in the /data
-    // partition or be disabled.
-    private final List<String> mStubSystemApps = new ArrayList<>();
 
     // TODO(b/198166813): remove PMS dependency
-    InitAppsHelper(PackageManagerService pm, ApexManager apexManager,
-            InstallPackageHelper installPackageHelper, PackageParser2 packageParser,
-            List<ScanPartition> systemPartitions) {
+    InitAndSystemPackageHelper(PackageManagerService pm) {
         mPm = pm;
-        mApexManager = apexManager;
-        mInstallPackageHelper = installPackageHelper;
-        mPackageParser = packageParser;
-        mSystemPartitions = systemPartitions;
+        mInstallPackageHelper = new InstallPackageHelper(pm);
         mDirsToScanAsSystem = getSystemScanPartitions();
-        mIsDeviceUpgrading = mPm.isDeviceUpgrading();
-        mIsOnlyCoreApps = mPm.isOnlyCoreApps();
         // Set flag to monitor and not change apk file paths when scanning install directories.
         int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
-        if (mIsDeviceUpgrading || mPm.isFirstBoot()) {
+        if (mPm.isDeviceUpgrading() || mPm.isFirstBoot()) {
             mScanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
         } else {
             mScanFlags = scanFlags;
         }
         mSystemParseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
         mSystemScanFlags = scanFlags | SCAN_AS_SYSTEM;
-        mExecutorService = ParallelPackageParser.makeExecutorService();
     }
 
     private List<File> getFrameworkResApkSplitFiles() {
@@ -143,7 +118,7 @@
 
     private List<ScanPartition> getSystemScanPartitions() {
         final List<ScanPartition> scanPartitions = new ArrayList<>();
-        scanPartitions.addAll(mSystemPartitions);
+        scanPartitions.addAll(mPm.mInjector.getSystemPartitions());
         scanPartitions.addAll(getApexScanPartitions());
         Slog.d(TAG, "Directories scanned as system partitions: " + scanPartitions);
         return scanPartitions;
@@ -151,7 +126,8 @@
 
     private List<ScanPartition> getApexScanPartitions() {
         final List<ScanPartition> scanPartitions = new ArrayList<>();
-        final List<ApexManager.ActiveApexInfo> activeApexInfos = mApexManager.getActiveApexInfos();
+        final List<ApexManager.ActiveApexInfo> activeApexInfos =
+                mPm.mApexManager.getActiveApexInfos();
         for (int i = 0; i < activeApexInfos.size(); i++) {
             final ScanPartition scanPartition = resolveApexToScanPartition(activeApexInfos.get(i));
             if (scanPartition != null) {
@@ -168,133 +144,117 @@
             if (apexInfo.preInstalledApexPath.getAbsolutePath().equals(
                     sp.getFolder().getAbsolutePath())
                     || apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
-                    sp.getFolder().getAbsolutePath() + File.separator)) {
+                        sp.getFolder().getAbsolutePath() + File.separator)) {
                 return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX);
             }
         }
         return null;
     }
 
-    /**
-     * Install apps from system dirs.
-     */
-    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
-    public OverlayConfig initSystemApps(WatchedArrayMap<String, PackageSetting> packageSettings,
-            int[] userIds, long startTime) {
+    public OverlayConfig initPackages(
+            WatchedArrayMap<String, PackageSetting> packageSettings, int[] userIds,
+            long startTime) {
+        PackageParser2 packageParser = mPm.mInjector.getScanningCachingPackageParser();
+
+        ExecutorService executorService = ParallelPackageParser.makeExecutorService();
         // Prepare apex package info before scanning APKs, this information is needed when
         // scanning apk in apex.
-        mApexManager.scanApexPackagesTraced(mPackageParser, mExecutorService);
+        mPm.mApexManager.scanApexPackagesTraced(packageParser, executorService);
 
-        scanSystemDirs(mPackageParser, mExecutorService);
+        scanSystemDirs(packageParser, executorService);
         // Parse overlay configuration files to set default enable state, mutability, and
         // priority of system overlays.
         final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>();
-        for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) {
-            for (String packageName : mApexManager.getApksInApex(apexInfo.apexModuleName)) {
+        for (ApexManager.ActiveApexInfo apexInfo : mPm.mApexManager.getActiveApexInfos()) {
+            for (String packageName : mPm.mApexManager.getApksInApex(apexInfo.apexModuleName)) {
                 apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath);
             }
         }
-        final OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
+        OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
                 consumer -> mPm.forEachPackage(
                         pkg -> consumer.accept(pkg, pkg.isSystem(),
-                                apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
+                          apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
+        // Prune any system packages that no longer exist.
+        final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
+        // Stub packages must either be replaced with full versions in the /data
+        // partition or be disabled.
+        final List<String> stubSystemApps = new ArrayList<>();
 
-        if (!mIsOnlyCoreApps) {
+        if (!mPm.isOnlyCoreApps()) {
             // do this first before mucking with mPackages for the "expecting better" case
-            updateStubSystemAppsList(mStubSystemApps);
+            updateStubSystemAppsList(stubSystemApps);
             mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings,
-                    mPossiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
+                    possiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
         }
 
-        logSystemAppsScanningTime(startTime);
-        return overlayConfig;
-    }
-
-    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
-    private void logSystemAppsScanningTime(long startTime) {
-        mCachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
+        final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
 
         // Remove any shared userIDs that have no associated packages
         mPm.mSettings.pruneSharedUsersLPw();
-        mSystemScanTime = SystemClock.uptimeMillis() - startTime;
-        mSystemPackagesCount = mPm.mPackages.size();
-        Slog.i(TAG, "Finished scanning system apps. Time: " + mSystemScanTime
-                + " ms, packageCount: " + mSystemPackagesCount
+        final long systemScanTime = SystemClock.uptimeMillis() - startTime;
+        final int systemPackagesCount = mPm.mPackages.size();
+        Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
+                + " ms, packageCount: " + systemPackagesCount
                 + " , timePerPackage: "
-                + (mSystemPackagesCount == 0 ? 0 : mSystemScanTime / mSystemPackagesCount)
-                + " , cached: " + mCachedSystemApps);
-        if (mIsDeviceUpgrading && mSystemPackagesCount > 0) {
+                + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
+                + " , cached: " + cachedSystemApps);
+        if (mPm.isDeviceUpgrading() && systemPackagesCount > 0) {
             //CHECKSTYLE:OFF IndentationCheck
             FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
                     BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
-                    mSystemScanTime / mSystemPackagesCount);
+                    systemScanTime / systemPackagesCount);
             //CHECKSTYLE:ON IndentationCheck
         }
-    }
 
-    /**
-     * Install apps/updates from data dir and fix system apps that are affected.
-     */
-    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
-    public void initNonSystemApps(@NonNull int[] userIds, long startTime) {
-        if (!mIsOnlyCoreApps) {
+        if (!mPm.isOnlyCoreApps()) {
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                     SystemClock.uptimeMillis());
             scanDirTracedLI(mPm.getAppInstallDir(), /* frameworkSplits= */ null, 0,
-                    mScanFlags | SCAN_REQUIRE_KNOWN,
-                    mPackageParser, mExecutorService);
+                    mScanFlags | SCAN_REQUIRE_KNOWN, 0,
+                    packageParser, executorService);
+
         }
 
-        List<Runnable> unfinishedTasks = mExecutorService.shutdownNow();
+        List<Runnable> unfinishedTasks = executorService.shutdownNow();
         if (!unfinishedTasks.isEmpty()) {
             throw new IllegalStateException("Not all tasks finished before calling close: "
                     + unfinishedTasks);
         }
-        if (!mIsOnlyCoreApps) {
-            fixSystemPackages(userIds);
-            logNonSystemAppScanningTime(startTime);
+
+        if (!mPm.isOnlyCoreApps()) {
+            mInstallPackageHelper.cleanupDisabledPackageSettings(possiblyDeletedUpdatedSystemApps,
+                    userIds, mScanFlags);
+            mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
+                    stubSystemApps, mSystemScanFlags, mSystemParseFlags);
+
+            // Uncompress and install any stubbed system applications.
+            // This must be done last to ensure all stubs are replaced or disabled.
+            mInstallPackageHelper.installSystemStubPackages(stubSystemApps, mScanFlags);
+
+            final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
+                    - cachedSystemApps;
+
+            final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
+            final int dataPackagesCount = mPm.mPackages.size() - systemPackagesCount;
+            Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
+                    + " ms, packageCount: " + dataPackagesCount
+                    + " , timePerPackage: "
+                    + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
+                    + " , cached: " + cachedNonSystemApps);
+            if (mPm.isDeviceUpgrading() && dataPackagesCount > 0) {
+                //CHECKSTYLE:OFF IndentationCheck
+                FrameworkStatsLog.write(
+                        FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+                        BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
+                        dataScanTime / dataPackagesCount);
+                //CHECKSTYLE:OFF IndentationCheck
+            }
         }
         mExpectingBetter.clear();
+
         mPm.mSettings.pruneRenamedPackagesLPw();
-        mPackageParser.close();
-    }
-
-    /**
-     * Clean up system packages now that some system package updates have been installed from
-     * the data dir. Also install system stub packages as the last step.
-     */
-    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
-    private void fixSystemPackages(@NonNull int[] userIds) {
-        mInstallPackageHelper.cleanupDisabledPackageSettings(mPossiblyDeletedUpdatedSystemApps,
-                userIds, mScanFlags);
-        mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
-                mStubSystemApps, mSystemScanFlags, mSystemParseFlags);
-
-        // Uncompress and install any stubbed system applications.
-        // This must be done last to ensure all stubs are replaced or disabled.
-        mInstallPackageHelper.installSystemStubPackages(mStubSystemApps, mScanFlags);
-    }
-
-    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
-    private void logNonSystemAppScanningTime(long startTime) {
-        final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
-                - mCachedSystemApps;
-
-        final long dataScanTime = SystemClock.uptimeMillis() - mSystemScanTime - startTime;
-        final int dataPackagesCount = mPm.mPackages.size() - mSystemPackagesCount;
-        Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
-                + " ms, packageCount: " + dataPackagesCount
-                + " , timePerPackage: "
-                + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
-                + " , cached: " + cachedNonSystemApps);
-        if (mIsDeviceUpgrading && dataPackagesCount > 0) {
-            //CHECKSTYLE:OFF IndentationCheck
-            FrameworkStatsLog.write(
-                    FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
-                    BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
-                    dataScanTime / dataPackagesCount);
-            //CHECKSTYLE:OFF IndentationCheck
-        }
+        packageParser.close();
+        return overlayConfig;
     }
 
     /**
@@ -314,14 +274,14 @@
                 continue;
             }
             scanDirTracedLI(partition.getOverlayFolder(), /* frameworkSplits= */ null,
-                    mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
+                    mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
                     packageParser, executorService);
         }
 
         List<File> frameworkSplits = getFrameworkResApkSplitFiles();
         scanDirTracedLI(frameworkDir, frameworkSplits,
                 mSystemParseFlags | PARSE_FRAMEWORK_RES_SPLITS,
-                mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,
+                mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
                 packageParser, executorService);
         if (!mPm.mPackages.containsKey("android")) {
             throw new IllegalStateException(
@@ -333,11 +293,11 @@
             if (partition.getPrivAppFolder() != null) {
                 scanDirTracedLI(partition.getPrivAppFolder(), /* frameworkSplits= */ null,
                         mSystemParseFlags,
-                        mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,
+                        mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
                         packageParser, executorService);
             }
             scanDirTracedLI(partition.getAppFolder(), /* frameworkSplits= */ null,
-                    mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
+                    mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
                     packageParser, executorService);
         }
     }
@@ -356,11 +316,11 @@
     @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
     private void scanDirTracedLI(File scanDir, List<File> frameworkSplits,
             final int parseFlags, int scanFlags,
-            PackageParser2 packageParser, ExecutorService executorService) {
+            long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
         try {
             mInstallPackageHelper.installPackagesFromDir(scanDir, frameworkSplits, parseFlags,
-                    scanFlags, packageParser, executorService);
+                    scanFlags, currentTime, packageParser, executorService);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 83c8472..336da2a 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -3030,7 +3030,7 @@
         final RemovePackageHelper removePackageHelper = new RemovePackageHelper(mPm);
         removePackageHelper.removePackageLI(stubPkg, true /*chatty*/);
         try {
-            return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, null);
+            return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
         } catch (PackageManagerException e) {
             Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
                     e);
@@ -3163,7 +3163,7 @@
                         | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
         @PackageManagerService.ScanFlags int scanFlags = mPm.getSystemPackageScanFlags(codePath);
         final AndroidPackage pkg = scanSystemPackageTracedLI(
-                codePath, parseFlags, scanFlags, null);
+                        codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
 
         PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
 
@@ -3338,7 +3338,7 @@
                 mRemovePackageHelper.removePackageLI(pkg, true);
                 try {
                     final File codePath = new File(pkg.getPath());
-                    scanSystemPackageTracedLI(codePath, 0, scanFlags, null);
+                    scanSystemPackageTracedLI(codePath, 0, scanFlags, 0, null);
                 } catch (PackageManagerException e) {
                     Slog.e(TAG, "Failed to parse updated, ex-system package: "
                             + e.getMessage());
@@ -3359,7 +3359,7 @@
 
     @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
     public void installPackagesFromDir(File scanDir, List<File> frameworkSplits, int parseFlags,
-            int scanFlags, PackageParser2 packageParser,
+            int scanFlags, long currentTime, PackageParser2 packageParser,
             ExecutorService executorService) {
         final File[] files = scanDir.listFiles();
         if (ArrayUtils.isEmpty(files)) {
@@ -3402,7 +3402,7 @@
                             parseResult.parsedPackage);
                 }
                 try {
-                    addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
+                    addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, currentTime,
                             null);
                 } catch (PackageManagerException e) {
                     errorCode = e.error;
@@ -3465,7 +3465,7 @@
 
             try {
                 final AndroidPackage newPkg = scanSystemPackageTracedLI(
-                        scanFile, reparseFlags, rescanFlags, null);
+                        scanFile, reparseFlags, rescanFlags, 0, null);
                 // We rescanned a stub, add it to the list of stubbed system packages
                 if (newPkg.isStub()) {
                     stubSystemApps.add(packageName);
@@ -3479,14 +3479,14 @@
 
     /**
      *  Traces a package scan.
-     *  @see #scanSystemPackageLI(File, int, int, UserHandle)
+     *  @see #scanSystemPackageLI(File, int, int, long, UserHandle)
      */
     @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
     public AndroidPackage scanSystemPackageTracedLI(File scanFile, final int parseFlags,
-            int scanFlags, UserHandle user) throws PackageManagerException {
+            int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
         try {
-            return scanSystemPackageLI(scanFile, parseFlags, scanFlags, user);
+            return scanSystemPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
@@ -3498,7 +3498,7 @@
      */
     @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
     private AndroidPackage scanSystemPackageLI(File scanFile, int parseFlags, int scanFlags,
-            UserHandle user) throws PackageManagerException {
+            long currentTime, UserHandle user) throws PackageManagerException {
         if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
@@ -3514,7 +3514,7 @@
             PackageManagerService.renameStaticSharedLibraryPackage(parsedPackage);
         }
 
-        return addForInitLI(parsedPackage, parseFlags, scanFlags, user);
+        return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
     }
 
     /**
@@ -3533,11 +3533,11 @@
     @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
     private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
             @ParsingPackageUtils.ParseFlags int parseFlags,
-            @PackageManagerService.ScanFlags int scanFlags,
+            @PackageManagerService.ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user) throws PackageManagerException {
 
         final Pair<ScanResult, Boolean> scanResultPair = scanSystemPackageLI(
-                parsedPackage, parseFlags, scanFlags, user);
+                parsedPackage, parseFlags, scanFlags, currentTime, user);
         final ScanResult scanResult = scanResultPair.first;
         boolean shouldHideSystemApp = scanResultPair.second;
         if (scanResult.mSuccess) {
@@ -3715,7 +3715,7 @@
 
     private Pair<ScanResult, Boolean> scanSystemPackageLI(ParsedPackage parsedPackage,
             @ParsingPackageUtils.ParseFlags int parseFlags,
-            @PackageManagerService.ScanFlags int scanFlags,
+            @PackageManagerService.ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user) throws PackageManagerException {
         final boolean scanSystemPartition =
                 (parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
@@ -3902,7 +3902,7 @@
         }
 
         final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags,
-                scanFlags | SCAN_UPDATE_SIGNATURE, 0 /* currentTime */, user, null);
+                scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
         return new Pair<>(scanResult, shouldHideSystemApp);
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9d95ead..ee5c638 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -247,6 +247,7 @@
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
 import com.android.server.storage.DeviceStorageMonitorInternal;
+import com.android.server.supplementalprocess.SupplementalProcessManagerLocal;
 import com.android.server.utils.SnapshotCache;
 import com.android.server.utils.TimingsTraceAndSlog;
 import com.android.server.utils.Watchable;
@@ -934,6 +935,7 @@
     final @Nullable String mOverlayConfigSignaturePackage;
     final @Nullable String mRecentsPackage;
     final @Nullable String mAmbientContextDetectionPackage;
+    private final @NonNull String mRequiredSupplementalProcessPackage;
 
     @GuardedBy("mLock")
     private final PackageUsage mPackageUsage = new PackageUsage();
@@ -944,7 +946,7 @@
     private final BroadcastHelper mBroadcastHelper;
     private final RemovePackageHelper mRemovePackageHelper;
     private final DeletePackageHelper mDeletePackageHelper;
-    private final InitAppsHelper mInitAppsHelper;
+    private final InitAndSystemPackageHelper mInitAndSystemPackageHelper;
     private final AppDataHelper mAppDataHelper;
     private final InstallPackageHelper mInstallPackageHelper;
     private final PreferredActivityHelper mPreferredActivityHelper;
@@ -1671,6 +1673,7 @@
         mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName;
         mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage;
         mResolveComponentName = testParams.resolveComponentName;
+        mRequiredSupplementalProcessPackage = testParams.requiredSupplementalProcessPackage;
 
         mLiveComputer = createLiveComputer();
         mSnapshotComputer = null;
@@ -1689,12 +1692,13 @@
         mAppDataHelper = testParams.appDataHelper;
         mInstallPackageHelper = testParams.installPackageHelper;
         mRemovePackageHelper = testParams.removePackageHelper;
-        mInitAppsHelper = testParams.initAndSystemPackageHelper;
+        mInitAndSystemPackageHelper = testParams.initAndSystemPackageHelper;
         mDeletePackageHelper = testParams.deletePackageHelper;
         mPreferredActivityHelper = testParams.preferredActivityHelper;
         mResolveIntentHelper = testParams.resolveIntentHelper;
         mDexOptHelper = testParams.dexOptHelper;
         mSuspendPackageHelper = testParams.suspendPackageHelper;
+
         mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
 
         registerObservers(false);
@@ -1836,8 +1840,7 @@
         mAppDataHelper = new AppDataHelper(this);
         mInstallPackageHelper = new InstallPackageHelper(this, mAppDataHelper);
         mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
-        mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
-                mInjector.getScanningCachingPackageParser(), mInjector.getSystemPartitions());
+        mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this);
         mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
                 mAppDataHelper);
         mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
@@ -1967,8 +1970,8 @@
                     mIsEngBuild, mIsUserDebugBuild, mIncrementalVersion);
 
             final int[] userIds = mUserManager.getUserIds();
-            mOverlayConfig = mInitAppsHelper.initSystemApps(packageSettings, userIds, startTime);
-            mInitAppsHelper.initNonSystemApps(userIds, startTime);
+            mOverlayConfig = mInitAndSystemPackageHelper.initPackages(packageSettings,
+                    userIds, startTime);
 
             // Resolve the storage manager.
             mStorageManagerPackage = getStorageManagerPackageName();
@@ -2139,6 +2142,9 @@
                     getPackageInfo(mRequiredPermissionControllerPackage, 0,
                             UserHandle.USER_SYSTEM).getLongVersionCode());
 
+            // Resolve the supplemental process
+            mRequiredSupplementalProcessPackage = getRequiredSupplementalProcessPackageName();
+
             // Initialize InstantAppRegistry's Instant App list for all users.
             for (AndroidPackage pkg : mPackages.values()) {
                 if (pkg.isSystem()) {
@@ -3154,6 +3160,11 @@
         throw new IllegalStateException("PermissionController is not found");
     }
 
+    @Override
+    public String getSupplementalProcessPackageName() {
+        return mRequiredSupplementalProcessPackage;
+    }
+
     String getPackageInstallerPackageName() {
         return mRequiredInstallerPackage;
     }
@@ -5519,6 +5530,24 @@
         }
     }
 
+    private @NonNull String getRequiredSupplementalProcessPackageName() {
+        final Intent intent = new Intent(SupplementalProcessManagerLocal.SERVICE_INTERFACE);
+
+        final List<ResolveInfo> matches = queryIntentServicesInternal(
+                intent,
+                /* resolvedType= */ null,
+                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+                UserHandle.USER_SYSTEM,
+                /* callingUid= */ Process.myUid(),
+                /* includeInstantApps= */ false);
+        if (matches.size() == 1) {
+            return matches.get(0).getComponentInfo().packageName;
+        } else {
+            throw new RuntimeException("There should exactly one supplemental process; found "
+                    + matches.size() + ": matches=" + matches);
+        }
+    }
+
     @Override
     public String getDefaultTextClassifierPackageName() {
         return ensureSystemPackageName(
@@ -8677,7 +8706,7 @@
     }
 
     boolean isExpectingBetter(String packageName) {
-        return mInitAppsHelper.isExpectingBetter(packageName);
+        return mInitAndSystemPackageHelper.isExpectingBetter(packageName);
     }
 
     int getDefParseFlags() {
@@ -8780,12 +8809,13 @@
     }
 
     boolean isOverlayMutable(String packageName) {
-        return mOverlayConfig.isMutable(packageName);
+        return (mOverlayConfig != null ? mOverlayConfig
+                : OverlayConfig.getSystemInstance()).isMutable(packageName);
     }
 
     @ScanFlags int getSystemPackageScanFlags(File codePath) {
         List<ScanPartition> dirsToScanAsSystem =
-                mInitAppsHelper.getDirsToScanAsSystem();
+                mInitAndSystemPackageHelper.getDirsToScanAsSystem();
         @PackageManagerService.ScanFlags int scanFlags = SCAN_AS_SYSTEM;
         for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
             ScanPartition partition = dirsToScanAsSystem.get(i);
@@ -8803,7 +8833,7 @@
     Pair<Integer, Integer> getSystemPackageRescanFlagsAndReparseFlags(File scanFile,
             int systemScanFlags, int systemParseFlags) {
         List<ScanPartition> dirsToScanAsSystem =
-                mInitAppsHelper.getDirsToScanAsSystem();
+                mInitAndSystemPackageHelper.getDirsToScanAsSystem();
         @ParsingPackageUtils.ParseFlags int reparseFlags = 0;
         @PackageManagerService.ScanFlags int rescanFlags = 0;
         for (int i1 = dirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index 00ca4ae..d12c826 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -89,6 +89,7 @@
     public @Nullable String defaultTextClassifierPackage;
     public @Nullable String systemTextClassifierPackage;
     public @Nullable String overlayConfigSignaturePackage;
+    public @NonNull String requiredSupplementalProcessPackage;
     public ViewCompiler viewCompiler;
     public @Nullable String retailDemoPackage;
     public @Nullable String recentsPackage;
@@ -108,7 +109,7 @@
     public AppDataHelper appDataHelper;
     public InstallPackageHelper installPackageHelper;
     public RemovePackageHelper removePackageHelper;
-    public InitAppsHelper initAndSystemPackageHelper;
+    public InitAndSystemPackageHelper initAndSystemPackageHelper;
     public DeletePackageHelper deletePackageHelper;
     public PreferredActivityHelper preferredActivityHelper;
     public ResolveIntentHelper resolveIntentHelper;
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index 1372098..bb7e55a 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -32,6 +32,7 @@
 import android.content.pm.PackagePartitions;
 import android.content.pm.UserInfo;
 import android.content.pm.VersionedPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.UserHandle;
@@ -47,7 +48,6 @@
 import com.android.internal.policy.AttributeCache;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -150,7 +150,7 @@
                 final AndroidPackage pkg;
                 try {
                     pkg = installPackageHelper.scanSystemPackageTracedLI(
-                            ps.getPath(), parseFlags, SCAN_INITIAL, null);
+                            ps.getPath(), parseFlags, SCAN_INITIAL, 0, null);
                     loaded.add(pkg);
 
                 } catch (PackageManagerException e) {
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 06ce4a4..1dea3d7 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -71,6 +71,7 @@
     private static final int MSG_ESCROW_TOKEN_STATE = 9;
     private static final int MSG_UNLOCK_USER = 10;
     private static final int MSG_SHOW_KEYGUARD_ERROR_MESSAGE = 11;
+    private static final int MSG_LOCK_USER = 12;
 
     /**
      * Time in uptime millis that we wait for the service connection, both when starting
@@ -100,6 +101,8 @@
 
     // Trust state
     private boolean mTrusted;
+    private boolean mWaitingForTrustableDowngrade = false;
+    private boolean mTrustable;
     private CharSequence mMessage;
     private boolean mDisplayTrustGrantedMessage;
     private boolean mTrustDisabledByDpm;
@@ -108,6 +111,25 @@
     private AlarmManager mAlarmManager;
     private final Intent mAlarmIntent;
     private PendingIntent mAlarmPendingIntent;
+    private final BroadcastReceiver mTrustableDowngradeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!TrustManagerService.ENABLE_ACTIVE_UNLOCK_FLAG) {
+                return;
+            }
+            if (!mWaitingForTrustableDowngrade) {
+                return;
+            }
+            // are these the broadcasts we want to listen to
+            if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())
+                    || Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
+                mTrusted = false;
+                mTrustable = true;
+                mWaitingForTrustableDowngrade = false;
+                mTrustManagerService.updateTrust(mUserId, 0);
+            }
+        }
+    };
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -126,16 +148,21 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_GRANT_TRUST:
-                    // TODO(b/213631675): Respect FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE
                     if (!isConnected()) {
                         Log.w(TAG, "Agent is not connected, cannot grant trust: "
                                 + mName.flattenToShortString());
                         return;
                     }
                     mTrusted = true;
+                    mTrustable = false;
                     mMessage = (CharSequence) msg.obj;
                     int flags = msg.arg1;
                     mDisplayTrustGrantedMessage = (flags & FLAG_GRANT_TRUST_DISPLAY_MESSAGE) != 0;
+                    if ((flags & TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0) {
+                        mWaitingForTrustableDowngrade = true;
+                    } else {
+                        mWaitingForTrustableDowngrade = false;
+                    }
                     long durationMs = msg.getData().getLong(DATA_DURATION);
                     if (durationMs > 0) {
                         final long duration;
@@ -270,6 +297,13 @@
                     mTrustManagerService.showKeyguardErrorMessage(message);
                     break;
                 }
+                case MSG_LOCK_USER: {
+                    mTrusted = false;
+                    mTrustable = false;
+                    mTrustManagerService.updateTrust(mUserId, 0 /* flags */);
+                    mTrustManagerService.lockUser(mUserId);
+                    break;
+                }
             }
         }
     };
@@ -295,6 +329,11 @@
         }
 
         @Override
+        public void lockUser() {
+            mHandler.sendEmptyMessage(MSG_LOCK_USER);
+        }
+
+        @Override
         public void setManagingTrust(boolean managingTrust) {
             if (DEBUG) Slog.d(TAG, "managingTrust()");
             mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget();
@@ -427,6 +466,9 @@
         final String pathUri = mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME);
         alarmFilter.addDataPath(pathUri, PatternMatcher.PATTERN_LITERAL);
 
+        IntentFilter trustableFilter = new IntentFilter(Intent.ACTION_USER_PRESENT);
+        trustableFilter.addAction(Intent.ACTION_SCREEN_OFF);
+
         // Schedules a restart for when connecting times out. If the connection succeeds,
         // the restart is canceled in mCallback's onConnected.
         scheduleRestart();
@@ -435,6 +477,7 @@
         if (mBound) {
             mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null,
                     Context.RECEIVER_EXPORTED);
+            mContext.registerReceiver(mTrustableDowngradeReceiver, trustableFilter);
         } else {
             Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString());
         }
@@ -591,6 +634,10 @@
         return mTrusted && mManagingTrust && !mTrustDisabledByDpm;
     }
 
+    public boolean isTrustable() {
+        return mTrustable && mManagingTrust && !mTrustDisabledByDpm;
+    }
+
     public boolean isManagingTrust() {
         return mManagingTrust && !mTrustDisabledByDpm;
     }
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 52f7d10..6aafd4a 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -54,6 +54,7 @@
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -65,6 +66,7 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.Xml;
 import android.view.IWindowManager;
@@ -122,8 +124,7 @@
     private static final int MSG_DISPATCH_UNLOCK_LOCKOUT = 13;
     private static final int MSG_REFRESH_DEVICE_LOCKED_FOR_USER = 14;
     private static final int MSG_SCHEDULE_TRUST_TIMEOUT = 15;
-    private static final int MSG_USER_REQUESTED_UNLOCK = 16;
-    private static final int MSG_ENABLE_TRUST_AGENT = 17;
+    public static final int MSG_USER_REQUESTED_UNLOCK = 16;
 
     private static final String REFRESH_DEVICE_LOCKED_EXCEPT_USER = "except";
 
@@ -146,6 +147,21 @@
     @GuardedBy("mUserIsTrusted")
     private final SparseBooleanArray mUserIsTrusted = new SparseBooleanArray();
 
+    //TODO(b/215724686): remove flag
+    public static final boolean ENABLE_ACTIVE_UNLOCK_FLAG = SystemProperties.getBoolean(
+            "fw.enable_active_unlock_flag", true);
+
+    private enum TrustState {
+        UNTRUSTED, // the phone is not unlocked by any trustagents
+        TRUSTABLE, // the phone is in a semi-locked state that can be unlocked if
+        // FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE is passed and a trustagent is trusted
+        TRUSTED // the phone is unlocked
+    };
+
+    @GuardedBy("mUserTrustState")
+    private final SparseArray<TrustManagerService.TrustState> mUserTrustState =
+            new SparseArray<>();
+
     /**
      * Stores the locked state for users on the device. There are three different type of users
      * which are handled slightly differently:
@@ -229,7 +245,6 @@
     }
 
     // Extend unlock config and logic
-
     private final class SettingsObserver extends ContentObserver {
         private final Uri TRUST_AGENTS_EXTEND_UNLOCK =
                 Settings.Secure.getUriFor(Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK);
@@ -397,6 +412,14 @@
     }
 
     private void updateTrust(int userId, int flags, boolean isFromUnlock) {
+        if (ENABLE_ACTIVE_UNLOCK_FLAG) {
+            updateTrustWithRenewableUnlock(userId, flags, isFromUnlock);
+        } else {
+            updateTrustWithExtendUnlock(userId, flags, isFromUnlock);
+        }
+    }
+
+    private void updateTrustWithExtendUnlock(int userId, int flags, boolean isFromUnlock) {
         boolean managed = aggregateIsTrustManaged(userId);
         dispatchOnTrustManagedChanged(managed, userId);
         if (mStrongAuthTracker.isTrustAllowedForUser(userId)
@@ -442,6 +465,65 @@
         }
     }
 
+    private void updateTrustWithRenewableUnlock(int userId, int flags, boolean isFromUnlock) {
+        boolean managed = aggregateIsTrustManaged(userId);
+        dispatchOnTrustManagedChanged(managed, userId);
+        if (mStrongAuthTracker.isTrustAllowedForUser(userId)
+                && isTrustUsuallyManagedInternal(userId) != managed) {
+            updateTrustUsuallyManaged(userId, managed);
+        }
+
+        boolean trustedByAtLeastOneAgent = aggregateIsTrusted(userId);
+        boolean trustableByAtLeastOneAgent = aggregateIsTrustable(userId);
+        boolean wasTrusted;
+        boolean wasTrustable;
+        TrustState pendingTrustState;
+
+        IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+        boolean alreadyUnlocked = false;
+        try {
+            alreadyUnlocked = !wm.isKeyguardLocked();
+        } catch (RemoteException e) {
+        }
+
+        synchronized (mUserTrustState) {
+            wasTrusted = (mUserTrustState.get(userId) == TrustState.TRUSTED);
+            wasTrustable = (mUserTrustState.get(userId) == TrustState.TRUSTABLE);
+            boolean renewingTrust = wasTrustable && (
+                    (flags & TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0);
+            boolean canMoveToTrusted = alreadyUnlocked || isFromUnlock || renewingTrust;
+            boolean upgradingTrustForCurrentUser = (userId == mCurrentUser);
+
+            if (trustedByAtLeastOneAgent && wasTrusted) {
+                // no change
+                return;
+            } else if (trustedByAtLeastOneAgent && canMoveToTrusted
+                    && upgradingTrustForCurrentUser) {
+                pendingTrustState = TrustState.TRUSTED;
+            } else if (trustableByAtLeastOneAgent && (wasTrusted || wasTrustable)
+                    && upgradingTrustForCurrentUser) {
+                pendingTrustState = TrustState.TRUSTABLE;
+            } else {
+                pendingTrustState = TrustState.UNTRUSTED;
+            }
+
+            mUserTrustState.put(userId, pendingTrustState);
+        }
+        if (DEBUG) Slog.d(TAG, "pendingTrustState: " + pendingTrustState);
+
+        boolean isNowTrusted = pendingTrustState == TrustState.TRUSTED;
+        dispatchOnTrustChanged(isNowTrusted, userId, flags, getTrustGrantedMessages(userId));
+        if (isNowTrusted != wasTrusted) {
+            refreshDeviceLockedForUser(userId);
+            if (!isNowTrusted) {
+                maybeLockScreen(userId);
+            } else {
+                scheduleTrustTimeout(userId, false /* override */);
+            }
+        }
+    }
+
+
     private void updateTrustUsuallyManaged(int userId, boolean managed) {
         synchronized (mTrustUsuallyManagedForUser) {
             mTrustUsuallyManagedForUser.put(userId, managed);
@@ -473,6 +555,20 @@
         mLockPatternUtils.unlockUserWithToken(handle, token, userId);
     }
 
+    /**
+     * Locks the phone and requires some auth (not trust) like a biometric or passcode before
+     * unlocking.
+     */
+    public void lockUser(int userId) {
+        mLockPatternUtils.requireStrongAuth(
+                StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
+        try {
+            WindowManagerGlobal.getWindowManagerService().lockNow(null);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Error locking screen when called from trust agent");
+        }
+    }
+
     void showKeyguardErrorMessage(CharSequence message) {
         dispatchOnTrustError(message);
     }
@@ -632,24 +728,6 @@
         }
     }
 
-
-    /**
-     * Uses {@link LockPatternUtils} to enable the setting for trust agent in the specified
-     * component name. This should only be used for testing.
-     */
-    private void enableTrustAgentForUserForTest(@NonNull ComponentName componentName, int userId) {
-        Log.i(TAG,
-                "Enabling trust agent " + componentName.flattenToString() + " for user " + userId);
-        List<ComponentName> agents =
-                new ArrayList<>(mLockPatternUtils.getEnabledTrustAgents(userId));
-        if (!agents.contains(componentName)) {
-            agents.add(componentName);
-        }
-        // Even if the agent was already there, we still call setEnabledTrustAgents to trigger a
-        // refresh of installed agents.
-        mLockPatternUtils.setEnabledTrustAgents(agents, userId);
-    }
-
     boolean isDeviceLockedInner(int userId) {
         synchronized (mDeviceLockedForUser) {
             return mDeviceLockedForUser.get(userId, true);
@@ -948,7 +1026,6 @@
                 continue;
             }
             allowedAgents.add(resolveInfo);
-            if (DEBUG) Slog.d(TAG, "Adding agent " + getComponentName(resolveInfo));
         }
         return allowedAgents;
     }
@@ -970,6 +1047,21 @@
         return false;
     }
 
+    private boolean aggregateIsTrustable(int userId) {
+        if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
+            return false;
+        }
+        for (int i = 0; i < mActiveAgents.size(); i++) {
+            AgentInfo info = mActiveAgents.valueAt(i);
+            if (info.userId == userId) {
+                if (info.agent.isTrustable()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     private List<String> getTrustGrantedMessages(int userId) {
         if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
             return new ArrayList<>();
@@ -1178,13 +1270,6 @@
         }
 
         @Override
-        public void enableTrustAgentForUserForTest(ComponentName componentName, int userId)
-                throws RemoteException {
-            enforceReportPermission();
-            mHandler.obtainMessage(MSG_ENABLE_TRUST_AGENT, userId, 0, componentName).sendToTarget();
-        }
-
-        @Override
         public void reportKeyguardShowingChanged() throws RemoteException {
             enforceReportPermission();
             // coalesce refresh messages.
@@ -1460,9 +1545,6 @@
                     // This is also called when the security mode of a user changes.
                     refreshDeviceLockedForUser(UserHandle.USER_ALL);
                     break;
-                case MSG_ENABLE_TRUST_AGENT:
-                    enableTrustAgentForUserForTest((ComponentName) msg.obj, msg.arg1);
-                    break;
                 case MSG_KEYGUARD_SHOWING_CHANGED:
                     refreshDeviceLockedForUser(mCurrentUser);
                     break;
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index f91969b..1f0fdcf 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -24,6 +24,7 @@
 import static com.android.server.wm.WindowManagerService.H.ON_POINTER_DOWN_OUTSIDE_FOCUS;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.graphics.PointF;
 import android.os.Debug;
 import android.os.IBinder;
@@ -254,6 +255,25 @@
         }
     }
 
+    @Override
+    @Nullable
+    public SurfaceControl createSurfaceForGestureMonitor(String name, int displayId) {
+        synchronized (mService.mGlobalLock) {
+            final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+            if (dc == null) {
+                Slog.e(TAG, "Failed to create a gesture monitor on display: " + displayId
+                        + " - DisplayContent not found.");
+                return null;
+            }
+            return mService.makeSurfaceBuilder(dc.getSession())
+                    .setContainerLayer()
+                    .setName(name)
+                    .setCallsite("createSurfaceForGestureMonitor")
+                    .setParent(dc.getSurfaceControl())
+                    .build();
+        }
+    }
+
     /** Waits until the built-in input devices have been configured. */
     public boolean waitForInputDevicesReady(long timeoutMillis) {
         synchronized (mInputDevicesReadyMonitor) {
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 10776ab..1e12173 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -32,6 +32,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityTaskManager;
 import android.app.StatusBarManager;
 import android.graphics.Insets;
 import android.graphics.Rect;
@@ -134,7 +135,7 @@
 
     /** Updates the target which can control system bars. */
     void updateBarControlTarget(@Nullable WindowState focusedWin) {
-        if (mFocusedWin != focusedWin){
+        if (mFocusedWin != focusedWin) {
             abortTransient();
         }
         mFocusedWin = focusedWin;
@@ -156,7 +157,7 @@
     }
 
     boolean isHidden(@InternalInsetsType int type) {
-        final InsetsSourceProvider provider =  mStateController.peekSourceProvider(type);
+        final InsetsSourceProvider provider = mStateController.peekSourceProvider(type);
         return provider != null && provider.hasWindow() && !provider.getSource().isVisible();
     }
 
@@ -181,6 +182,10 @@
                         mShowingTransientTypes.toArray(), isGestureOnSystemBar);
             }
             updateBarControlTarget(mFocusedWin);
+            dispatchTransientSystemBarsVisibilityChanged(
+                    mFocusedWin,
+                    isTransient(ITYPE_STATUS_BAR) || isTransient(ITYPE_NAVIGATION_BAR),
+                    isGestureOnSystemBar);
 
             // The leashes can be created while updating bar control target. The surface transaction
             // of the new leashes might not be applied yet. The callback posted here ensures we can
@@ -198,6 +203,12 @@
         if (mShowingTransientTypes.size() == 0) {
             return;
         }
+
+        dispatchTransientSystemBarsVisibilityChanged(
+                mFocusedWin,
+                /* areVisible= */ false,
+                /* wereRevealedFromSwipeOnSystemBar= */ false);
+
         startAnimation(false /* show */, () -> {
             synchronized (mDisplayContent.mWmService.mGlobalLock) {
                 for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
@@ -373,6 +384,11 @@
                     mDisplayContent.getDisplayId(), mShowingTransientTypes.toArray());
         }
         mShowingTransientTypes.clear();
+
+        dispatchTransientSystemBarsVisibilityChanged(
+                mFocusedWin,
+                /* areVisible= */ false,
+                /* wereRevealedFromSwipeOnSystemBar= */ false);
     }
 
     private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin,
@@ -521,6 +537,32 @@
         listener.mControlCallbacks.controlAnimationUnchecked(typesReady, controls, show);
     }
 
+    private void dispatchTransientSystemBarsVisibilityChanged(
+            @Nullable WindowState focusedWindow,
+            boolean areVisible,
+            boolean wereRevealedFromSwipeOnSystemBar) {
+        if (focusedWindow == null) {
+            return;
+        }
+
+        Task task = focusedWindow.getTask();
+        if (task == null) {
+            return;
+        }
+
+        int taskId = task.mTaskId;
+        boolean isValidTaskId = taskId != ActivityTaskManager.INVALID_TASK_ID;
+        if (!isValidTaskId) {
+            return;
+        }
+
+        mDisplayContent.mWmService.mTaskSystemBarsListenerController
+                .dispatchTransientSystemBarVisibilityChanged(
+                        taskId,
+                        areVisible,
+                        wereRevealedFromSwipeOnSystemBar);
+    }
+
     private class BarWindow {
 
         private final int mId;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 76a7981..ee03d02 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -981,6 +981,29 @@
             mWmService.checkDrawnWindowsLocked();
         }
 
+        final int N = mWmService.mPendingRemove.size();
+        if (N > 0) {
+            if (mWmService.mPendingRemoveTmp.length < N) {
+                mWmService.mPendingRemoveTmp = new WindowState[N + 10];
+            }
+            mWmService.mPendingRemove.toArray(mWmService.mPendingRemoveTmp);
+            mWmService.mPendingRemove.clear();
+            ArrayList<DisplayContent> displayList = new ArrayList();
+            for (i = 0; i < N; i++) {
+                final WindowState w = mWmService.mPendingRemoveTmp[i];
+                w.removeImmediately();
+                final DisplayContent displayContent = w.getDisplayContent();
+                if (displayContent != null && !displayList.contains(displayContent)) {
+                    displayList.add(displayContent);
+                }
+            }
+
+            for (int j = displayList.size() - 1; j >= 0; --j) {
+                final DisplayContent dc = displayList.get(j);
+                dc.assignWindowLayers(true /*setLayoutNeeded*/);
+            }
+        }
+
         forAllDisplays(dc -> {
             dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
             dc.updateSystemGestureExclusion();
diff --git a/services/core/java/com/android/server/wm/TaskSystemBarsListenerController.java b/services/core/java/com/android/server/wm/TaskSystemBarsListenerController.java
new file mode 100644
index 0000000..acb6061
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskSystemBarsListenerController.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import com.android.internal.os.BackgroundThread;
+import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
+
+import java.util.HashSet;
+import java.util.concurrent.Executor;
+
+/**
+ * Manages dispatch of task system bar changes to interested listeners. All invocations must be
+ * performed while the {@link WindowManagerService#getWindowManagerLock() Window Manager Lock} is
+ * held.
+ */
+final class TaskSystemBarsListenerController {
+
+    private final HashSet<TaskSystemBarsListener> mListeners = new HashSet<>();
+    private final Executor mBackgroundExecutor;
+
+    TaskSystemBarsListenerController() {
+        this.mBackgroundExecutor = BackgroundThread.getExecutor();
+    }
+
+    void registerListener(TaskSystemBarsListener listener) {
+        mListeners.add(listener);
+    }
+
+    void unregisterListener(TaskSystemBarsListener listener) {
+        mListeners.remove(listener);
+    }
+
+    void dispatchTransientSystemBarVisibilityChanged(
+            int taskId,
+            boolean visible,
+            boolean wereRevealedFromSwipeOnSystemBar) {
+        HashSet<TaskSystemBarsListener> localListeners;
+        localListeners = new HashSet<>(mListeners);
+
+        mBackgroundExecutor.execute(() -> {
+            for (TaskSystemBarsListener listener : localListeners) {
+                listener.onTransientSystemBarsVisibilityChanged(
+                        taskId,
+                        visible,
+                        wereRevealedFromSwipeOnSystemBar);
+            }
+        });
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 20fa7a9..4900f929 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -256,6 +256,25 @@
     }
 
     /**
+     * An interface to be notified when the system bars for a task change.
+     */
+    public interface TaskSystemBarsListener {
+
+        /**
+         * Called when the visibility of the system bars of a task change.
+         *
+         * @param taskId the identifier of the task.
+         * @param visible if the transient system bars are visible.
+         * @param wereRevealedFromSwipeOnSystemBar if the transient bars were revealed due to a
+         *                                         swipe gesture on a system bar.
+         */
+        void onTransientSystemBarsVisibilityChanged(
+                int taskId,
+                boolean visible,
+                boolean wereRevealedFromSwipeOnSystemBar);
+    }
+
+    /**
      * An interface to be notified when keyguard exit animation should start.
      */
     public interface KeyguardExitAnimationStartListener {
@@ -519,6 +538,20 @@
     public abstract void registerAppTransitionListener(AppTransitionListener listener);
 
     /**
+     * Registers a listener to be notified to when the system bars of a task changes.
+     *
+     * @param listener The listener to register.
+     */
+    public abstract void registerTaskSystemBarsListener(TaskSystemBarsListener listener);
+
+    /**
+     * Registers a listener to be notified to when the system bars of a task changes.
+     *
+     * @param listener The listener to unregister.
+     */
+    public abstract void unregisterTaskSystemBarsListener(TaskSystemBarsListener listener);
+
+    /**
      * Registers a listener to be notified to start the keyguard exit animation.
      *
      * @param listener The listener to register.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b37cb4f..1167cb5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -222,6 +222,7 @@
 import android.util.EventLog;
 import android.util.MergedConfiguration;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.TimeUtils;
 import android.util.TypedValue;
@@ -586,6 +587,20 @@
     final ArrayList<WindowState> mResizingWindows = new ArrayList<>();
 
     /**
+     * Windows whose animations have ended and now must be removed.
+     */
+    final ArrayList<WindowState> mPendingRemove = new ArrayList<>();
+
+    /**
+     * Used when processing mPendingRemove to avoid working on the original array.
+     */
+    WindowState[] mPendingRemoveTmp = new WindowState[20];
+
+    // TODO: use WindowProcessController once go/wm-unified is done.
+    /** Mapping of process pids to configurations */
+    final SparseArray<Configuration> mProcessConfigurations = new SparseArray<>();
+
+    /**
      * Mapping of displayId to {@link DisplayImePolicy}.
      * Note that this can be accessed without holding the lock.
      */
@@ -683,6 +698,7 @@
             () -> mDisplayRotationController = null;
 
     final DisplayWindowListenerController mDisplayNotificationController;
+    final TaskSystemBarsListenerController mTaskSystemBarsListenerController;
 
     boolean mDisplayFrozen = false;
     long mDisplayFreezeTime = 0;
@@ -1265,6 +1281,7 @@
         mScreenFrozenLock.setReferenceCounted(false);
 
         mDisplayNotificationController = new DisplayWindowListenerController(this);
+        mTaskSystemBarsListenerController = new TaskSystemBarsListenerController();
 
         mActivityManager = ActivityManager.getService();
         mActivityTaskManager = ActivityTaskManager.getService();
@@ -2036,6 +2053,7 @@
             dc.mWinRemovedSinceNullFocus.add(win);
         }
         mEmbeddedWindowController.onWindowRemoved(win);
+        mPendingRemove.remove(win);
         mResizingWindows.remove(win);
         updateNonSystemOverlayWindowsVisibilityIfNeeded(win, false /* surfaceShown */);
         mWindowsChanged = true;
@@ -6364,6 +6382,23 @@
                 }
             }
         }
+        if (mPendingRemove.size() > 0) {
+            pw.println();
+            pw.println("  Remove pending for:");
+            for (int i=mPendingRemove.size()-1; i>=0; i--) {
+                WindowState w = mPendingRemove.get(i);
+                if (windows == null || windows.contains(w)) {
+                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
+                            pw.print(w);
+                    if (dumpAll) {
+                        pw.println(":");
+                        w.dump(pw, "    ", true);
+                    } else {
+                        pw.println();
+                    }
+                }
+            }
+        }
         if (mForceRemoves != null && mForceRemoves.size() > 0) {
             pw.println();
             pw.println("  Windows force removing:");
@@ -7591,6 +7626,20 @@
         }
 
         @Override
+        public void registerTaskSystemBarsListener(TaskSystemBarsListener listener) {
+            synchronized (mGlobalLock) {
+                mTaskSystemBarsListenerController.registerListener(listener);
+            }
+        }
+
+        @Override
+        public void unregisterTaskSystemBarsListener(TaskSystemBarsListener listener) {
+            synchronized (mGlobalLock) {
+                mTaskSystemBarsListenerController.unregisterListener(listener);
+            }
+        }
+
+        @Override
         public void registerKeyguardExitAnimationStartListener(
                 KeyguardExitAnimationStartListener listener) {
             synchronized (mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0a02b44..79c64b1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4887,20 +4887,15 @@
             if (hasSurface) {
                 mWmService.mDestroySurface.add(this);
             }
+            if (mRemoveOnExit) {
+                mWmService.mPendingRemove.add(this);
+                mRemoveOnExit = false;
+            }
         }
         mAnimatingExit = false;
         getDisplayContent().mWallpaperController.hideWallpapers(this);
     }
 
-    @Override
-    boolean handleCompleteDeferredRemoval() {
-        if (mRemoveOnExit) {
-            mRemoveOnExit = false;
-            removeImmediately();
-        }
-        return super.handleCompleteDeferredRemoval();
-    }
-
     boolean clearAnimatingFlags() {
         boolean didSomething = false;
         // We don't want to clear it out for windows that get replaced, because the
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 161d7ce..166a0f5 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -244,6 +244,9 @@
     return hasLatLong(location.v1_0);
 }
 
+bool isSvStatusRegistered = false;
+bool isNmeaRegistered = false;
+
 }  // namespace
 
 static inline jboolean boolToJbool(bool value) {
@@ -505,6 +508,13 @@
 
 template <class T_list, class T_sv_info>
 Return<void> GnssCallback::gnssSvStatusCbImpl(const T_list& svStatus) {
+    // In HIDL or AIDL v1, if no listener is registered, do not report svInfoList to the framework.
+    if (gnssHalAidl == nullptr || gnssHalAidl->getInterfaceVersion() == 1) {
+        if (!isSvStatusRegistered) {
+            return Void();
+        }
+    }
+
     JNIEnv* env = getJniEnv();
 
     uint32_t listSize = getGnssSvInfoListSize(svStatus);
@@ -566,8 +576,12 @@
     return Void();
 }
 
-Return<void> GnssCallback::gnssNmeaCb(
-    int64_t timestamp, const ::android::hardware::hidl_string& nmea) {
+Return<void> GnssCallback::gnssNmeaCb(int64_t timestamp,
+                                      const ::android::hardware::hidl_string& nmea) {
+    // In HIDL, if no listener is registered, do not report nmea to the framework.
+    if (!isNmeaRegistered) {
+        return Void();
+    }
     JNIEnv* env = getJniEnv();
     /*
      * The Java code will call back to read these values.
@@ -680,6 +694,12 @@
 }
 
 Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
+    // In AIDL v1, if no listener is registered, do not report nmea to the framework.
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() == 1) {
+        if (!isNmeaRegistered) {
+            return Status::ok();
+        }
+    }
     JNIEnv* env = getJniEnv();
     /*
      * The Java code will call back to read these values.
@@ -1562,6 +1582,58 @@
     return checkHidlReturn(result, "IGnss stop() failed.");
 }
 
+static jboolean android_location_gnss_hal_GnssNative_start_sv_status_collection(JNIEnv* /* env */,
+                                                                                jclass) {
+    isSvStatusRegistered = true;
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+        auto status = gnssHalAidl->startSvStatus();
+        return checkAidlStatus(status, "IGnssAidl startSvStatus() failed.");
+    }
+    if (gnssHal == nullptr) {
+        return JNI_FALSE;
+    }
+    return JNI_TRUE;
+}
+
+static jboolean android_location_gnss_hal_GnssNative_stop_sv_status_collection(JNIEnv* /* env */,
+                                                                               jclass) {
+    isSvStatusRegistered = false;
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+        auto status = gnssHalAidl->stopSvStatus();
+        return checkAidlStatus(status, "IGnssAidl stopSvStatus() failed.");
+    }
+    if (gnssHal == nullptr) {
+        return JNI_FALSE;
+    }
+    return JNI_TRUE;
+}
+
+static jboolean android_location_gnss_hal_GnssNative_start_nmea_message_collection(
+        JNIEnv* /* env */, jclass) {
+    isNmeaRegistered = true;
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+        auto status = gnssHalAidl->startNmea();
+        return checkAidlStatus(status, "IGnssAidl startNmea() failed.");
+    }
+    if (gnssHal == nullptr) {
+        return JNI_FALSE;
+    }
+    return JNI_TRUE;
+}
+
+static jboolean android_location_gnss_hal_GnssNative_stop_nmea_message_collection(JNIEnv* /* env */,
+                                                                                  jclass) {
+    isNmeaRegistered = false;
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+        auto status = gnssHalAidl->stopNmea();
+        return checkAidlStatus(status, "IGnssAidl stopNmea() failed.");
+    }
+    if (gnssHal == nullptr) {
+        return JNI_FALSE;
+    }
+    return JNI_TRUE;
+}
+
 static void android_location_gnss_hal_GnssNative_delete_aiding_data(JNIEnv* /* env */, jclass,
                                                                     jint flags) {
     if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
@@ -1989,7 +2061,7 @@
     jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
     jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
     uint16_t corrFlags = static_cast<uint16_t>(correctionFlags);
-    jobject reflectingPlaneObj;
+    jobject reflectingPlaneObj = nullptr;
     bool has_ref_plane = (corrFlags & GnssSingleSatCorrectionFlags::HAS_REFLECTING_PLANE) != 0;
     if (has_ref_plane) {
         reflectingPlaneObj =
@@ -2013,6 +2085,7 @@
                 .azimuthDegrees = azimuthDegreeRefPlane,
         };
     }
+    env->DeleteLocalRef(reflectingPlaneObj);
 
     SingleSatCorrection_V1_0 singleSatCorrection = {
             .singleSatCorrectionFlags = corrFlags,
@@ -2044,6 +2117,7 @@
         };
 
         list[i] = singleSatCorrection_1_1;
+        env->DeleteLocalRef(singleSatCorrectionObj);
     }
 }
 
@@ -2061,6 +2135,7 @@
         singleSatCorrection.constellation = static_cast<GnssConstellationType_V1_0>(constType),
 
         list[i] = singleSatCorrection;
+        env->DeleteLocalRef(singleSatCorrectionObj);
     }
 }
 
@@ -2131,6 +2206,7 @@
 
     hidl_vec<SingleSatCorrection_V1_0> list(len);
     getSingleSatCorrectionList_1_0(env, singleSatCorrectionList, list);
+    env->DeleteLocalRef(singleSatCorrectionList);
     measurementCorrections_1_0.satCorrections = list;
 
     auto result = gnssCorrectionsIface_V1_0->setCorrections(measurementCorrections_1_0);
@@ -2365,6 +2441,16 @@
         {"native_is_gnss_visibility_control_supported", "()Z",
          reinterpret_cast<void*>(
                  android_location_gnss_hal_GnssNative_is_gnss_visibility_control_supported)},
+        {"native_start_sv_status_collection", "()Z",
+         reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_start_sv_status_collection)},
+        {"native_stop_sv_status_collection", "()Z",
+         reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_stop_sv_status_collection)},
+        {"native_start_nmea_message_collection", "()Z",
+         reinterpret_cast<void*>(
+                 android_location_gnss_hal_GnssNative_start_nmea_message_collection)},
+        {"native_stop_nmea_message_collection", "()Z",
+         reinterpret_cast<void*>(
+                 android_location_gnss_hal_GnssNative_stop_nmea_message_collection)},
 };
 
 static const JNINativeMethod sBatchingMethods[] = {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ce937d2..e34178a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -18515,9 +18515,10 @@
         final CallerIdentity caller = getCallerIdentity();
         Preconditions.checkCallAuthorization(
                 isDefaultDeviceOwner(caller) || isProfileOwnerOfOrganizationOwnedDevice(caller)
-                        || isSystemUid(caller),
+                        || canQueryAdminPolicy(caller),
                 "SSID allowlist can only be retrieved by a device owner or "
-                        + "a profile owner on an organization-owned device or a system app.");
+                        + "a profile owner on an organization-owned device or "
+                        + "an app with the QUERY_ADMIN_POLICY permission.");
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(
                     UserHandle.USER_SYSTEM);
@@ -18553,9 +18554,10 @@
         final CallerIdentity caller = getCallerIdentity();
         Preconditions.checkCallAuthorization(
                 isDefaultDeviceOwner(caller) || isProfileOwnerOfOrganizationOwnedDevice(caller)
-                        || isSystemUid(caller),
+                        || canQueryAdminPolicy(caller),
                 "SSID denylist can only be retrieved by a device owner or "
-                        + "a profile owner on an organization-owned device or a system app.");
+                        + "a profile owner on an organization-owned device or "
+                        + "an app with the QUERY_ADMIN_POLICY permission.");
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(
                     UserHandle.USER_SYSTEM);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c9aeabd..d0c861f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -366,6 +366,8 @@
             "com.android.server.adb.AdbService$Lifecycle";
     private static final String SPEECH_RECOGNITION_MANAGER_SERVICE_CLASS =
             "com.android.server.speech.SpeechRecognitionManagerService";
+    private static final String WALLPAPER_EFFECTS_GENERATION_MANAGER_SERVICE_CLASS =
+            "com.android.server.wallpapereffectsgeneration.WallpaperEffectsGenerationManagerService";
     private static final String APP_PREDICTION_MANAGER_SERVICE_CLASS =
             "com.android.server.appprediction.AppPredictionManagerService";
     private static final String CONTENT_SUGGESTIONS_SERVICE_CLASS =
@@ -1895,7 +1897,6 @@
             }
             t.traceEnd();
 
-
             t.traceBegin("StartIpSecService");
             try {
                 ipSecService = IpSecService.create(context);
@@ -2126,6 +2127,14 @@
                 Slog.i(TAG, "Wallpaper service disabled by config");
             }
 
+            // WallpaperEffectsGeneration manager service
+            // TODO (b/135218095): Use deviceHasConfigString(context,
+            //  R.string.config_defaultWallpaperEffectsGenerationService)
+            t.traceBegin("StartWallpaperEffectsGenerationService");
+            mSystemServiceManager.startService(
+                    WALLPAPER_EFFECTS_GENERATION_MANAGER_SERVICE_CLASS);
+            t.traceEnd();
+
             t.traceBegin("StartAudioService");
             if (!isArc) {
                 mSystemServiceManager.startService(AudioService.Lifecycle.class);
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 9e221be..75669d5 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -52,6 +52,7 @@
         "service-blobstore",
         "service-jobscheduler",
         "service-permission.impl",
+        "service-supplementalprocess.impl",
         "services.core",
         "services.devicepolicy",
         "services.net",
diff --git a/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_disabled.xml b/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_disabled.xml
new file mode 100644
index 0000000..eb15451
--- /dev/null
+++ b/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_disabled.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<game-mode-config
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:supportsPerformanceGameMode="false"
+    android:supportsBatteryGameMode="false"
+    android:allowGameAngleDriver="false"
+    android:allowGameDownscaling="false"
+    android:allowGameFpsOverride="false"
+/>
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_enabled.xml b/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_enabled.xml
new file mode 100644
index 0000000..65b7467
--- /dev/null
+++ b/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_enabled.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<game-mode-config
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:supportsPerformanceGameMode="false"
+    android:supportsBatteryGameMode="false"
+    android:allowGameAngleDriver="true"
+    android:allowGameDownscaling="true"
+    android:allowGameFpsOverride="true"
+/>
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java b/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java
index fec9b12..e89c812 100644
--- a/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java
+++ b/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java
@@ -359,6 +359,34 @@
                 LifecycleTrackingGameSession.LifecycleMethodCall.ON_DESTROY).inOrder();
     }
 
+    @Test
+    public void dispatchTransientVisibilityChanged_valueUnchanged_doesNotInvokeCallback() {
+        mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(false);
+
+        assertThat(mGameSession.mCapturedTransientSystemBarVisibilityFromRevealGestures).hasSize(0);
+    }
+
+    @Test
+    public void dispatchTransientVisibilityChanged_valueChanged_invokesCallback() {
+        mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(true);
+
+        assertThat(mGameSession.mCapturedTransientSystemBarVisibilityFromRevealGestures)
+                .containsExactly(true).inOrder();
+    }
+
+    @Test
+    public void dispatchTransientVisibilityChanged_manyTimes_invokesCallbackWhenValueChanges() {
+        mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(false);
+        mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(true);
+        mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(false);
+        mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(false);
+        mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(true);
+        mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(true);
+
+        assertThat(mGameSession.mCapturedTransientSystemBarVisibilityFromRevealGestures)
+                .containsExactly(true, false, true).inOrder();
+    }
+
     private static class LifecycleTrackingGameSession extends GameSession {
         private enum LifecycleMethodCall {
             ON_CREATE,
@@ -368,6 +396,8 @@
         }
 
         final List<LifecycleMethodCall> mLifecycleMethodCalls = new ArrayList<>();
+        final List<Boolean> mCapturedTransientSystemBarVisibilityFromRevealGestures =
+                new ArrayList<>();
 
         @Override
         public void onCreate() {
@@ -387,5 +417,11 @@
                 mLifecycleMethodCalls.add(LifecycleMethodCall.ON_GAME_TASK_UNFOCUSED);
             }
         }
+
+        @Override
+        public void onTransientSystemBarVisibilityFromRevealGestureChanged(
+                boolean visibleDueToGesture) {
+            mCapturedTransientSystemBarVisibilityFromRevealGestures.add(visibleDueToGesture);
+        }
     }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index eed2d42..d2358a0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -23,20 +23,32 @@
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.Manifest;
 import android.app.GameManager;
 import android.app.GameModeInfo;
+import android.app.GameState;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.hardware.power.Mode;
 import android.os.Bundle;
+import android.os.PowerManagerInternal;
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
 import android.provider.DeviceConfig;
@@ -46,6 +58,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.LocalServices;
 import com.android.server.SystemService;
 
 import org.junit.After;
@@ -76,6 +89,8 @@
     private TestLooper mTestLooper;
     @Mock
     private PackageManager mMockPackageManager;
+    @Mock
+    private PowerManagerInternal mMockPowerManager;
 
     // Stolen from ConnectivityServiceTest.MockContext
     class MockContext extends ContextWrapper {
@@ -149,19 +164,27 @@
         mPackageName = mMockContext.getPackageName();
         final ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.category = ApplicationInfo.CATEGORY_GAME;
+        applicationInfo.packageName = mPackageName;
         final PackageInfo pi = new PackageInfo();
         pi.packageName = mPackageName;
         pi.applicationInfo = applicationInfo;
         final List<PackageInfo> packages = new ArrayList<>();
         packages.add(pi);
+
+        final Resources resources =
+                InstrumentationRegistry.getInstrumentation().getContext().getResources();
+        when(mMockPackageManager.getResourcesForApplication(anyString()))
+                .thenReturn(resources);
         when(mMockPackageManager.getInstalledPackagesAsUser(anyInt(), anyInt()))
                 .thenReturn(packages);
         when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
                 .thenReturn(applicationInfo);
+        LocalServices.addService(PowerManagerInternal.class, mMockPowerManager);
     }
 
     @After
     public void tearDown() throws Exception {
+        LocalServices.removeServiceForTest(PowerManagerInternal.class);
         GameManagerService gameManagerService = new GameManagerService(mMockContext);
         gameManagerService.disableCompatScale(mPackageName);
         if (mMockingSession != null) {
@@ -310,6 +333,46 @@
                 .thenReturn(applicationInfo);
     }
 
+    private void mockInterventionsEnabledFromXml() throws Exception {
+        final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
+                mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
+        Bundle metaDataBundle = new Bundle();
+        final int resId = 123;
+        metaDataBundle.putInt(
+                GameManagerService.GamePackageConfiguration.METADATA_GAME_MODE_CONFIG, resId);
+        applicationInfo.metaData = metaDataBundle;
+        when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+                .thenReturn(applicationInfo);
+        seedGameManagerServiceMetaDataFromFile(mPackageName, resId,
+                "res/xml/gama_manager_service_metadata_config_enabled.xml");
+    }
+
+    private void mockInterventionsDisabledFromXml() throws Exception {
+        final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
+                mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
+        Bundle metaDataBundle = new Bundle();
+        final int resId = 123;
+        metaDataBundle.putInt(
+                GameManagerService.GamePackageConfiguration.METADATA_GAME_MODE_CONFIG, resId);
+        applicationInfo.metaData = metaDataBundle;
+        when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+                .thenReturn(applicationInfo);
+        seedGameManagerServiceMetaDataFromFile(mPackageName, resId,
+                "res/xml/gama_manager_service_metadata_config_disabled.xml");
+    }
+
+
+    private void seedGameManagerServiceMetaDataFromFile(String packageName, int resId,
+            String fileName)
+            throws Exception {
+        AssetManager assetManager =
+                InstrumentationRegistry.getInstrumentation().getContext().getAssets();
+        XmlResourceParser xmlResourceParser =
+                assetManager.openXmlResourceParser(fileName);
+        when(mMockPackageManager.getXml(eq(packageName), eq(resId), any()))
+                .thenReturn(xmlResourceParser);
+    }
+
     /**
      * By default game mode is not supported.
      */
@@ -499,8 +562,8 @@
                 gameManagerService.getConfig(mPackageName);
         assertEquals(config.getGameModeConfiguration(gameMode).getUseAngle(), angleEnabled);
 
-        // Validate GameManagerService.getAngleEnabled() returns the correct value.
-        assertEquals(gameManagerService.getAngleEnabled(mPackageName, USER_ID_1), angleEnabled);
+        // Validate GameManagerService.isAngleEnabled() returns the correct value.
+        assertEquals(gameManagerService.isAngleEnabled(mPackageName, USER_ID_1), angleEnabled);
     }
 
     private void checkFps(GameManagerService gameManagerService, int gameMode, int fps) {
@@ -511,7 +574,7 @@
         }
         GameManagerService.GamePackageConfiguration config =
                 gameManagerService.getConfig(mPackageName);
-        assertEquals(config.getGameModeConfiguration(gameMode).getFps(), fps);
+        assertEquals(fps, config.getGameModeConfiguration(gameMode).getFps());
     }
 
     /**
@@ -893,6 +956,36 @@
     }
 
     @Test
+    public void testGameModeConfigAllowFpsTrue() throws Exception {
+        mockDeviceConfigAll();
+        mockModifyGameModeGranted();
+        mockInterventionsEnabledFromXml();
+        GameManagerService gameManagerService = new GameManagerService(mMockContext,
+                mTestLooper.getLooper());
+        startUser(gameManagerService, USER_ID_1);
+        GameManagerService.GamePackageConfiguration config =
+                gameManagerService.getConfig(mPackageName);
+        assertEquals(90,
+                config.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE).getFps());
+        assertEquals(30, config.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY).getFps());
+    }
+
+    @Test
+    public void testGameModeConfigAllowFpsFalse() throws Exception {
+        mockDeviceConfigAll();
+        mockModifyGameModeGranted();
+        mockInterventionsDisabledFromXml();
+        GameManagerService gameManagerService = new GameManagerService(mMockContext,
+                mTestLooper.getLooper());
+        startUser(gameManagerService, USER_ID_1);
+        GameManagerService.GamePackageConfiguration config =
+                gameManagerService.getConfig(mPackageName);
+        assertEquals(0,
+                config.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE).getFps());
+        assertEquals(0, config.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY).getFps());
+    }
+
+    @Test
     public void testInterventionFps() throws Exception {
         mockDeviceConfigAll();
         mockModifyGameModeGranted();
@@ -1052,4 +1145,41 @@
         assertEquals(GameManager.GAME_MODE_UNSUPPORTED, gameModeInfo.getActiveGameMode());
         assertEquals(0, gameModeInfo.getAvailableGameModes().length);
     }
+
+    @Test
+    public void testGameStateLoadingRequiresPerformanceMode() {
+        mockDeviceConfigNone();
+        mockModifyGameModeGranted();
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
+        startUser(gameManagerService, USER_ID_1);
+        GameState gameState = new GameState(true, GameState.MODE_NONE);
+        gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
+        mTestLooper.dispatchAll();
+        verify(mMockPowerManager, never()).setPowerMode(anyInt(), anyBoolean());
+    }
+
+    private void setGameState(boolean isLoading) {
+        mockDeviceConfigNone();
+        mockModifyGameModeGranted();
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
+        startUser(gameManagerService, USER_ID_1);
+        gameManagerService.setGameMode(
+                mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+        GameState gameState = new GameState(isLoading, GameState.MODE_NONE);
+        gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
+        mTestLooper.dispatchAll();
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, isLoading);
+    }
+
+    @Test
+    public void testSetGameStateLoading() {
+        setGameState(true);
+    }
+
+    @Test
+    public void testSetGameStateNotLoading() {
+        setGameState(false);
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
index 317a51b..08de62b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
@@ -31,7 +31,6 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.Manifest;
@@ -72,6 +71,7 @@
 import com.android.internal.util.FunctionalUtils.ThrowingConsumer;
 import com.android.internal.util.Preconditions;
 import com.android.server.wm.WindowManagerInternal;
+import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
 import com.android.server.wm.WindowManagerService;
 
 import org.junit.After;
@@ -112,6 +112,7 @@
     private static final ComponentName GAME_B_MAIN_ACTIVITY =
             new ComponentName(GAME_B_PACKAGE, "com.package.game.b.MainActivity");
 
+
     private static final Bitmap TEST_BITMAP = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888);
 
     private MockitoSession mMockingSession;
@@ -131,6 +132,7 @@
     private FakeGameSessionService mFakeGameSessionService;
     private FakeServiceConnector<IGameSessionService> mFakeGameSessionServiceConnector;
     private ArrayList<ITaskStackListener> mTaskStackListeners;
+    private ArrayList<TaskSystemBarsListener> mTaskSystemBarsListeners;
     private ArrayList<RunningTaskInfo> mRunningTaskInfos;
 
     @Mock
@@ -159,15 +161,25 @@
             mTaskStackListeners.add(invocation.getArgument(0));
             return null;
         }).when(mMockActivityTaskManager).registerTaskStackListener(any());
+        doAnswer(invocation -> {
+            mTaskStackListeners.remove(invocation.getArgument(0));
+            return null;
+        }).when(mMockActivityTaskManager).unregisterTaskStackListener(any());
+
+        mTaskSystemBarsListeners = new ArrayList<>();
+        doAnswer(invocation -> {
+            mTaskSystemBarsListeners.add(invocation.getArgument(0));
+            return null;
+        }).when(mMockWindowManagerInternal).registerTaskSystemBarsListener(any());
+        doAnswer(invocation -> {
+            mTaskSystemBarsListeners.remove(invocation.getArgument(0));
+            return null;
+        }).when(mMockWindowManagerInternal).unregisterTaskSystemBarsListener(any());
 
         mRunningTaskInfos = new ArrayList<>();
         when(mMockActivityTaskManager.getTasks(anyInt(), anyBoolean(), anyBoolean())).thenReturn(
                 mRunningTaskInfos);
 
-        doAnswer(invocation -> {
-            mTaskStackListeners.remove(invocation.getArgument(0));
-            return null;
-        }).when(mMockActivityTaskManager).unregisterTaskStackListener(any());
 
         mGameServiceProviderInstance = new GameServiceProviderInstanceImpl(
                 new UserHandle(USER_ID),
@@ -394,7 +406,60 @@
                 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
 
         verify(mMockWindowManagerInternal).addTaskOverlay(eq(10), eq(mockSurfacePackage10));
-        verifyNoMoreInteractions(mMockWindowManagerInternal);
+    }
+
+    @Test
+    public void taskSystemBarsListenerChanged_noAssociatedGameSession_doesNothing() {
+        mGameServiceProviderInstance.start();
+
+        dispatchTaskSystemBarsEvent(taskSystemBarsListener -> {
+            taskSystemBarsListener.onTransientSystemBarsVisibilityChanged(
+                    10,
+                    /* areVisible= */ false,
+                    /* wereRevealedFromSwipeOnSystemBar= */ false);
+        });
+    }
+
+    @Test
+    public void systemBarsTransientShownDueToGesture_hasGameSession_propagatesToGameSession() {
+        mGameServiceProviderInstance.start();
+        startTask(10, GAME_A_MAIN_ACTIVITY);
+        mFakeGameService.requestCreateGameSession(10);
+
+        FakeGameSession gameSession10 = new FakeGameSession();
+        SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+        mFakeGameSessionService.removePendingFutureForTaskId(10)
+                .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+
+        dispatchTaskSystemBarsEvent(taskSystemBarsListener -> {
+            taskSystemBarsListener.onTransientSystemBarsVisibilityChanged(
+                    10,
+                    /* areVisible= */ true,
+                    /* wereRevealedFromSwipeOnSystemBar= */ true);
+        });
+
+        assertThat(gameSession10.mAreTransientSystemBarsVisibleFromRevealGesture).isTrue();
+    }
+
+    @Test
+    public void systemBarsTransientShownButNotGesture_hasGameSession_notPropagatedToGameSession() {
+        mGameServiceProviderInstance.start();
+        startTask(10, GAME_A_MAIN_ACTIVITY);
+        mFakeGameService.requestCreateGameSession(10);
+
+        FakeGameSession gameSession10 = new FakeGameSession();
+        SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+        mFakeGameSessionService.removePendingFutureForTaskId(10)
+                .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+
+        dispatchTaskSystemBarsEvent(taskSystemBarsListener -> {
+            taskSystemBarsListener.onTransientSystemBarsVisibilityChanged(
+                    10,
+                    /* areVisible= */ true,
+                    /* wereRevealedFromSwipeOnSystemBar= */ false);
+        });
+
+        assertThat(gameSession10.mAreTransientSystemBarsVisibleFromRevealGesture).isFalse();
     }
 
     @Test
@@ -492,7 +557,6 @@
 
         verify(mMockWindowManagerInternal).addTaskOverlay(eq(10), eq(mockSurfacePackage10));
         verify(mMockWindowManagerInternal).removeTaskOverlay(eq(10), eq(mockSurfacePackage10));
-        verifyNoMoreInteractions(mMockWindowManagerInternal);
     }
 
     @Test
@@ -830,6 +894,13 @@
         mMockContext.setPermission(permission, PackageManager.PERMISSION_DENIED);
     }
 
+    private void dispatchTaskSystemBarsEvent(
+            ThrowingConsumer<TaskSystemBarsListener> taskSystemBarsListenerConsumer) {
+        for (TaskSystemBarsListener listener : mTaskSystemBarsListeners) {
+            taskSystemBarsListenerConsumer.accept(listener);
+        }
+    }
+
     static final class FakeGameService extends IGameService.Stub {
         private IGameServiceController mGameServiceController;
 
@@ -944,6 +1015,7 @@
     private static class FakeGameSession extends IGameSession.Stub {
         boolean mIsDestroyed = false;
         boolean mIsFocused = false;
+        boolean mAreTransientSystemBarsVisibleFromRevealGesture = false;
 
         @Override
         public void onDestroyed() {
@@ -954,6 +1026,11 @@
         public void onTaskFocusChanged(boolean focused) {
             mIsFocused = focused;
         }
+
+        @Override
+        public void onTransientSystemBarVisibilityFromRevealGestureChanged(boolean areVisible) {
+            mAreTransientSystemBarsVisibleFromRevealGesture = areVisible;
+        }
     }
 
     private final class MockContext extends ContextWrapper {
@@ -1005,5 +1082,4 @@
             return mLastStartedIntent;
         }
     }
-
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 6ae0031..4ec1641 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -69,6 +69,7 @@
 import com.android.server.pm.pkg.parsing.ParsingPackage
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
+import com.android.server.supplementalprocess.SupplementalProcessManagerLocal
 import com.android.server.testutils.TestHandler
 import com.android.server.testutils.mock
 import com.android.server.testutils.nullable
@@ -335,6 +336,7 @@
         stageServicesExtensionScan()
         stageSystemSharedLibraryScan()
         stagePermissionsControllerScan()
+        stageSupplementalProcessScan()
         stageInstantAppResolverScan()
     }
 
@@ -569,6 +571,22 @@
     }
 
     @Throws(Exception::class)
+    private fun stageSupplementalProcessScan() {
+        stageScanNewPackage("com.android.supplemental.process",
+                1L, systemPartitions[0].privAppFolder,
+                withPackage = { pkg: PackageImpl ->
+                    val applicationInfo: ApplicationInfo = createBasicApplicationInfo(pkg)
+                    mockQueryServices(SupplementalProcessManagerLocal.SERVICE_INTERFACE,
+                            createBasicServiceInfo(
+                                    pkg, applicationInfo, "SupplementalProcessService"))
+                    pkg
+                },
+                withSetting = { setting: PackageSettingBuilder ->
+                    setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+                })
+    }
+
+    @Throws(Exception::class)
     private fun stageSystemSharedLibraryScan() {
         stageScanNewPackage("android.ext.shared",
                 1L, systemPartitions[0].appFolder,
diff --git a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
index 9ee1205..3890d4d 100644
--- a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
@@ -24,14 +24,20 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static junit.framework.Assert.fail;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.attention.AttentionManagerInternal.AttentionCallbackInternal;
+import android.attention.AttentionManagerInternal.ProximityCallbackInternal;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.IBinder;
@@ -42,6 +48,7 @@
 import android.provider.DeviceConfig;
 import android.service.attention.IAttentionCallback;
 import android.service.attention.IAttentionService;
+import android.service.attention.IProximityCallback;
 
 import androidx.test.filters.SmallTest;
 
@@ -49,6 +56,7 @@
 import com.android.server.attention.AttentionManagerService.AttentionCheckCache;
 import com.android.server.attention.AttentionManagerService.AttentionCheckCacheBuffer;
 import com.android.server.attention.AttentionManagerService.AttentionHandler;
+import com.android.server.attention.AttentionManagerService.ProximityUpdate;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -59,10 +67,13 @@
 /**
  * Tests for {@link com.android.server.attention.AttentionManagerService}
  */
+@SuppressWarnings("GuardedBy")
 @SmallTest
 public class AttentionManagerServiceTest {
+    private static final double PROXIMITY_SUCCESS_STATE = 1.0;
     private AttentionManagerService mSpyAttentionManager;
     private final int mTimeout = 1000;
+    private final Object mLock = new Object();
     @Mock
     private AttentionCallbackInternal mMockAttentionCallbackInternal;
     @Mock
@@ -73,6 +84,8 @@
     private IThermalService mMockIThermalService;
     @Mock
     Context mContext;
+    @Mock
+    private ProximityCallbackInternal mMockProximityCallbackInternal;
 
     @Before
     public void setUp() throws RemoteException {
@@ -84,7 +97,6 @@
         doReturn(true).when(mMockIPowerManager).isInteractive();
         mPowerManager = new PowerManager(mContext, mMockIPowerManager, mMockIThermalService, null);
 
-        Object mLock = new Object();
         // setup a spy on attention manager
         AttentionManagerService attentionManager = new AttentionManagerService(
                 mContext,
@@ -100,6 +112,119 @@
                 mSpyAttentionManager);
         mSpyAttentionManager.mCurrentAttentionCheck = attentionCheck;
         mSpyAttentionManager.mService = new MockIAttentionService();
+        doNothing().when(mSpyAttentionManager).freeIfInactiveLocked();
+    }
+
+    @Test
+    public void testRegisterProximityUpdates_returnFalseWhenServiceDisabled() {
+        mSpyAttentionManager.mIsServiceEnabled = false;
+
+        assertThat(mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal))
+                .isFalse();
+    }
+
+    @Test
+    public void testRegisterProximityUpdates_returnFalseWhenServiceUnavailable() {
+        mSpyAttentionManager.mIsServiceEnabled = true;
+        doReturn(false).when(mSpyAttentionManager).isServiceAvailable();
+
+        assertThat(mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal))
+                .isFalse();
+    }
+
+    @Test
+    public void testRegisterProximityUpdates_returnFalseWhenPowerManagerNotInteract()
+            throws RemoteException {
+        mSpyAttentionManager.mIsServiceEnabled = true;
+        doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
+        doReturn(false).when(mMockIPowerManager).isInteractive();
+
+        assertThat(mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal))
+                .isFalse();
+    }
+
+    @Test
+    public void testRegisterProximityUpdates_callOnSuccess() throws RemoteException {
+        mSpyAttentionManager.mIsServiceEnabled = true;
+        doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
+        doReturn(true).when(mMockIPowerManager).isInteractive();
+
+        assertThat(mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal))
+                .isTrue();
+        verify(mMockProximityCallbackInternal, times(1))
+                .onProximityUpdate(PROXIMITY_SUCCESS_STATE);
+    }
+
+    @Test
+    public void testRegisterProximityUpdates_callOnSuccessTwiceInARow() throws RemoteException {
+        mSpyAttentionManager.mIsServiceEnabled = true;
+        doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
+        doReturn(true).when(mMockIPowerManager).isInteractive();
+
+        assertThat(mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal))
+                .isTrue();
+
+        ProximityUpdate prevProximityUpdate = mSpyAttentionManager.mCurrentProximityUpdate;
+        assertThat(mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal))
+                .isTrue();
+        assertThat(mSpyAttentionManager.mCurrentProximityUpdate).isEqualTo(prevProximityUpdate);
+        verify(mMockProximityCallbackInternal, times(1))
+                .onProximityUpdate(PROXIMITY_SUCCESS_STATE);
+    }
+
+    @Test
+    public void testUnregisterProximityUpdates_noCrashWhenNoCallbackIsRegistered() {
+        mSpyAttentionManager.onStopProximityUpdates(mMockProximityCallbackInternal);
+        verifyZeroInteractions(mMockProximityCallbackInternal);
+    }
+
+    @Test
+    public void testUnregisterProximityUpdates_noCrashWhenCallbackMismatched()
+            throws RemoteException {
+        mSpyAttentionManager.mIsServiceEnabled = true;
+        doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
+        doReturn(true).when(mMockIPowerManager).isInteractive();
+        mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal);
+        verify(mMockProximityCallbackInternal, times(1))
+                .onProximityUpdate(PROXIMITY_SUCCESS_STATE);
+
+        ProximityCallbackInternal mismatchedCallback = new ProximityCallbackInternal() {
+            @Override
+            public void onProximityUpdate(double distance) {
+                fail("Callback shouldn't have responded.");
+            }
+        };
+        mSpyAttentionManager.onStopProximityUpdates(mismatchedCallback);
+
+        verifyNoMoreInteractions(mMockProximityCallbackInternal);
+    }
+
+    @Test
+    public void testUnregisterProximityUpdates_cancelRegistrationWhenMatched()
+            throws RemoteException {
+        mSpyAttentionManager.mIsServiceEnabled = true;
+        doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
+        doReturn(true).when(mMockIPowerManager).isInteractive();
+        mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal);
+        mSpyAttentionManager.onStopProximityUpdates(mMockProximityCallbackInternal);
+
+        assertThat(mSpyAttentionManager.mCurrentProximityUpdate).isNull();
+    }
+
+    @Test
+    public void testUnregisterProximityUpdates_noCrashWhenTwiceInARow() throws RemoteException {
+        // Attention Service registers proximity updates.
+        mSpyAttentionManager.mIsServiceEnabled = true;
+        doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
+        doReturn(true).when(mMockIPowerManager).isInteractive();
+        mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal);
+        verify(mMockProximityCallbackInternal, times(1))
+                .onProximityUpdate(PROXIMITY_SUCCESS_STATE);
+
+        // Attention Service unregisters the proximity update twice in a row.
+        mSpyAttentionManager.onStopProximityUpdates(mMockProximityCallbackInternal);
+        mSpyAttentionManager.onStopProximityUpdates(mMockProximityCallbackInternal);
+        verifyNoMoreInteractions(mMockProximityCallbackInternal);
     }
 
     @Test
@@ -127,7 +252,6 @@
         mSpyAttentionManager.mIsServiceEnabled = true;
         doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
         doReturn(true).when(mMockIPowerManager).isInteractive();
-        doNothing().when(mSpyAttentionManager).freeIfInactiveLocked();
         mSpyAttentionManager.mCurrentAttentionCheck = null;
 
         AttentionCallbackInternal callback = Mockito.mock(AttentionCallbackInternal.class);
@@ -213,6 +337,13 @@
         public void cancelAttentionCheck(IAttentionCallback callback) {
         }
 
+        public void onStartProximityUpdates(IProximityCallback callback) throws RemoteException {
+            callback.onProximityUpdate(PROXIMITY_SUCCESS_STATE);
+        }
+
+        public void onStopProximityUpdates() throws RemoteException {
+        }
+
         public IBinder asBinder() {
             return null;
         }
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 4caa85c..f5a5689 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -81,6 +81,7 @@
     @Mock HysteresisLevels mScreenBrightnessThresholds;
     @Mock Handler mNoOpHandler;
     @Mock HighBrightnessModeController mHbmController;
+    @Mock BrightnessThrottler mBrightnessThrottler;
 
     @Before
     public void setUp() {
@@ -128,12 +129,15 @@
                 INITIAL_LIGHT_SENSOR_RATE, BRIGHTENING_LIGHT_DEBOUNCE_CONFIG,
                 DARKENING_LIGHT_DEBOUNCE_CONFIG, RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG,
                 mAmbientBrightnessThresholds, mScreenBrightnessThresholds,
-                mContext, mHbmController, mIdleBrightnessMappingStrategy,
+                mContext, mHbmController, mBrightnessThrottler, mIdleBrightnessMappingStrategy,
                 AMBIENT_LIGHT_HORIZON_SHORT, AMBIENT_LIGHT_HORIZON_LONG
         );
 
         when(mHbmController.getCurrentBrightnessMax()).thenReturn(BRIGHTNESS_MAX_FLOAT);
         when(mHbmController.getCurrentBrightnessMin()).thenReturn(BRIGHTNESS_MIN_FLOAT);
+        // Disable brightness throttling by default. Individual tests can enable it as needed.
+        when(mBrightnessThrottler.getBrightnessCap()).thenReturn(BRIGHTNESS_MAX_FLOAT);
+        when(mBrightnessThrottler.isThrottled()).thenReturn(false);
 
         // Configure the brightness controller and grab an instance of the sensor listener,
         // through which we can deliver fake (for test) sensor values.
@@ -420,4 +424,47 @@
         assertEquals(600f, hysteresisLevels.getBrighteningThreshold(500f), EPSILON);
         assertEquals(250f, hysteresisLevels.getDarkeningThreshold(500f), EPSILON);
     }
+
+    @Test
+    public void testBrightnessGetsThrottled() throws Exception {
+        Sensor lightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor");
+        mController = setupController(lightSensor);
+
+        ArgumentCaptor<SensorEventListener> listenerCaptor =
+                ArgumentCaptor.forClass(SensorEventListener.class);
+        verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(lightSensor),
+                eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+        SensorEventListener listener = listenerCaptor.getValue();
+
+        // Set up system to return max brightness at 100 lux
+        final float normalizedBrightness = BRIGHTNESS_MAX_FLOAT;
+        final float lux = 100.0f;
+        when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux))
+                .thenReturn(lux);
+        when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux))
+                .thenReturn(lux);
+        when(mBrightnessMappingStrategy.getBrightness(eq(lux), eq(null), anyInt()))
+                .thenReturn(normalizedBrightness);
+
+        // Sensor reads 100 lux. We should get max brightness.
+        listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux));
+        assertEquals(BRIGHTNESS_MAX_FLOAT, mController.getAutomaticScreenBrightness(), 0.0f);
+
+        // Apply throttling and notify ABC (simulates DisplayPowerController#updatePowerState())
+        final float throttledBrightness = 0.123f;
+        when(mBrightnessThrottler.getBrightnessCap()).thenReturn(throttledBrightness);
+        when(mBrightnessThrottler.isThrottled()).thenReturn(true);
+        mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration */,
+                BRIGHTNESS_MAX_FLOAT /* brightness */, false /* userChangedBrightness */,
+                0 /* adjustment */, false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT);
+        assertEquals(throttledBrightness, mController.getAutomaticScreenBrightness(), 0.0f);
+
+        // Remove throttling and notify ABC again
+        when(mBrightnessThrottler.getBrightnessCap()).thenReturn(BRIGHTNESS_MAX_FLOAT);
+        when(mBrightnessThrottler.isThrottled()).thenReturn(false);
+        mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration */,
+                BRIGHTNESS_MAX_FLOAT /* brightness */, false /* userChangedBrightness */,
+                0 /* adjustment */, false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT);
+        assertEquals(BRIGHTNESS_MAX_FLOAT, mController.getAutomaticScreenBrightness(), 0.0f);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
index d441143..0028969 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
@@ -165,6 +165,17 @@
                 R.bool.config_cecTvSendStandbyOnSleepDisabled_default);
 
         doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSetMenuLanguage_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSetMenuLanguageEnabled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSetMenuLanguageEnabled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSetMenuLanguageDisabled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecSetMenuLanguageDisabled_default);
+
+        doReturn(true).when(resources).getBoolean(
                 R.bool.config_cecRcProfileTv_userConfigurable);
         doReturn(true).when(resources).getBoolean(
                 R.bool.config_cecRcProfileTvNone_allowed);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
index 85d30a6..ae7b494 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
@@ -83,6 +83,7 @@
                     HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
                     HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
                     HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+                    HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE,
                     HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
                     HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
                     HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
@@ -121,6 +122,7 @@
                     HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
                     HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
                     HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+                    HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE,
                     HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
                     HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
                     HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
@@ -159,6 +161,7 @@
                     HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
                     HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
                     HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+                    HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE,
                     HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
                     HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
                     HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 7751ef5..c48a974 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -42,6 +42,7 @@
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
 import android.hardware.hdmi.IHdmiControlStatusChangeListener;
+import android.hardware.hdmi.IHdmiVendorCommandListener;
 import android.os.Binder;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -747,6 +748,114 @@
     }
 
     @Test
+    public void addVendorCommandListener_receiveCallback_VendorCmdNoIdTest() {
+        int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress();
+        int sourceAddress = Constants.ADDR_TV;
+        byte[] params = {0x00, 0x01, 0x02, 0x03};
+        int vendorId = 0x123456;
+
+        VendorCommandListener vendorCmdListener =
+                new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
+        mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage vendorCommandNoId =
+                HdmiCecMessageBuilder.buildVendorCommand(sourceAddress, destAddress, params);
+        mNativeWrapper.onCecMessage(vendorCommandNoId);
+        mTestLooper.dispatchAll();
+        assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isTrue();
+        assertThat(vendorCmdListener.mParamsCorrect).isTrue();
+        assertThat(vendorCmdListener.mHasVendorId).isFalse();
+    }
+
+    @Test
+    public void addVendorCommandListener_receiveCallback_VendorCmdWithIdTest() {
+        int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress();
+        int sourceAddress = Constants.ADDR_TV;
+        byte[] params = {0x00, 0x01, 0x02, 0x03};
+        int vendorId = 0x123456;
+
+        VendorCommandListener vendorCmdListener =
+                new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
+        mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage vendorCommandWithId =
+                HdmiCecMessageBuilder.buildVendorCommandWithId(
+                        sourceAddress, destAddress, vendorId, params);
+        mNativeWrapper.onCecMessage(vendorCommandWithId);
+        mTestLooper.dispatchAll();
+        assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isTrue();
+        assertThat(vendorCmdListener.mParamsCorrect).isTrue();
+        assertThat(vendorCmdListener.mHasVendorId).isTrue();
+    }
+
+    @Test
+    public void addVendorCommandListener_noCallback_VendorCmdDiffIdTest() {
+        int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress();
+        int sourceAddress = Constants.ADDR_TV;
+        byte[] params = {0x00, 0x01, 0x02, 0x03};
+        int vendorId = 0x123456;
+        int diffVendorId = 0x345678;
+
+        VendorCommandListener vendorCmdListener =
+                new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
+        mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage vendorCommandWithDiffId =
+                HdmiCecMessageBuilder.buildVendorCommandWithId(
+                        sourceAddress, destAddress, diffVendorId, params);
+        mNativeWrapper.onCecMessage(vendorCommandWithDiffId);
+        mTestLooper.dispatchAll();
+        assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isFalse();
+    }
+
+    private static class VendorCommandListener extends IHdmiVendorCommandListener.Stub {
+        boolean mVendorCommandCallbackReceived = false;
+        boolean mParamsCorrect = false;
+        boolean mHasVendorId = false;
+
+        int mSourceAddress;
+        int mDestAddress;
+        byte[] mParams;
+        int mVendorId;
+
+        VendorCommandListener(int sourceAddress, int destAddress, byte[] params, int vendorId) {
+            this.mSourceAddress = sourceAddress;
+            this.mDestAddress = destAddress;
+            this.mParams = params.clone();
+            this.mVendorId = vendorId;
+        }
+
+        @Override
+        public void onReceived(
+                int sourceAddress, int destAddress, byte[] params, boolean hasVendorId) {
+            mVendorCommandCallbackReceived = true;
+            if (mSourceAddress == sourceAddress && mDestAddress == destAddress) {
+                byte[] expectedParams;
+                if (hasVendorId) {
+                    // If the command has vendor ID, we have to add it to mParams.
+                    expectedParams = new byte[params.length];
+                    expectedParams[0] = (byte) ((mVendorId >> 16) & 0xFF);
+                    expectedParams[1] = (byte) ((mVendorId >> 8) & 0xFF);
+                    expectedParams[2] = (byte) (mVendorId & 0xFF);
+                    System.arraycopy(mParams, 0, expectedParams, 3, mParams.length);
+                } else {
+                    expectedParams = params.clone();
+                }
+                if (Arrays.equals(expectedParams, params)) {
+                    mParamsCorrect = true;
+                }
+            }
+            mHasVendorId = hasVendorId;
+        }
+
+        @Override
+        public void onControlStateChanged(boolean enabled, int reason) {}
+    }
+
+    @Test
     public void dispatchMessageToLocalDevice_broadcastMessage_returnsHandled() {
         HdmiCecMessage message = HdmiCecMessageBuilder.buildStandby(
                 Constants.ADDR_TV,
diff --git a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
index e655013..27e8d69 100644
--- a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
+++ b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
@@ -16,6 +16,8 @@
 
 package com.android.server.usage;
 
+import static android.app.ActivityManager.procStateToString;
+
 import static com.android.server.usage.UsageStatsService.DEBUG_RESPONSE_STATS;
 
 import android.annotation.ElapsedRealtimeLong;
@@ -23,6 +25,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager.ProcessState;
 import android.app.usage.BroadcastResponseStats;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -78,12 +81,17 @@
     // TODO (206518114): Move all callbacks handling to a handler thread.
     void reportBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage,
             UserHandle targetUser, long idForResponseEvent,
-            @ElapsedRealtimeLong long timestampMs) {
+            @ElapsedRealtimeLong long timestampMs, @ProcessState int targetUidProcState) {
         if (DEBUG_RESPONSE_STATS) {
-            Slog.d(TAG, TextUtils.formatSimple(
-                    "reportBroadcastDispatchEvent; srcUid=%d, tgtPkg=%s, tgtUsr=%d, id=%d, ts=%s",
+            Slog.d(TAG, TextUtils.formatSimple("reportBroadcastDispatchEvent; "
+                            + "srcUid=%d, tgtPkg=%s, tgtUsr=%d, id=%d, ts=%s, state=%s",
                     sourceUid, targetPackage, targetUser, idForResponseEvent,
-                    TimeUtils.formatDuration(timestampMs)));
+                    TimeUtils.formatDuration(timestampMs), procStateToString(targetUidProcState)));
+        }
+        if (targetUidProcState <= mAppStandby.getBroadcastResponseFgThresholdState()) {
+            // No need to track the broadcast response state while the target app is
+            // in the foreground.
+            return;
         }
         synchronized (mLock) {
             final LongSparseArray<BroadcastEvent> broadcastEvents =
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 6906f20..98a41bc 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -42,6 +42,7 @@
 import android.annotation.SuppressLint;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessState;
 import android.app.AppOpsManager;
 import android.app.IUidObserver;
 import android.app.PendingIntent;
@@ -3042,9 +3043,9 @@
         @Override
         public void reportBroadcastDispatched(int sourceUid, @NonNull String targetPackage,
                 @NonNull UserHandle targetUser, long idForResponseEvent,
-                @ElapsedRealtimeLong long timestampMs) {
+                @ElapsedRealtimeLong long timestampMs, @ProcessState int targetUidProcState) {
             mResponseStatsTracker.reportBroadcastDispatchEvent(sourceUid, targetPackage,
-                    targetUser, idForResponseEvent, timestampMs);
+                    targetUser, idForResponseEvent, timestampMs, targetUidProcState);
         }
 
         @Override
diff --git a/services/wallpapereffectsgeneration/Android.bp b/services/wallpapereffectsgeneration/Android.bp
new file mode 100644
index 0000000..4dbb0fd
--- /dev/null
+++ b/services/wallpapereffectsgeneration/Android.bp
@@ -0,0 +1,22 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "services.wallpapereffectsgeneration-sources",
+    srcs: ["java/**/*.java"],
+    path: "java",
+    visibility: ["//frameworks/base/services"],
+}
+
+java_library_static {
+    name: "services.wallpapereffectsgeneration",
+    defaults: ["platform_service_defaults"],
+    srcs: [":services.wallpapereffectsgeneration-sources"],
+    libs: ["services.core"],
+}
diff --git a/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/RemoteWallpaperEffectsGenerationService.java b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/RemoteWallpaperEffectsGenerationService.java
new file mode 100644
index 0000000..c228daf
--- /dev/null
+++ b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/RemoteWallpaperEffectsGenerationService.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.wallpapereffectsgeneration;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.service.wallpapereffectsgeneration.IWallpaperEffectsGenerationService;
+import android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService;
+import android.text.format.DateUtils;
+
+import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
+
+
+/**
+ * Proxy to the
+ * {@link android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService}
+ * implementation in another process.
+ */
+public class RemoteWallpaperEffectsGenerationService extends
+        AbstractMultiplePendingRequestsRemoteService<RemoteWallpaperEffectsGenerationService,
+                IWallpaperEffectsGenerationService> {
+
+    private static final String TAG =
+            RemoteWallpaperEffectsGenerationService.class.getSimpleName();
+
+    private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
+
+    private final RemoteWallpaperEffectsGenerationServiceCallback mCallback;
+
+    public RemoteWallpaperEffectsGenerationService(Context context,
+            ComponentName componentName, int userId,
+            RemoteWallpaperEffectsGenerationServiceCallback callback,
+            boolean bindInstantServiceAllowed,
+            boolean verbose) {
+        super(context, WallpaperEffectsGenerationService.SERVICE_INTERFACE,
+                componentName, userId, callback,
+                context.getMainThreadHandler(),
+                bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0,
+                verbose, /* initialCapacity= */ 1);
+        mCallback = callback;
+    }
+
+    @Override
+    protected IWallpaperEffectsGenerationService getServiceInterface(IBinder service) {
+        return IWallpaperEffectsGenerationService.Stub.asInterface(service);
+    }
+
+    @Override
+    protected long getTimeoutIdleBindMillis() {
+        return PERMANENT_BOUND_TIMEOUT_MS;
+    }
+
+    @Override
+    protected long getRemoteRequestMillis() {
+        return TIMEOUT_REMOTE_REQUEST_MILLIS;
+    }
+
+    /**
+     * Schedules a request to bind to the remote service.
+     */
+    public void reconnect() {
+        super.scheduleBind();
+    }
+
+    /**
+     * Schedule async request on remote service.
+     */
+    public void scheduleOnResolvedService(
+            @NonNull AsyncRequest<IWallpaperEffectsGenerationService> request) {
+        scheduleAsyncRequest(request);
+    }
+
+    /**
+     * Execute async request on remote service immediately instead of sending it to Handler queue.
+     */
+    public void executeOnResolvedService(
+            @NonNull AsyncRequest<IWallpaperEffectsGenerationService> request) {
+        executeAsyncRequest(request);
+    }
+
+    /**
+     * Notifies server (WallpaperEffectsGenerationPerUserService) about unexpected events..
+     */
+    public interface RemoteWallpaperEffectsGenerationServiceCallback
+            extends VultureCallback<RemoteWallpaperEffectsGenerationService> {
+        /**
+         * Notifies change in connected state of the remote service.
+         */
+        void onConnectedStateChanged(boolean connected);
+    }
+
+    @Override // from AbstractRemoteService
+    protected void handleOnConnectedStateChanged(boolean connected) {
+        if (mCallback != null) {
+            mCallback.onConnectedStateChanged(connected);
+        }
+    }
+}
diff --git a/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationManagerService.java b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationManagerService.java
new file mode 100644
index 0000000..0d0b3e0
--- /dev/null
+++ b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationManagerService.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wallpapereffectsgeneration;
+
+import static android.Manifest.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
+import static android.content.Context.WALLPAPER_EFFECTS_GENERATION_SERVICE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
+import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
+import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
+import android.app.wallpapereffectsgeneration.ICinematicEffectListener;
+import android.app.wallpapereffectsgeneration.IWallpaperEffectsGenerationManager;
+import android.content.Context;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+import com.android.server.infra.AbstractMasterSystemService;
+import com.android.server.infra.FrameworkResourcesServiceNameResolver;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+import java.io.FileDescriptor;
+import java.util.function.Consumer;
+
+/**
+ * A service used to return wallpaper effect given a request.
+ */
+public class WallpaperEffectsGenerationManagerService extends
+        AbstractMasterSystemService<WallpaperEffectsGenerationManagerService,
+                WallpaperEffectsGenerationPerUserService> {
+    private static final String TAG =
+            WallpaperEffectsGenerationManagerService.class.getSimpleName();
+    private static final boolean DEBUG = false;
+    private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
+    private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
+
+    public WallpaperEffectsGenerationManagerService(Context context) {
+        super(context,
+                new FrameworkResourcesServiceNameResolver(context,
+                        com.android.internal.R.string.config_defaultWallpaperEffectsGenerationService),
+                null,
+                PACKAGE_UPDATE_POLICY_NO_REFRESH | PACKAGE_RESTART_POLICY_NO_REFRESH);
+        mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+    }
+
+    @Override
+    protected WallpaperEffectsGenerationPerUserService newServiceLocked(int resolvedUserId,
+            boolean disabled) {
+        return new WallpaperEffectsGenerationPerUserService(this, mLock, resolvedUserId);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(WALLPAPER_EFFECTS_GENERATION_SERVICE,
+                new WallpaperEffectsGenerationManagerStub());
+    }
+
+    @Override
+    protected void enforceCallingPermissionForManagement() {
+        getContext().enforceCallingPermission(MANAGE_WALLPAPER_EFFECTS_GENERATION, TAG);
+    }
+
+    @Override // from AbstractMasterSystemService
+    protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
+        final WallpaperEffectsGenerationPerUserService service = peekServiceForUserLocked(userId);
+        if (service != null) {
+            service.onPackageUpdatedLocked();
+        }
+    }
+
+    @Override // from AbstractMasterSystemService
+    protected void onServicePackageRestartedLocked(@UserIdInt int userId) {
+        final WallpaperEffectsGenerationPerUserService service = peekServiceForUserLocked(userId);
+        if (service != null) {
+            service.onPackageRestartedLocked();
+        }
+    }
+
+    @Override
+    protected int getMaximumTemporaryServiceDurationMs() {
+        return MAX_TEMP_SERVICE_DURATION_MS;
+    }
+
+    private class WallpaperEffectsGenerationManagerStub
+            extends IWallpaperEffectsGenerationManager.Stub {
+        @Override
+        public void generateCinematicEffect(@NonNull CinematicEffectRequest request,
+                @NonNull ICinematicEffectListener listener) {
+            if (!runForUserLocked("generateCinematicEffect", (service) ->
+                    service.onGenerateCinematicEffectLocked(request, listener))) {
+                try {
+                    listener.onCinematicEffectGenerated(
+                            new CinematicEffectResponse.Builder(
+                                    CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_ERROR,
+                                    request.getTaskId()).build());
+                } catch (RemoteException e) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "fail to invoke cinematic effect listener for task["
+                                + request.getTaskId() + "]");
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void returnCinematicEffectResponse(@NonNull CinematicEffectResponse response) {
+            runForUserLocked("returnCinematicResponse", (service) ->
+                    service.onReturnCinematicEffectResponseLocked(response));
+        }
+
+        public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+                @Nullable FileDescriptor err,
+                @NonNull String[] args, @Nullable ShellCallback callback,
+                @NonNull ResultReceiver resultReceiver) {
+            new WallpaperEffectsGenerationManagerServiceShellCommand(
+                    WallpaperEffectsGenerationManagerService.this)
+                    .exec(this, in, out, err, args, callback, resultReceiver);
+        }
+
+        /**
+         * Execute the operation for the user locked. Return true if
+         * WallpaperEffectsGenerationPerUserService is found for the user.
+         * Otherwise return false.
+         */
+        private boolean runForUserLocked(@NonNull final String func,
+                @NonNull final Consumer<WallpaperEffectsGenerationPerUserService> c) {
+            ActivityManagerInternal am = LocalServices.getService(ActivityManagerInternal.class);
+            final int userId = am.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+                    Binder.getCallingUserHandle().getIdentifier(), false, ALLOW_NON_FULL,
+                    null, null);
+            if (DEBUG) {
+                Slog.d(TAG, "runForUserLocked:" + func + " from pid=" + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+            }
+            Context ctx = getContext();
+            if (!(ctx.checkCallingPermission(MANAGE_WALLPAPER_EFFECTS_GENERATION)
+                    == PERMISSION_GRANTED
+                    || mServiceNameResolver.isTemporary(userId)
+                    || mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid()))) {
+                String msg = "Permission Denial: Cannot call " + func + " from pid="
+                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid();
+                Slog.w(TAG, msg);
+                throw new SecurityException(msg);
+            }
+            final long origId = Binder.clearCallingIdentity();
+            boolean accepted = false;
+            try {
+                synchronized (mLock) {
+                    final WallpaperEffectsGenerationPerUserService service =
+                            getServiceForUserLocked(userId);
+                    if (service != null) {
+                        accepted = true;
+                        c.accept(service);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+
+            return accepted;
+        }
+    }
+}
diff --git a/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationManagerServiceShellCommand.java b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationManagerServiceShellCommand.java
new file mode 100644
index 0000000..fc6f75f
--- /dev/null
+++ b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationManagerServiceShellCommand.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wallpapereffectsgeneration;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/**
+ * The shell command implementation for the WallpaperEffectsGenerationService.
+ */
+public class WallpaperEffectsGenerationManagerServiceShellCommand extends ShellCommand {
+
+    private static final String TAG =
+            WallpaperEffectsGenerationManagerServiceShellCommand.class.getSimpleName();
+
+    private final WallpaperEffectsGenerationManagerService mService;
+
+    public WallpaperEffectsGenerationManagerServiceShellCommand(
+            @NonNull WallpaperEffectsGenerationManagerService service) {
+        mService = service;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        final PrintWriter pw = getOutPrintWriter();
+        switch (cmd) {
+            case "set": {
+                final String what = getNextArgRequired();
+                switch (what) {
+                    case "temporary-service": {
+                        final int userId = Integer.parseInt(getNextArgRequired());
+                        String serviceName = getNextArg();
+                        if (serviceName == null) {
+                            mService.resetTemporaryService(userId);
+                            pw.println("WallpaperEffectsGenerationService temporarily reset. ");
+                            return 0;
+                        }
+                        final int duration = Integer.parseInt(getNextArgRequired());
+                        mService.setTemporaryService(userId, serviceName, duration);
+                        pw.println("WallpaperEffectsGenerationService temporarily set to "
+                                + serviceName + " for " + duration + "ms");
+                        break;
+                    }
+                }
+            }
+            break;
+            default:
+                return handleDefaultCommands(cmd);
+        }
+        return 0;
+    }
+
+    @Override
+    public void onHelp() {
+        try (PrintWriter pw = getOutPrintWriter()) {
+            pw.println("WallpaperEffectsGenerationService commands:");
+            pw.println("  help");
+            pw.println("    Prints this help text.");
+            pw.println("");
+            pw.println("  set temporary-service USER_ID [COMPONENT_NAME DURATION]");
+            pw.println("    Temporarily (for DURATION ms) changes the service implemtation.");
+            pw.println("    To reset, call with just the USER_ID argument.");
+            pw.println("");
+        }
+    }
+}
diff --git a/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java
new file mode 100644
index 0000000..d541051
--- /dev/null
+++ b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wallpapereffectsgeneration;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppGlobals;
+import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
+import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
+import android.app.wallpapereffectsgeneration.ICinematicEffectListener;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.infra.AbstractPerUserSystemService;
+
+/**
+ * Per-user instance of {@link WallpaperEffectsGenerationManagerService}.
+ */
+public class WallpaperEffectsGenerationPerUserService extends
+        AbstractPerUserSystemService<WallpaperEffectsGenerationPerUserService,
+                WallpaperEffectsGenerationManagerService> implements
+        RemoteWallpaperEffectsGenerationService.RemoteWallpaperEffectsGenerationServiceCallback {
+
+    private static final String TAG =
+            WallpaperEffectsGenerationPerUserService.class.getSimpleName();
+
+    @GuardedBy("mLock")
+    private CinematicEffectListenerWrapper mCinematicEffectListenerWrapper;
+
+    @Nullable
+    @GuardedBy("mLock")
+    private RemoteWallpaperEffectsGenerationService mRemoteService;
+
+    protected WallpaperEffectsGenerationPerUserService(
+            WallpaperEffectsGenerationManagerService master,
+            Object lock, int userId) {
+        super(master, lock, userId);
+    }
+
+    @Override // from PerUserSystemService
+    protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
+            throws NameNotFoundException {
+        ServiceInfo si;
+        try {
+            si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
+                    PackageManager.GET_META_DATA, mUserId);
+        } catch (RemoteException e) {
+            throw new NameNotFoundException("Could not get service for " + serviceComponent);
+        }
+        if (!Manifest.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE.equals(si.permission)) {
+            Slog.w(TAG, "WallpaperEffectsGenerationService from '" + si.packageName
+                    + "' does not require permission "
+                    + Manifest.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE);
+            throw new SecurityException("Service does not require permission "
+                    + Manifest.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE);
+        }
+        return si;
+    }
+
+    @GuardedBy("mLock")
+    @Override // from PerUserSystemService
+    protected boolean updateLocked(boolean disabled) {
+        final boolean enabledChanged = super.updateLocked(disabled);
+        updateRemoteServiceLocked();
+        return enabledChanged;
+    }
+
+    /**
+     * Notifies the service of a new cinematic effect generation request.
+     */
+    @GuardedBy("mLock")
+    public void onGenerateCinematicEffectLocked(
+            @NonNull CinematicEffectRequest cinematicEffectRequest,
+            @NonNull ICinematicEffectListener cinematicEffectListener) {
+        String newTaskId = cinematicEffectRequest.getTaskId();
+        // Previous request is still being processed.
+        if (mCinematicEffectListenerWrapper != null) {
+            if (mCinematicEffectListenerWrapper.mTaskId.equals(newTaskId)) {
+                invokeCinematicListenerAndCleanup(
+                        new CinematicEffectResponse.Builder(
+                                CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_PENDING, newTaskId)
+                                .build()
+                );
+            } else {
+                invokeCinematicListenerAndCleanup(
+                        new CinematicEffectResponse.Builder(
+                                CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS,
+                                newTaskId).build()
+                );
+            }
+            return;
+        }
+        RemoteWallpaperEffectsGenerationService remoteService = ensureRemoteServiceLocked();
+        if (remoteService != null) {
+            remoteService.executeOnResolvedService(
+                    s -> s.onGenerateCinematicEffect(cinematicEffectRequest));
+            mCinematicEffectListenerWrapper =
+                    new CinematicEffectListenerWrapper(newTaskId, cinematicEffectListener);
+        } else {
+            if (isDebug()) {
+                Slog.d(TAG, "Remote service not found");
+            }
+            try {
+                cinematicEffectListener.onCinematicEffectGenerated(
+                        createErrorCinematicEffectResponse(newTaskId));
+            } catch (RemoteException e) {
+                if (isDebug()) {
+                    Slog.d(TAG, "Failed to invoke cinematic effect listener for task [" + newTaskId
+                            + "]");
+                }
+            }
+        }
+    }
+
+    /**
+     * Notifies the service of a generated cinematic effect response.
+     */
+    @GuardedBy("mLock")
+    public void onReturnCinematicEffectResponseLocked(
+            @NonNull CinematicEffectResponse cinematicEffectResponse) {
+        invokeCinematicListenerAndCleanup(cinematicEffectResponse);
+    }
+
+    @GuardedBy("mLock")
+    private void updateRemoteServiceLocked() {
+        if (mRemoteService != null) {
+            mRemoteService.destroy();
+            mRemoteService = null;
+        }
+        // End existing response and clean up listener for next request.
+        if (mCinematicEffectListenerWrapper != null) {
+            invokeCinematicListenerAndCleanup(
+                    createErrorCinematicEffectResponse(mCinematicEffectListenerWrapper.mTaskId));
+        }
+
+    }
+
+    void onPackageUpdatedLocked() {
+        if (isDebug()) {
+            Slog.v(TAG, "onPackageUpdatedLocked()");
+        }
+        destroyAndRebindRemoteService();
+    }
+
+    void onPackageRestartedLocked() {
+        if (isDebug()) {
+            Slog.v(TAG, "onPackageRestartedLocked()");
+        }
+        destroyAndRebindRemoteService();
+    }
+
+    private void destroyAndRebindRemoteService() {
+        if (mRemoteService == null) {
+            return;
+        }
+
+        if (isDebug()) {
+            Slog.d(TAG, "Destroying the old remote service.");
+        }
+        mRemoteService.destroy();
+        mRemoteService = null;
+        mRemoteService = ensureRemoteServiceLocked();
+        if (mRemoteService != null) {
+            if (isDebug()) {
+                Slog.d(TAG, "Rebinding to the new remote service.");
+            }
+            mRemoteService.reconnect();
+        }
+        // Clean up listener for next request.
+        if (mCinematicEffectListenerWrapper != null) {
+            invokeCinematicListenerAndCleanup(
+                    createErrorCinematicEffectResponse(mCinematicEffectListenerWrapper.mTaskId));
+        }
+    }
+
+    private CinematicEffectResponse createErrorCinematicEffectResponse(String taskId) {
+        return new CinematicEffectResponse.Builder(
+                CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_ERROR,
+                taskId).build();
+    }
+
+    @GuardedBy("mLock")
+    private void invokeCinematicListenerAndCleanup(
+            CinematicEffectResponse cinematicEffectResponse) {
+        try {
+            if (mCinematicEffectListenerWrapper != null
+                    && mCinematicEffectListenerWrapper.mListener != null) {
+                mCinematicEffectListenerWrapper.mListener.onCinematicEffectGenerated(
+                        cinematicEffectResponse);
+            } else {
+                if (isDebug()) {
+                    Slog.w(TAG, "Cinematic effect listener not found for task["
+                            + mCinematicEffectListenerWrapper.mTaskId + "]");
+                }
+            }
+        } catch (RemoteException e) {
+            if (isDebug()) {
+                Slog.w(TAG, "Error invoking cinematic effect listener for task["
+                        + mCinematicEffectListenerWrapper.mTaskId + "]");
+            }
+        } finally {
+            mCinematicEffectListenerWrapper = null;
+        }
+    }
+
+    @GuardedBy("mLock")
+    @Nullable
+    private RemoteWallpaperEffectsGenerationService ensureRemoteServiceLocked() {
+        if (mRemoteService == null) {
+            final String serviceName = getComponentNameLocked();
+            if (serviceName == null) {
+                if (mMaster.verbose) {
+                    Slog.v(TAG, "ensureRemoteServiceLocked(): not set");
+                }
+                return null;
+            }
+            ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+
+            mRemoteService = new RemoteWallpaperEffectsGenerationService(getContext(),
+                    serviceComponent, mUserId, this,
+                    mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
+        }
+
+        return mRemoteService;
+    }
+
+    @Override // from RemoteWallpaperEffectsGenerationService
+    public void onServiceDied(RemoteWallpaperEffectsGenerationService service) {
+        Slog.w(TAG, "remote wallpaper effects generation service died");
+        updateRemoteServiceLocked();
+    }
+
+    @Override // from RemoteWallpaperEffectsGenerationService
+    public void onConnectedStateChanged(boolean connected) {
+        if (!connected) {
+            Slog.w(TAG, "remote wallpaper effects generation service disconnected");
+            updateRemoteServiceLocked();
+        }
+    }
+
+    private static final class CinematicEffectListenerWrapper {
+        @NonNull
+        private final String mTaskId;
+        @NonNull
+        private final ICinematicEffectListener mListener;
+
+        CinematicEffectListenerWrapper(
+                @NonNull final String taskId,
+                @NonNull final ICinematicEffectListener listener) {
+            mTaskId = taskId;
+            mListener = listener;
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e0e7913..3c277b7 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4540,9 +4540,7 @@
      * Passing this value as {@link #KEY_SUBSCRIPTION_GROUP_UUID_STRING} will remove the
      * subscription from a group instead of adding it to a group.
      *
-     * TODO: Expose in a future release.
-     *
-     * @hide
+     * <p>This value will work all the way back to {@link android.os.Build.VERSION_CODES#Q}.
      */
     public static final String REMOVE_GROUP_UUID_STRING = "00000000-0000-0000-0000-000000000000";
 
@@ -4555,9 +4553,7 @@
      * <p>If set to {@link #REMOVE_GROUP_UUID_STRING}, then the subscription will be removed from
      * its current group.
      *
-     * TODO: unhide this key.
-     *
-     * @hide
+     * <p>This key will work all the way back to {@link android.os.Build.VERSION_CODES#Q}.
      */
     public static final String KEY_SUBSCRIPTION_GROUP_UUID_STRING =
             "subscription_group_uuid_string";
@@ -4605,17 +4601,15 @@
             "data_switch_validation_min_gap_long";
 
     /**
-    * A boolean property indicating whether this subscription should be managed as an opportunistic
-    * subscription.
-    *
-    * If true, then this subscription will be selected based on available coverage and will not be
-    * available for a user in settings menus for selecting macro network providers. If unset,
-    * defaults to “false”.
-    *
-    * TODO: unhide this key.
-    *
-    * @hide
-    */
+     * A boolean property indicating whether this subscription should be managed as an opportunistic
+     * subscription.
+     *
+     * If true, then this subscription will be selected based on available coverage and will not be
+     * available for a user in settings menus for selecting macro network providers. If unset,
+     * defaults to “false”.
+     *
+     * <p>This key will work all the way back to {@link android.os.Build.VERSION_CODES#Q}.
+     */
     public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL =
             "is_opportunistic_subscription_bool";